第 8 章:人脸识别
本章目标:注册人脸特征,让 NanoCam 认出“你是谁”,搭建完整门禁方案。
原理
人脸识别 = 人脸检测(MSR01+MNP01 双阶段流水线)+ 特征提取(FaceRecognition112V1S8 MFN 神经网络)+ 余弦相似度比对。
摄像头 RGB565 帧
→ MSR01 粗检测(320×240, 0.3F 阈值)
→ MNP01 精检测(基于粗检候选框, 0.4F 阈值)
→ 10 个面部关键点提取(双眼/鼻尖/嘴角)
→ 关键点对齐 → 裁剪 112×112 人脸
→ MFN 卷积网络 → 512 维特征向量
→ L2 归一化
→ 与 Flash 中所有已注册 ID 的向量逐一计算余弦距离
→ 最大余弦相似度 > 阈值(0.55) → 匹配成功 → 输出 ID
→ 所有相似度 < 阈值 → 陌生人 → 输出 "who?"性能优化
MFN 特征提取和全库比对运算量较大,每帧都跑会导致画面卡顿。当前实现采用跳帧策略:人脸检测每帧运行(廉价),MFN 识别每 10 帧运行一次(昂贵),标签使用上一次识别结果持续叠加显示。这样画面保持流畅,ID 标签不闪烁。
人脸特征存储
已注册的人脸特征(id + 512维 embedding)持久化存储在 Flash 的 fr 分区(96 KB,最多 47 个人脸 ID)。掉电不丢失。
硬件准备
NanoCam 核心板 + 底板
USB-C 数据线(接电脑供电+串口)
串口助手(波特率 115200)
步骤
8.1 进入人脸识别模式
ai_mode:4设备自动重启进入 FaceID 模式,WS2812 RGB LED (GPIO18 DIN, VDD50 供电) 显示紫色。重启后串口应看到:
I (5526) MFN: fr partition size: 98304 bytes, maxminum 47 IDs can be stored
I (5526) MFN: No face ID in flashNo face ID in flash 表示还没有注册过任何人脸,正常。
8.2 注册人脸
让人脸正对摄像头(距离 30-50cm,光照均匀),确保画面中只有一张人脸。在串口发送:
face_eril设备检测到人脸后自动提取特征并注册到 Flash:
I (xxxx) ENROLL: ID 1 is enrolled画面叠加蓝色文字 Enroll: ID 1,持续约 0.5 秒后消失。
注意:命令是
face_eril(enroll 缩写),不是face_enroll。如果看到fail: unknown command,检查拼写。
8.3 辨认识别人脸
注册完成后,发送识别命令:
face_rz系统进入持续识别模式。当前人脸与 Flash 中所有已注册 ID 比对:
匹配成功:串口输出
Similarity: 0.85, Match ID: 1,画面持续叠加绿色ID: 1陌生人:串口输出
Similarity: 0.32, Match ID: 0,画面持续叠加红色who?
标签持续显示不会消失。要退出识别模式,发送
face_detect返回纯检测模式。
8.4 删除人脸
face_del删除最后注册的人脸 ID,串口返回 N IDs left,画面短暂显示剩余 ID 数量。Flash 中的特征同步删除。
8.5 退出识别模式
face_detect返回纯人脸检测模式(只画框+关键点,不识别),ID 标签清除。
关于 DETECT 模式: 在 ESP32-S3 上,纯人脸检测模式的串口坐标打印被禁用(
#if !CONFIG_IDF_TARGET_ESP32S3),这是为了避免串口被检测日志刷屏。进入识别模式(face_rz)后才会输出detection_result坐标日志。
完整命令速查
| 命令 | 功能 | 标签行为 | 是否持续 |
|---|---|---|---|
face_eril | 注册当前检测到的人脸 | 蓝色 "Enroll: ID N" | 闪现 0.5s |
face_rz | 进入持续识别模式 | 绿色 "ID: N" / 红色 "who?" | ✅ 持续 |
face_del | 删除最后注册的 ID | 红色 "N IDs left" | 闪现 0.5s |
face_detect | 退出识别,返回纯检测 | 清除所有标签 | — |
完整指令见串口协议手册。
操作流程示例
ai_mode:4 # 进入人脸识别模式
[设备重启,LED 紫色]
face_eril # 注册第一个人脸(张三)
→ ID 1 is enrolled
face_eril # 注册第二个人脸(李四)
→ ID 2 is enrolled
face_rz # 开始持续识别
→ 张三站摄像头前: 画面持续显示 "ID: 1"
→ 李四站摄像头前: 画面持续显示 "ID: 2"
→ 陌生人站摄像头前: 画面持续显示 "who?"
face_detect # 退出识别模式
→ 标签消失,只画检测框
face_del # 删除李四 (ID 2)
→ 1 IDs left
face_rz # 再次识别
→ 张三站摄像头前: "ID: 1"
→ 李四站摄像头前: "who?" (已被删除)人脸识别模式内存占用较大(MFN 模型 + 人脸检测双模型),Type-C 串口(UART0)正常工作。如遇串口无响应,先检查波特率是否为 115200。
代码
核心识别逻辑
components/modules/ai/who_human_face_recognition.cpp — 跳帧识别策略:
case RECOGNIZE:
{
// 跳帧:每 10 次检测执行 1 次 MFN 识别
static int recog_skip = 0;
if (recog_skip <= 0) {
recognize_result = recognizer->recognize(
(uint16_t *)frame->buf,
{(int)frame->height, (int)frame->width, 3},
detect_results.front().keypoint);
recog_skip = 10;
}
recog_skip--;
frame_show_state = SHOW_STATE_RECOGNIZE;
break;
}故障排除
| 症状 | 可能原因 | 解决 |
|---|---|---|
No face ID in flash | 正常,还没注册过 | 发送 face_eril 注册 |
识别结果始终 who? | 光照不足/角度偏/相似度低于阈值 | 重新注册,正对摄像头,光度均匀 |
| 注册时没反应 | 画面中人脸 ≠ 1 张 | 确保只有一张脸,距离 30-50cm |
| 识别时画面卡顿 | 正常,MFN 推理需要时间 | 已通过跳帧优化,每 10 帧跑一次 |
| 标签闪烁 | — | 已修复,标签持续显示不消失 |
fail: unknown command | 命令拼写错误 | 检查命令:face_eril 不是 face_enroll |
效果
注册人脸→持续识别显示 ID→I2C/串口输出结果→控制继电器/舵机,完整门禁方案。
下一章:第 9 章:语音对话

