简介面向单片机与嵌入式视觉学习者的基于STM32人脸识别资料包是一套可直接运行的Keil5工程实例展示了STM32Cortex-M4配合OV5640摄像头模块从图像采集、预处理到人脸检测与识别的完整软硬件设计流程适用于电子设计竞赛、智能家居安防项目以及嵌入式图像处理入门与进阶。资源共174个文件以72个C源文件和72个头文件为主另有Keil工程配置、hex固件、Lib库、图片与文本说明压缩包约1.03MB目录结构按功能模块划分便于快速定位与逐段阅读源码。已有8607人学习。工程代码覆盖图像灰度化、直方图均衡化、Haar特征级联人脸检测、PCA-LBP特征提取等常见算法并针对Cortex-M4的浮点单元做了轻量级裁剪兼顾识别速度和功耗。配套的批处理脚本和工程配置支持在Keil5中直接编译烧录同时也适合作为摄像头驱动、算法移植和性能调优的参考框架能帮助开发者少走弯路快速搭建自己的STM32人脸识别原型。1. 需求切入当毕设题目只给你“STM32做人脸识别”这句话时人手一份树莓派做人脸识别的时代突然要求你换成单片机第一反应往往是“这也能跑”但基于STM32的人脸识别恰恰是很多毕业设计和嵌入式课设里最容易踩坑的题它就是要把你熟悉的 OpenCV 思路全部压缩进一颗只有几百 KB 内存、主频一两百兆的芯片里。没有 Linux没有 Python没有现成库你能依赖的只有摄像头接口、DMA、中断和你自己写的图像处理函数。这个方案适合两类人一类是正在做基于STM32的人脸识别毕设或课设的学生需要从选型到验收形成完整闭环另一类是想做低成本离线门禁、考勤机、智能储物柜原型的开发者需要在保证稳定性的前提下把成本压到百元以内。你不一定真要跑到实时视频流那种“秒开”效果但你必须能站在评委面前讲清楚每一块内存、每一次循环为什么这么写。下面这套方案就是按这个目标拆的先选型再定总体架构然后逐个模块实现最后给出调试避坑和验收话术。2. 总体方案设计三层结构、两种内存策略与五类硬件接口2.1 系统拓扑从摄像头到控制输出的完整数据流整个系统的数据流可以拆成三层感知层、处理层、交互层。感知层负责拿到图像处理层负责把人脸找出来并完成比对交互层负责把结果告诉用户。这里最常犯的错是一上来就写“人脸识别算法”其实先画数据流才是正经事。我一般会把流程固定成摄像头通过 DCMI 接口把图像帧交给 DMADMA 在内存里形成一个 RGB565 缓冲区下一级把 RGB565 转成灰度图同时做降采样然后在灰度图上跑人脸检测如果检测到人脸再截取人脸区域做特征提取最后特征与 Flash 或 SD 卡中的特征库比对输出串口日志和 LCD 提示。这套流程里最核心的约束不是算法精度而是内存。摄像头按 320×240 分辨率、RGB565 格式算一帧裸图像要 320×240×2 153.6 KB。如果你选的是 STM32F407片上 RAM 一共 192 KB单帧图像就占掉 80%还要留出堆栈、特征库、LCD 缓冲根本不够用。所以设计第一步就是决定图像进内存之后到底是继续以 RGB565 保留还是立刻转灰度释放原图。我推荐的做法是DMA 直接把 RGB565 写入一块缓冲区CPU 在后半夜无事的空闲期从缓冲区读像素转成灰度并缩小到 160×120然后立刻把原缓冲区标记为可用。这样灰度图只占 160×120×1 19.2 KB原图缓冲 153.6 KB 也未必占满因为摄像头可以输出更小的分辨率。两种内存策略就此决定一种是保持原始图质量适合做精细识别但内存紧张另一种是“直接降级提取灰度”牺牲一部分色彩信息换空间非常适合单片机场景。2.2 硬件选型STM32F407 与 OV2640 为什么是默认组合芯片的选型逻辑不是越贵越好而是只看你有没有摄像头接口和足够 RAM。这里我建议用 STM32F407VET6 作为主控它带 DCMI 数字摄像头接口、硬件 FIFO 和 DMA 支持可以直接对接摄像头并行数据流CPU 主频 168 MHz带有单精度 FPU虽然特征比对基本用整数运算但图像预处理过程中偶尔用浮点做阈值校正也不会卡到不能看RAM 192 KBFlash 512 KB足以存一条 LBP 特征表和简单的人脸检测模板。摄像头我倾向于选 OV2640 而不是 OV7670。虽然 OV7670 更便宜但 OV2640 在 SCCB 寄存器配置上更灵活支持 RGB565 输出、JPEG 输出而且能够很轻松地把分辨率配到 160×120 或者 320×240。JPEG 格式虽然压缩率高但 MCU 端解码 JPEG 的开销非常大所以这里不用 JPEG直接配 RGB565。另外还需要一块 32MB 左右的 SPI Flash 或 SD 卡保存人脸特征库毕竟后期要存几个人甚至几十个人的模板全部放片上 Flash 会有点局促。LCD 选用 1.8 寸或 2.4 寸 SPI 屏用于显示“有人脸/无人脸”和识别结果。加上一个蜂鸣器、两个按键一个 UART 转串口模块这套硬件就齐了。五类硬件接口要提前规划好DCMI 接口给摄像头速率大约在 24-48 MHzI2C或者复用引脚配 SCCB用来控制 OV2640 的寄存器SPI 接口同时挂 Flash 和 LCDFlash 与 LCD 分片选即可UART 做调试日志和上位机透传GPIO 输入接按键GPIO 输出接蜂鸣器。需要注意的是OV2640 的像素时钟最好用 MCO 或外部晶振提供不要用内部 RC 振荡器否则容易产生捕获错位。2.3 内存与算力规划图像缓存、特征库与识别效率的权衡内存规划不能靠猜我习惯直接列一张静态分配表。以 320×240 RGB565 原图、160×120 灰度图为例原图缓冲区双缓冲各 160×240 分辨率RGB5652 × 160×240×2 153.6 KB但 OV2640 可以配置只输出 320×240 的一半所以实际常把分辨率降到 160×120这样一帧 RGB565 只有 38.4 KB双缓冲也就 76.8 KB灰度图像 160×120 19.2 KB人脸检测辅助标记图 160×120 19.2 KB特征向量数组LBP 直方图按 59 个 bin 算每个 bin 用 uint32 存储一个人脸的直方图约 236 字节LCD 显示缓冲只保留一行的行缓冲而不是整帧否则又要多出几十 KB。算力规划上最耗时的是 RGB565 转灰度与缩放。按 160×120 分辨率总共 19200 个像素做一次灰度转换加 3×3 中值滤波在 168MHz 上大概消耗 3-5 ms这个开销是可以接受的。人脸检测就另说了如果用滑动窗口法每个窗口都要做肤色检测和形状校验消耗会成倍增长所以后面会专门讲如何用肤色模型把检测区域缩小。比对阶段如果用 LBPH每张特征数据库比对耗时大约在几十微秒量级完全可以做到实时。总体帧率如果控制在 5-10 帧每秒系统有足够余量去处理按键和串口通信。3. 关键模块实现图像采集、人脸检测与特征比对怎么做3.1 摄像头驱动DCMI 加 DMA 实现一帧图像的完整接收摄像头驱动的核心角色是 DMA。如果只用中断逐像素读 DCMI 的 FIFO很容易出现 FIFO 溢出丢帧。正确做法是配置 DCMI 为连续模式开启帧同步中断再让 DMA 把一整帧数据搬到内存缓冲区。初始化步骤可以这样void dcmi_init_rgb565(uint32_t buf_addr) { // 使能 DCMI 与 GPIOD、GPIOE、GPIOG 时钟 __HAL_RCC_DCMI_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_DMA2_CLK_ENABLE(); // DCMI 数据引脚接在 PD0-PD11 等相应的 GPIO 上 GPIO_InitTypeDef gpio {0}; gpio.Pin GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_6 | GPIO_PIN_7; gpio.Mode GPIO_MODE_AF_PP; gpio.Pull GPIO_NOPULL; gpio.Speed GPIO_SPEED_FREQ_VERY_HIGH; gpio.Alternate GPIO_AF13_DCMI; HAL_GPIO_Init(GPIOD, gpio); // DCMI 配置下降沿捕捉同步有效捕获 RGB565 DCMI_HandleTypeDef hdcmi {0}; hdcmi.Instance DCMI; hdcmi.Init.SynchroMode DCMI_SYNC_UNEMBEDDED; hdcmi.Init.PCKPolarity DCMI_PCKPOLARITY_FALLING; hdcmi.Init.VSPolarity DCMI_VSPOLARITY_HIGH; hdcmi.Init.HSPolarity DCMI_HSPOLARITY_HIGH; hdcmi.Init.CaptureMode DCMI_MODE_CONTINUOUS; hdcmi.Init.ExtendedDataMode DCMI_EXTEND_DATA_8B; hdcmi.Init.HSyncPol DCMI_HSYNC_HIGH; HAL_DCMI_Init(hdcmi); // DMA2 配置为内存到内存搬运外设地址固定为 DCMI_DR DMA_HandleTypeDef hdma {0}; hdma.Instance DMA2_Stream1; hdma.Init.Channel DMA_CHANNEL_1; hdma.Init.Direction DMA_PERIPH_TO_MEMORY; hdma.Init.PeriphInc DMA_PINC_DISABLE; hdma.Init.MemInc DMA_MINC_ENABLE; hdma.Init.PeriphDataAlignment DMA_PDATAALIGN_WORD; hdma.Init.MemDataAlignment DMA_MDATAALIGN_WORD; hdma.Init.Mode DMA_CIRCULAR; HAL_DMA_Init(hdma); __HAL_LINKDMA(hdcmi, DMA_Handle, hdma); HAL_DCMI_Start_DMA(hdcmi, (uint32_t)buf_addr, 160 * 120 * 2); }这段代码的关键点有两个第一DCMI 的数据线是并行的 8 位或 12 位配成 ExtendedDataMode 为 8 位后收到的 8 位数据要拼成 RGB565所以我的缓冲区按 uint16 数组来访问第二DMA 配成 CIRCULAR 循环模式后图像数据会持续往缓冲区里写如果一帧写完后不处理下一帧就可能覆盖因此需要在帧中断里用标志位通知主循环。帧同步中断处理时最稳的做法是开启“Snapshot Mode”一次只采一帧处理完再启动下一次。否则你读到一半DMA 又写入新帧你会看到画面有一半是新数据一半是旧数据这正是很多单片机摄像头方案“图像撕裂”的根源。3.2 图像预处理RGB565 转灰度与大津阈值分割RGB565 里每个像素 16 位高 5 位红、中 6 位绿、低 5 位蓝。转灰度常用加权平均公式但单片机里为了避免浮点运算我直接按整数权重算void rgb565_to_gray(const uint16_t *src, uint8_t *dst, int w, int h) { int total w * h; for (int i 0; i total; i) { uint16_t px src[i]; int r (px 11) 0x1F; int g (px 5) 0x3F; int b px 0x1F; // 整数近似 299R 587G 114B 然后右移10位 int gray (r * 299 g * 587 b * 114) 10; dst[i] (uint8_t)gray; } }加权系数 299、587、114 是标准灰度公式乘 1000 后的整数化。你可能会问为什么不直接用平均值因为人眼对绿色更敏感接近 BT.601 的系数更合理。灰度图出来后人脸检测阶段经常还要做一次二值化我推荐大津法而不是固定阈值因为室内光线变化时固定阈值很容易翻车。大津法实现不算复杂统计 0-255 各灰度级像素数然后按每个可能阈值把像素分成前景背景找出类间方差最大的那个阈值。在 160×120 分辨率下统计直方图本身很快整个大津法也就 1-2 ms完全值得。注意输入图像如果直接用 OV2640 的 RGB565 缓冲转灰度最好先用中值滤波滤掉随机噪声否则肤色检测的边界会非常碎后续连通域也不好做。3.3 人脸检测肤色模型加形状校验的轻量方案在人脸识别初段不需要马上就找眼睛鼻子而是先在图像里圈出“可能是人脸的矩形区域”。对单片机来说最实用的做法是 YCrCb 肤色分割。RGB 与 YCrCb 的转换公式可以离线算也可以用近似整数void rgb565_to_ycbcr(const uint16_t *src, uint8_t *cb, uint8_t *cr, int w, int h) { for (int i 0; i w * h; i) { uint16_t px src[i]; int r (px 11) 0x1F; int g (px 5) 0x3F; int b px 0x1F; // 20 位定点扩展略分支但快 int y ( 66 * r 129 * g 25 * b 4096) 10; int cbf (-38 * r - 74 * g 112 * b 32768) 10; int crf (112 * r - 94 * g - 18 * b 32768) 10; cb[i] (uint8_t)(cbf 128); cr[i] (uint8_t)(crf 128); } }得到每个像素的 Cr、Cb 后设置肤色的阈值范围通常在 YCrCb 空间Cr 在 135 到 180 之间Cb 在 85 到 135 之间但我调试时发现不同型号摄像头的色偏比较大所以会在程序启动时加一个“色偏校准模式”通过按键手动标定一组 Cr/Cb 偏移。这个细节在答辩时很加分因为很多人只是写死阈值。肤色二值图生成后用一个简单的“投影法”对二值图分别做水平投影和垂直投影找出连续肤色像素行列的起止范围形成候选矩形。然后用三个先验条件过滤掉误检候选矩形宽高比在 0.7 到 1.5 之间候选区域内肤色像素比例大于 0.35候选矩形面积大于整幅图像面积的 5%。这几个条件可以把墙面、肤色手掌等干扰去掉一大部分。如果你追求更稳定还可以在候选区域内找眼睛暗区但那样会增加计算量我的建议是先不加留给后续迭代。3.4 特征提取与比对LBPH 在单片机上的裁剪人脸检测框出来后要把人脸区域归一化到固定尺寸比如 64×64然后提取 LBP 纹理特征。原始 LBP 是 3×3 邻域内中心像素与周围 8 个像素比较大于中心则编码为 1否则为 0。直方图有 256 个 bin但在 MCU 上太占空间更常用的是等价模式 Uniform LBP它把 256 类压缩成 59 类这样每个特征直方图只有 59 个值。比对时计算直方图相似度推荐用直方图相交距离它对光照变化容忍度好而且计算简单uint32_t lbph_dist(const uint32_t *hist1, const uint32_t *hist2, int bins) { uint32_t sum 0; for (int i 0; i bins; i) { sum (hist1[i] hist2[i]) ? hist1[i] : hist2[i]; } return sum; }这个函数返回两个直方图共有的像素数量值越大代表越相似。注册阶段对新用户连续采集 5 张不同角度的人脸抽出 LBP 直方图再取平均值存进特征库。识别阶段将当前直方图与特征库里每张模板的直方图求相交距离取最大值如果超过一个阈值比如“占比大于 0.68”则认为是同一个用户否则判为陌生人。阈值的选择是永远的玄学我会把启动次数里的误识率统计出来再动态调整。考虑到 64×64 图像分块成 4×4 子块每个子块单独提取 LBP 直方图最后特征长度是 4×4×59 个 uint32约 3.7 KB 一个模板能存进外部 Flash。整体比对一次连除法都不用速度非常快。这里需要特别提醒不要在单片机里直接用 EigenFace 那样的 PCA 亮源码矩阵运算和协方差计算会把 MCU 耗死。LBPH 是性价比最高的选择它不需要训练只需要统计直方图很适合“嵌入式离线人脸识别”的定位。3.5 用户交互与结果输出LCD、蜂鸣器与串口日志识别结果不只在 LCD 上显示“张某某”或“陌生人”还要支持注册、删除、清空特征库等操作。我的交互逻辑是这样的按键 1 短按进入注册模式LCD 提示“请输入用户ID”再按一次开始采集并自动存特征按键 2 长按进入删除模式。识别成功后蜂鸣器短鸣一声陌生人则连续鸣两声。所有调试信息通过 UART 输出比如当前帧率、内存剩余、人脸检测定位坐标、比对分数这些信息在调参时非常关键。虽然交互逻辑简单但也要注意别把按键扫描放在图像处理的 critical path 里。我用一个 10ms 定时器做按键去抖扫描把按键事件放到队列中主循环每帧结束时才消费事件。否则按键扫描一旦受到图像处理阻塞去抖效果会严重劣化。4. 系统集成与性能优化帧率、内存占用与识别准确率的拉锯4.1 从裸机到精简调度用状态机代替操作系统很多人在单片机人脸识别项目上会想移植 FreeRTOS但我更建议先从状态机开始。人脸识别流程是天然的状态链初始化 → 待机 → 采集 → 检测 → 识别 → 结果。如果写成多线程图像缓冲区的互斥访问会让你调试起来非常难受线程切换还会消耗宝贵的时序余量。状态机不仅省掉 OS 开销还能让帧率更可控。typedef enum { SYS_INIT, SYS_IDLE, SYS_CAPTURE, SYS_DETECT, SYS_RECOGNIZE, SYS_RESULT } sys_state_t; void main_loop(void) { while (1) { switch (state) { case SYS_IDLE: if (frame_ready_flag) { state SYS_CAPTURE; } break; case SYS_CAPTURE: memcpy(current_frame, frame_buf, GRAY_SIZE); frame_ready_flag 0; state SYS_DETECT; break; case SYS_DETECT: face_rect face_detect(current_frame); if (face_rect.width 0) { state SYS_RECOGNIZE; } else { state SYS_RESULT; } break; case SYS_RECOGNIZE: match_result lbph_match(face_rect); state SYS_RESULT; break; case SYS_RESULT: display_result(match_result); state SYS_IDLE; break; } } }这个状态机的关键在于每个状态要么很短要么必须能被打断。比如 SYS_DETECT 如果耗时太长摄像头下一帧就已经来了所以检测函数内部要支持“提前退出”当扫描区域已经覆盖超过 80% 且仍没有人脸时就返回空结果避免卡死。4.2 内存复用双缓冲与区域裁剪内存复用策略能直接决定你能否把 192KB RAM 用转。我最常用的三个招数是第一只保留当前帧灰度图RGB565 原图在转完灰度后立刻释放第二把肤色二值图直接存放在灰度图的另半区也就是用上下半区隔离不必再额外申请一块同样大小的标记图第三检测到人脸框后在把该区域缩放至 64×64 时先裁剪到人脸矩形而不是全图缩放这样内存访问更集中而且 LBP 特征更准确。双缓冲方面,摄像头 DMA 的缓冲区我建议只开一块靠帧同步事件来保证不在传输中读取数据。很多参考代码用双缓冲是为了避免显示撕裂但在识别场景里你只关心最近一帧撕裂反而没那么重要。用一个信号量表示“当前帧有效”处理完一帧后再允许下一次 DMA 写入这个单缓冲方案比双缓冲省 38KB 内存还是相当划算的。需要注意的是DMA 循环模式下一旦开启就停不下来要在帧中断里关闭 DCMI 才能让处理过程无干扰。处理完再重新开启下一次捕获。4.3 性能调优阈值、分辨率与运行模式的组合性能调优的实质就是找到“检测灵敏度”和“响应时间”之间的平衡点。分辨率从 320×240 降到 160×120预处理时间近乎线性下降但人脸检测框也会变小。实测下来 160×120 已经足够识别 1 米外正对着摄像头的用户再低到 96×96 就很容易漏检。如果后期要识别多人脸那么分辨率降到 320×240 才是必要的但帧率会掉到 3 帧以下需要引入硬件缩放和更弱的滤波。我通常会提供两套运行模式快速模式160×120跳过中值滤波只做灰度转换和大津法适合环境光稳定时用和标准模式160×120开启中值滤波肤色阈值更保守适合灯光有波动时用。模式由按键切换内部只是过滤了几个使能布尔值。答辩时你可以说“设计并实现了自适应分辨率切换机制”这就比单纯写死一套参数听起来更有工程思想。准确率调优常犯的错误是死磕算法参数而不去看中间结果。我调试时会定期把二值图通过串口打成字符画比如用 AO 表示肤色像素在终端里直接看到人脸区域定位得准不准。这个方法比看识别分数直观得多能快速暴露是阈值问题还是形态学滤波问题。5. 调试避坑与常见问题排查五个最容易翻车的地方5.1 摄像头图像花屏或有色条现象LCD 显示的画面是横向条纹或者颜色完全不对偶尔会出现半边画面。原因除了接线接触不良最常见的是 DCMI 数据引脚时序不对。OV2640 的像素时钟 PCLK 和行场同步信号 HREF/VSYNC 必须严格对应DCMI 的捕捉极性配置不对就会把同步头采进有效数据里。其次是 SCCB 配置寄存器失败导致分辨率不是我们预期的 160×120DMA 接收的字节数不对图像自然花屏。解决先不要看 LCD直接用串口把每一行图像的前 20 个像素的 RGB565 值打出来人为判断是像素值错乱还是行列错乱。如果是整幅图错位用示波器量 PCLK 频率确认 PCLK 在 24 MHz 以下同时把 DCMI 的同步极性改成相反电平测试。寄存器初始化务必在输出图像前回读厂商 ID确认 SCCB 通信正常再开始采集。5.2 内存溢出导致程序跑飞现象程序运行一段时间后突然卡死或者图像处理后段出现随机乱码有时候不出现有时候复现。原因摄像头 DMA 缓冲区越界或者 LCD 驱动缓存分配不合理又或者在堆上 malloc 大数组导致碎片化。很多人移植串口打印时会在中断里 malloc这在裸机环境特别危险。解决整个工程禁用 malloc全部用静态数组。复用同一个全局缓冲区例如把灰度图和二值图放在同一个数组的前后段。DMA 缓冲区大小必须是 4 字节对齐并且要对 160×120×2 这个大小严格把关。调试时开启 STM32 的 HardFault 中断在中断里把故障寄存器打印出来通常能发现问题地址是不是落在参考内存范围外。5.3 人脸检测误检率过高现象门板、衣服上的图案、甚至墙上的影子都被识别为人脸但同时人脸在远处又识别不到。原因肤色阈值范围太宽宽高比过滤器只做了粗略过滤没有对候选区域内部做更严格的验证。例如门板上某个局部区域恰好呈肤色偏红宽高比也对得上就混过去了。解决把肤色阈值做两轮校验。第一轮按 Cr、Cb 范围分割第二轮在候选区域内分别计算水平和垂直投影同时要求子区域面积占比、长宽比、甚至眼睛暗区比例都满足条件。另外增强中值滤波可以大幅减少噪点让肤色区域更连续。实践中我的经验是宁可漏检几次也不要让误检把人脸库里注册的照片覆盖掉。5.4 SD 卡初始化偶尔失败现象在板上直接烧录后第一次初始化一定能读到 SD 卡第二次重新上电后却偶发初始化超时。原因SD 卡上电复位时序不稳定而代码里往往只做了一次初始化没有做复位重试。另外 SPI 模式的下拉电阻、卡座供电电压跌落也会造成这种偶发失败。解决SD 卡初始化函数做成可重入的遇到错误至少重试 3 次每次间隔 20ms。还要在初始化前拉低 CS、发送至少 80 个时钟脉冲让卡完成上电复位。如果系统里同时挂了 Flash 和 SD 卡注意分片选之间的电平状态避免片选浮空导致 SPI 总线被篡改。5.5 识别结果不稳定同一人脸时好时坏现象上午能识别下午不能识别换个角度后完全匹配不上戴眼镜后分数明显下降。原因这多半不是算法问题而是拍照时人脸对齐框不一致。人脸框如果发生偏移LBP 特征会从边界变化直方图直接受影响。另外注册阶段采集的人脸是正脸识别时如果侧脸超过 30 度特征自然差异很大。解决在注册阶段多做一次“头部姿态校验”只保留双眼位置水平且面积基本一致的样本并采集多角度做平均。比对时可以把特征库中每个人的多个样本都纳入计算取最高分。至于光照可以加一个简单的直方图均衡化预处理虽然多花几毫秒但对稳定性的提升非常明显。6. 验收与答辩从“能跑”到“能讲清楚方案”的五个检查点验收不是看程序能不能跑而是看你在所有边界条件下能不能给出可解释的结果。我的验收清单是第一光照变化室内灯关闭、半开、全开三种场景都要能检测到人脸第二姿态变化正脸、左右 15 度、戴不戴眼镜识别成功率应分别达到可接受的水平第三误识测试对不在特征库中的陌生面孔系统不能错误匹配到某个库内用户第四距离测试摄像头与用户之间 30cm、60cm、100cm至少中间两个距离能稳定识别第五连续运行上电连续跑 2 小时不跑飞、不出内存碎片。答辩时一定要讲清楚为什么不用树莓派。你可以说树莓派成本高、功耗高、不便于做成嵌入式产品STM32 方案成本在几十元冷启动时间快适合离线门禁。而“内存不够”这个问题就顺势引出你做的分辨率和算法裁剪策略。当评委问“如果人脸很多怎么办”你要回答特征库按 ID 存储查询复杂度是 O(N)但在 64 个用户以内都能在一秒内完成比对超过这个规模应该考虑云端。这比你背一堆原理要好得多。演示预案上我每次都会先录一段“识别成功”再现场演示“陌生人拒绝”。这样即便现场光线把识别成功率拉低了你也保留了证据。更重要的是在答辩前把自己的板子拿到窗边、日光灯下、昏暗角落各测一遍把测试数据记录成表格这比口头解释“效果还可以”有说服力得多。从那以后我每次做嵌入式视觉方案都会强制要求自己走一遍这个验收清单尤其是关灯测试这一关过了现场翻车的概率就低了很多。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?