01
这个项目做了什么?

本系统将实时摄像头画面转化为实时隐私保护盾:检测人脸并在设备端对人脸进行马赛克处理,同时在屏幕上显示人员计数。
核心能力
隐私马赛克:每个检测到的人脸都使用自身像素进行马赛克处理——可识别为人物,但无法识别具体面容。
准确人员计数:对唯一人员进行计数(非逐帧检测计数),采用最近中心人脸追踪器。检测器短暂丢失人脸不会导致同一人被重复计数。
屏幕实时显示:左上角显示 总计(历史确认人数)和 当前画面内(当前画面中已确认的人数)。
三路平铺推理:将 16:9 画面以两个重叠的 720×720 正方形窗口再次推理,最小可检测人脸从 31 px 缩小至 18 px——覆盖靠近镜头边缘原本会漏检的人脸。
绿色确认框:仅在追踪轨迹达到确认阈值(TRACK_MIN_HITS 次检测)后才显示绿色轮廓框,确保框与计数始终一致。
本项目不仅仅是简单的人脸检测与模糊演示,它将平铺 NPU 推理、多路贪婪 NMS、免卡尔曼最近中心追踪(含确认命中连击)、逐帧 OSD 马赛克渲染整合为一个完整的边缘 AI 隐私保护系统。
https://www.bilibili.com/video/BV1gZhk6pEn6
物料清单
02
硬件
K230 / K230D 开发板
与开发板兼容的摄像头模组
LCD 显示屏(或 HDMI,取决于你的配置)
SD 卡(至少 2 GB,建议 Class 10 及以上)
软件
CanMV IDE
最新版 CanMV 固件
https://download.kendryte.com/developer/releases/canmv_k230_micropython/daily_build/
03
三步部署
步骤 1:烧录 MicroPython 固件
烧录与你的开发板型号匹配的 MicroPython 固件镜像。烧录完成后,上电并确认 CanMV IDE 连接成功。
步骤 2:运行程序
在 CanMV IDE 中打开 /sdcard/examples/05-AI-Demo/face_masking_count.py,连接开发板并运行程序。左上角显示 总计 和 当前画面内 计数。已确认追踪的人脸周围会出现绿色确认框。
工作原理
04
4.1 双通道传感器流水线
摄像头传感器并行输出两路流:
通道 0(YUV420):直送视频层显示——快速且低功耗。
通道 2(RGBP888):送至 NPU 进行 AI 推理——作为人脸检测的输入。
马赛克绘制在视频层上方的 ARGB8888 OSD 层,因此像素化效果覆盖在实时画面之上,不会破坏源帧。
4.2 三路平铺推理
检测器输入为 320×320。1280×720 画面以 0.25 倍率 letterbox 填充至检测器,底部有 140 行空白——模型 44% 的输入空间浪费在填充上。这也是为何同一帧画面还需以两个重叠的 720×720 正方形窗口再次推理:
FACE_TILES = [None, # 全帧 -- 大人脸;跨平铺接缝(0, 0, 720, 720), # 左方窗(560, 0, 720, 720), # 右方窗 -- 与左窗重叠 160 px]
720×720 方窗以 0.444 倍率 letterbox——模型输入中目标人脸放大 1.78 倍,填充浪费为零。三路检测结果以贪婪 NMS 合并(TILE_MERGE_IOU = 0.35)。250 帧相同画面实测结果:
推理方式 | 最小检测到的人脸 | 推理耗时 |
仅全帧 | 31 px | 约 10.2 ms |
全帧 + 2 个方窗 | 18 px | 约 29.7 ms |
4.3 人脸追踪与计数
逐帧对原始检测结果计数毫无意义——检测器经常丢失一两帧人脸,因此"0 → 1 → 0 → 1"不断重复,同一人每次重新检测到就加一。解决方案是最近中心人脸追踪器:
每次检测结果按最近中心距离匹配到已有轨迹(门限 = 人脸宽度 × TRACK_MAX_MOVE)。
轨迹须在连续 TRACK_MIN_HITS 次检测后才确认为"人"并计入总数。
人脸消失不超过 TRACK_TIMEOUT_MS(1200 ms)时保留其轨迹,再次出现时不会被重新计入。
丢失帧会重置命中连击,但保留轨迹——短暂遮挡不会丢失已确认人员。
4.4 马赛克像素化
每个人脸框划分为 BLOCKS × BLOCKS 个单元格(默认 6 × 6)。对每个单元格,从 AI 帧中采样其中心像素作为填充颜色——生成可识别的自像素马赛克,而非均匀色块。若像素采样失败,马赛克退化为纯色 MASK_RGB 色块,而非露出人脸。
人脸框按 PAD_RATIO(0.18)扩展以覆盖头发和下巴,再裁剪至帧边界。
4.5 遮挡保持
检测器丢帧一两帧是家常便饭。没有保持机制,这几帧中人脸会闪烁露出——隐私目的完全落空。MASK_HOLD_MS(500 ms)复用轨迹最近一次已知框,在检测器最后看到人脸后继续遮挡。包括未确认轨迹也保留遮挡——仅出现两次的人脸在等待确认期间依然被覆盖。
05
为什么侧脸不会被遮挡?
检测器基于正面人脸训练。偏离摄像头即不会被遮挡也不会被计数——而人体分割还能覆盖后脑勺。
这是脚本顶部有记录的一个有意识权衡。替代方案(body_seg.kmodel)被移除的原因:
问题 | 人体分割 | 人脸检测 |
计数准确性 | 语义分割无法区分实例——人员重叠时必然误计数 | 每个人脸一个框 = 真实计数 |
速度 | 约 600 ms/帧(约 1.6 fps) | 约 39 ms/帧(约 27 fps) |
内存 | 25 MB 权重 + 15.7 MB 输出张量;耗尽 nncase 池后直接中止 | 单一模型,在池内运行 |
MASK_HOLD_MS(500 ms)可缓解闪烁但无法修复持续的侧脸视图。系统优先保证准确计数而非全身覆盖——检测器看不到的人脸,也无法被正确计数。
参数配置
06
所有关键参数集中在 face_masking_count.py 顶部。一次只改一个,观察结果后再继续微调。
参数 | 默认值 | 效果说明 |
CONF_TH | 0.25 | 置信度阈值。0.25 为实测拐点:降低至 0.15 仅多检测到 1 px 小人脸,但 false positive 增为 4 倍;提高至 0.50 损失 20% 的检测帧数。 |
FACE_TILES | [None, 左, 右] | 方窗列表。设为 [None] 即单路推理,约 41 fps。增加方窗数可检测更小人脸,但帧率下降。 |
TRACK_MIN_HITS | 3 | 确认轨迹为"人"所需的连续检测次数。增大可减少 false positive 人员计数;减小可加快确认速度(约 130 ms 达 3 次命中)。 |
TRACK_TIMEOUT_MS | 1200 | 未见到轨迹的保留时间(毫秒)。人员移动慢的场景可增大;快速离场场景可减小。 |
TRACK_MAX_MOVE | 1.2 | 每帧最大中心位移(相对人脸宽度的倍数)。快速运动场景可增大;防止轨迹跳到相邻人脸上可减小。 |
MIN_FACE_PX | 14 | 丢弃小于此值(AI 帧像素)的检测。设为 14 px 时脚本可通过平铺达到 18 px 小人脸。提高到 20 px 会丢弃所有平铺检测结果。 |
MASK_HOLD_MS | 500 | 检测最后一次出现后继续遮挡的时间。增大可容忍更长的遮挡断连;减小可让人离场后更快停止遮挡。 |
BLOCKS | 6 | 每人脸每轴马赛克块数。6 = 36 格/脸;10 = 100 格(更细马赛克,绘制更慢)。 |
PAD_RATIO | 0.18 | 人脸框扩展比例(相对人脸宽/高的倍数)。增大可覆盖更多头部和下巴区域。 |
SHOW_STATUS | False | 开启每帧人脸计数叠加显示(紫色文字)。调试用。 |
DEBUG_TIMING | False | 每帧打印各阶段毫秒耗时。性能分析用。 |
没有参数可以解决这个问题——这是检测器模型的根本局限。若必须覆盖全身,请使用 body_seg.kmodel,但需接受速度和内存的代价。
07
还能用在哪里?
人脸遮挡不仅是一个学术演示——它使任何有人员出现的场景都能实现隐私保护计算视觉:
医院走廊和 ICU:实时患者监护但不录制人脸;统计人流同时保护隐私。
零售分析:统计独立顾客数而不识别身份;按区域跟踪停留时长,无需生物识别。
智慧教室:教师注意力追踪但不记录学生身份;统计课堂活跃参与人数。
公共交通:站台和车站的乘客负载监控;聚合人群密度,无监控之实。
工业车间:操作员安全监控——检测并统计危险区域人员,不留存任何记录。
会议和活动场所:从摄像头画面实时估算出席人数;按区域聚合人流数据。
追踪器也可扩展为记录入场/离场时间戳(已确认轨迹首次出现和最终超时消失的时刻),在完全不存储人脸的情况下提供隐私保护的停留时长日志。
关键性能数据
08
测量环境:01Studio K230 2G,固件 v1.8-0,1280×720,默认三路检测推理(约 27 fps):
阶段 | 耗时(ms) | 说明 |
kpu.run × 3 | 13.1 | NPU,不可优化 |
face_det_post_process × 3 | 8.3 | C,每路 4200 个锚框 |
ai2d 预处理 × 3 | 5.3 | 张量提升比朴素写法节省 0.9 ms |
gc.collect | 3.4 | 每帧收集最优;批量收集使 p95 帧时翻倍 |
show_image | 2.7 | OSD 刷新至显示屏 |
get_frame | 2.7 | 阻塞等待传感器 |
马赛克 + 边框 | 约 1.2/人脸 | 占总帧时不到 2% |
get_output_tensor × 3 | 0.9 | NPU 输出传输 |
osd.clear | 0.2 | OSD 重置 |
每帧总计 | 约 37–38 ms(约 27 fps) |
绘制代码(马赛克 + 边框)占总帧时不到 2%。真正影响性能的杠杆是方窗数量(FACE_TILES)和 AI 帧尺寸,而非马赛克循环本身。
单路推理(FACE_TILES = [None])= 约 24.5 ms/帧(约 41 fps)。512×512 单路 = 约 15 ms(约 65 fps)。两者都会损失小人脸检测。默认三路平铺约 27 fps 是隐私遮挡覆盖率的最佳平衡点。
09
总结
从平铺 NPU 推理与跨路 NMS,到最近中心人脸追踪(含确认命中连击)和逐格马赛克渲染,本项目展示了 K230/K230D 在隐私保护边缘 AI 视觉领域的完整潜力。
只需一块开发板、一个摄像头和两个模型文件,你就可以构建一个实时系统:统计人员数量,同时从不记录任何人脸。每一个设计决策——平铺推理优于人体分割、轨迹追踪优于逐帧计数、OSD 遮挡优于帧替换——都有脚本内的实测证据支撑。
准备好试试了吗?烧录固件、复制模型、启动脚本,解锁一种全新的边缘隐私保护人员分析方式。