开始前适用开发板:ESP32-S3 Korvo · 开发框架:ESP-IDF
适用开发板:Korvo S3 · 工程
04.advanced.face_recognition· targetesp32s3
摄像头:DVP · 推理:ESP-DL 本地,无需联网
学习时长:约 30 分钟 · 难度:★★★★☆
学习目标
完成本节后,你将能够:
- 理解边缘 AI 人脸检测/识别的完整流水线
- 掌握 ESP-DL 模型的部署与使用方式
- 了解 FreeRTOS 队列在多任务数据传递中的应用
- 区分「人脸检测」(有没有脸)和「人脸识别」(是谁的脸)
1. 这个例子在干嘛
在设备端(不联网)完成人脸检测与识别。摄像头拍到人脸后,画面上叠加检测框和识别结果。
这不是简单的拍照——而是 AI 推理:
┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐
│ DVP 摄像头│───→│ 帧队列 │───→│ AI 推理任务 │───→│ 显示队列 │
│ 取帧任务 │ │ (FreeRTOS) │ │ ESP-DL 模型 │ │ │
└──────────┘ └──────────────┘ │ 检测+识别 │ │ │
└──────────────┘ └────┬─────┘
│
▼
┌──────────┐
│ LVGL 屏幕│
│ 画面+框 │
└──────────┘
人脸检测 vs 人脸识别
| 功能 | 人脸检测 | 人脸识别 |
|---|---|---|
| 问题 | "画面里有没有人脸?在哪?" | "这是谁的脸?" |
| 输出 | 边界框坐标 (x, y, w, h) | 匹配的身份 ID |
| 是否需要注册 | 不需要 | 需要预先录入人脸特征 |
| 计算量 | 中等 | 较大(检测 + 特征提取 + 比对) |
与 P4C5 版的区别:同名工程但 不可互烧。Korvo 是 DVP + S3 CPU 推理;P4 有 AI 加速器和 MIPI CSI,性能更强。P4 版见 P4C5 face_recognition。
2. 编译烧录
cd Korvo_Firmware\04.advanced.face_recognition
idf.py set-target esp32s3
idf.py menuconfig # 选择启用的 AI 功能和模型
idf.py build flash monitor
注意:
- 首次编译会通过 Component Manager 下载 ESP-DL 模型组件,确保网络通畅
- 首次启动可能格式化 SPIFFS 以存储人脸特征库
- 编译时间较长(模型文件大)
3. menuconfig 配置
根据 menuconfig 或 app_ai_config.h,可启用的功能:
| 功能 | 说明 | 性能影响 |
|---|---|---|
| 人脸检测 | 检测框 | 基础,建议必开 |
| 人脸识别 | 匹配身份 | 增加特征提取开销 |
| 猫脸检测 | 可选 | 与人脸共享检测器 |
| 颜色追踪 | 可选 | 额外处理 |
| 运动检测 | 可选 | 帧差法 |
S3 性能提醒:S3 没有 P4 级 AI 加速器,建议一次只开 1-2 个功能,否则帧率会很低。
4. 运行现象
| 阶段 | 屏幕表现 | 串口输出 |
|---|---|---|
| 启动 | 摄像头预览 | 初始化日志、模型加载 |
| 检测到人脸 | 画面上叠加 绿色矩形框 | bbox: [x, y, w, h] + 置信度 |
| 识别成功 | 框旁显示注册的名字 | Recognized: Kevin (0.85) |
| 无人脸 | 仅预览画面 | 无检测输出 |
最佳检测条件:
- 正面面对摄像头
- 距离 30~80 cm
- 光线充足,避免逆光
- 分辨率 QVGA(320×240)
5. 软件架构详解
5.1 多任务流水线
整个系统由 三个 FreeRTOS 任务 通过队列协作:
┌─────────────────┐
│ who_camera │ 任务 1:摄像头取帧
│ DVP → 帧 → 队列 │
└────────┬────────┘
│ frame_queue (帧数据)
▼
┌─────────────────┐
│ who_human_face │ 任务 2:AI 推理
│ 检测 → 识别 │
│ 结果 → 队列 │
└────────┬────────┘
│ result_queue (帧 + 检测结果)
▼
┌─────────────────┐
│ display_task │ 任务 3:LVGL 显示
│ 画面 + 叠框 │
└─────────────────┘
为什么用队列? 三个任务速度不同——摄像头最快(取帧),AI 推理最慢。队列解耦了它们的速度差异,让系统不会因为 AI 慢而卡住取帧。
5.2 AI 推理流程
输入:RGB565 图像帧
│
├── 人脸检测模型(轻量 CNN)
│ └── 输出:0 或多个 bbox + 置信度
│
└── 对每个 bbox:
├── 裁剪人脸区域
├── 人脸特征提取(深层 CNN)
│ └── 输出:128 维特征向量
└── 与 SPIFFS 中的特征库比对
└── 余弦相似度 > 阈值 → 识别成功
6. 关键文件与代码解析
| 文件 | 作用 | 重点关注 |
|---|---|---|
main/app_main.cpp | 流水线注册 + 启动 | register_selected_ai() |
main/who_human_face_detection.cpp | 人脸检测 | 检测模型调用 |
main/who_human_face_recognition.cpp | 人脸识别 | 特征提取 + 比对 |
main/who_camera.c | DVP 摄像头取帧 | camera_task |
main/camera_lvgl_view.c | LVGL 叠框显示 | 矩形绘制 + 文字 |
register_selected_ai() 做了什么
register_selected_ai()
├── 创建 frame_queue / result_queue
├── 启动 who_camera 任务(取帧 → frame_queue)
├── 启动 who_human_face 任务(frame_queue → AI → result_queue)
└── 启动 display_task(result_queue → LVGL)
7. 人脸录入(识别模式)
如果启用了人脸识别(不仅是检测),需要 预先录入 人脸:
- 通过代码或串口命令触发「录入模式」
- 对着摄像头,系统自动截取人脸
- 提取特征向量存入 SPIFFS
- 下次识别时与存储的特征比对
特征库持久化:存在 SPIFFS 中,断电不丢失。首次启动如果 SPIFFS 未格式化会自动执行一次。
8. 常见问题与排查
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无检测框 | menuconfig 未启用检测 | 确认 AI 功能已开启 |
| 无检测框 | Camera 不工作 | 先用 board_test Camera 页验证 |
| 帧率很低 (<5fps) | 开了太多 AI 功能 | 只保留人脸检测,关闭其他 |
| 帧率很低 | 分辨率过高 | 降为 QVGA 或更低 |
| 编译报缺模型 | 组件下载失败 | idf.py reconfigure,重试网络 |
| 编译报缺模型 | 代理/防火墙 | 配置 IDF_COMPONENT_REGISTRY_URL |
| 识别不准 | 光线变化大 | 在类似的光照条件下录入和识别 |
| 识别不准 | 录入时角度单一 | 多角度录入(正面 + 侧面) |
9. 动手改造建议
- 门禁系统:识别成功 → GPIO 驱动继电器开门锁
- 考勤打卡:识别成功 → NVS 记录时间 + MQTT 上报
- 陌生人警报:检测到人脸但未匹配 → 蜂鸣器报警
- 与 Web 联动:参考 camera_webserver,将识别结果推送到浏览器
10. 知识延伸
- ESP-DL:乐鑫官方的深度学习推理库,支持量化模型,针对 ESP32-S3 的向量指令优化
- 量化:将浮点模型转为 8 位整数运算,大幅减少计算量和内存占用,精度损失可控
- S3 的 AI 能力:ESP32-S3 有 向量扩展指令(类似 SIMD),虽然不是专用 AI 加速器,但比普通 MCU 快几倍
- 边缘 AI 的意义:数据不出设备 → 隐私安全;不需要网络 → 离线可用;低延迟 → 实时响应
11. 下一步
| 方向 | 推荐例程 | 说明 |
|---|---|---|
| 二维码检测 | qrcode_detection | 另一种视觉应用 |
| 摄像头预览 | camera_lvgl_display | 不带 AI 的预览 |
| 颜色追踪 | 04.advanced.color_tracking_lvgl | 非 AI 的视觉算法 |
酷世DIY · Kevincoooool