# 人脸识别按轨迹聚合告警设计 ## 1. 背景 当前人脸识别告警链路为: `face_det -> face_recog -> alarm.face_rules -> actions` 现有链路已经具备以下能力: - 从 gallery 中识别已知人员 - 基于单帧 embedding 匹配结果输出 `known` 或 `uncertain` - 生成 `known_person` 和 `unknown_face` 告警 - 通过现有 alarm action 链路上传截图和视频片段 但当前告警行为仍然主要由单帧人脸识别结果驱动。在车间测试中,同一个已知人员可能出现: - 近距离、高质量帧触发 `known_person` - 远距离、小脸、低质量帧被误当作陌生人候选并触发 `unknown_face` 这不符合目标场景要求。对当前车间场景来说: - 低质量人脸数据可以直接忽略 - 告警准确率优先于告警召回率 - 告警频率需要尽量低 - 已知人员告警用于后台打卡 - 人员短暂离场再进入,不应重复触发打卡告警 仓库中已经有人体 tracker 和基于 `track_id` 的鞋子识别逻辑。本设计优先复用这套能力,而不是再新增一套独立的人脸 tracker。 ## 2. 目标 ### 2.1 功能目标 - 复用现有人体 `track_id` 进行人脸身份聚合 - 不再把 `unknown` 简单视为 `known` 的反面 - 对低质量人脸直接忽略,而不是强行归类为 `unknown_face` - 告警由“按单帧”改为“按人轨迹” - 同一个人持续在场时不重复触发告警 - 人员短时离场再进入时不立即重复告警 ### 2.2 非目标 - 不替换现有人体 tracker 实现 - 不新增独立的人脸 tracker - 不修改人脸 embedding 提取和 gallery 检索逻辑 - 不把检测、识别、跟踪、告警合并到一个插件中 ## 3. 现状分析 ### 3.1 已有能力 - `plugins/tracker/tracker_node.cpp` - 会给 `frame->det` 中的人体检测框写入稳定的 `track_id` - `plugins/logic_gate/logic_gate_node.cpp` - 已经基于人体 `track_id` 做鞋子关联与规则判断 - `plugins/ai_face_det/*` 与 `plugins/ai_face_recog/ai_face_recog_node.cpp` - 已经能输出人脸检测和人脸识别结果 - `plugins/alarm/alarm_node.cpp` - 已经支持人脸规则和现有告警 action 链路 ### 3.2 当前缺口 当前人脸链路实际上没有接入人体跟踪能力: - `FaceDetItem` 虽然有 `track_id` 字段,但当前人脸检测节点都填的是 `-1` - `FaceRecogItem` 只保留了 gallery 身份字段,如 `best_person_id` - 当前人脸告警投票 key 为: - 已知人规则使用 `best_person_id` - 陌生人规则直接使用固定值 `unknown` 这意味着当前人脸告警链路无法回答以下问题: - 两帧是否属于同一个真实人 - 某一帧的低分结果是否属于刚刚已经识别成功的那个人 - 某人还在画面中时,是否应该抑制重复告警 ## 4. 设计概述 本设计在现有人体跟踪之上增加“按轨迹聚合的人脸身份确认层”。 改造后的行为如下: 1. 人体检测继续由现有 tracker 生成 `track_id` 2. 每张识别出的人脸在同帧内关联到一个人体框 3. 将关联后的人体 `track_id` 写入人脸识别结果 4. `alarm` 按 `person_track_id` 聚合多帧识别证据 5. 告警层身份判定改为三态: - `known` - `unknown` - `uncertain` 6. 只有稳定的 `known` 或稳定的 `unknown` 才允许触发告警 7. `uncertain` 状态直接忽略,不触发身份类告警 这样可以保持当前 DAG 架构和插件边界不变: - tracker 只负责跟踪人体 - 人脸插件只负责输出识别证据。识别节点没有 `unknown` 分类,只输出 `known` / `uncertain` - alarm 节点负责业务层面的身份确认、去重和抑制 ## 5. 数据流设计 目标运行链路变为: `person_det -> tracker -> face_det -> face_recog(face-person association) -> alarm(track-aware face rules) -> actions` ### 5.1 人脸与人体关联 对每一张识别出的人脸,在同一帧的 `frame->det` 中寻找一个已经具备有效 `track_id` 的人体框进行关联。 建议采用以下匹配顺序: 1. 优先选择“人脸中心点落在人框内”的人体框 2. 若存在多个候选,则选择重叠关系最合理的那个 3. 若不存在包含关系,可选地退化到 IoU / overlap ratio 匹配 4. 若仍无可靠匹配,则该人脸视为未关联成功 这个方案简单、稳定,也更适合当前车间摄像头场景,因为正常情况下一个人脸应当落在一个人体框内部。 ### 5.2 结果增强 对人脸识别结果增加与人体轨迹关联后的字段。 建议给 `FaceRecogItem` 增加: - `int person_track_id = -1` - 可选预留字段:`float person_match_score` 这样下游插件可以直接消费“带有人体连续性信息的人脸识别结果”,而不用再次读取原始人体框做推断。 ## 6. 身份状态模型 在 `alarm` 节点中,按 `person_track_id` 维护一份短生命周期的人脸身份聚合状态。 建议维护的字段包括: - `track_id` - `first_seen_ms` - `last_seen_ms` - `last_quality_pass_ms` - `best_known_person_id` - `best_known_name` - `best_sim_peak` - `best_known_hit_count` - `quality_pass_count` - `unknown_candidate_count` - `reported_known` - `reported_unknown` - `last_report_ms` 这份状态在轨迹有效期间存在,并在短暂 retention 窗口内保留,用于实现短时离场重入抑制。 ## 7. 三态判定模型 ### 7.1 状态定义 每个 `person_track_id` 在 alarm 聚合层只能处于以下三种状态之一: - `uncertain` - 质量不足,或证据不足 - `known` - 已经稳定确认属于某个已知人员 - `unknown` - 已经稳定确认无法归属到已知人员 注意:`unknown` 不是人脸识别模型或 `ai_face_recog` 节点的单帧输出。人脸识别模型输出 embedding,识别节点只判断当前帧是否可作为 `known` 证据;无法确认已知人时统一输出 `uncertain`。`unknown` 只在 alarm 层经过质量门控、持续跟踪和低已知相似度验证后形成。 ### 7.2 为什么必须引入 `uncertain` `uncertain` 是本方案的关键。 以下情况都应保持为 `uncertain`: - 人脸太小 - 对齐质量差 - 运动模糊 - 距离过远 - 相似度波动明显 - 当前轨迹累计证据不足 这些观察结果都不应直接触发身份类告警。 ## 8. 质量门控 只有通过质量门控的人脸观测,才允许进入身份聚合逻辑。 建议质量条件包括: - 已关联到有效 `person_track_id` - 人脸面积占比达到下限 - 人脸长宽比处于合理范围 - 当需要对齐时,必须具备有效 landmarks - 可选:人脸最小像素宽高门限 - 可选:最小人脸检测置信度 若某一帧未通过质量门控: - 不计入 `unknown` - 不计入 `known` - 保持该轨迹状态为 `uncertain` 这与当前车间场景的业务要求一致:低质量数据可以直接忽略。 ## 9. 已知人确认策略 已知人确认必须基于“同一人体轨迹内,对同一 gallery 身份的持续命中”。 建议条件如下: - 当前帧通过质量门控 - `best_person_id >= 0` - `best_sim >= known_accept` - `(best_sim - second_sim) >= known_margin` - 在 `known_hit_window_ms` 时间窗内,同一个 `best_person_id` 至少命中 `known_min_hits` 次 可选增强: - 若 `best_sim` 足够高且连续稳定,可允许 peak-sim 快速确认 一旦某条轨迹稳定进入 `known`: - 触发一次 `known_person` - 标记该轨迹 `reported_known = true` - 在该轨迹存活期间不再重复触发已知人告警 ## 10. 陌生人确认策略 陌生人确认必须比已知人确认更保守。 陌生人不应被定义为: - “这一帧不是 known” 陌生人应被定义为: - “这个人已经被持续观察了足够长时间,且人脸质量足够,但始终无法稳定归入任何已知身份” 建议条件如下: - 当前帧通过质量门控 - 存在有效 `person_track_id` - 轨迹存活时间超过 `unknown_min_track_age_ms` - 质量合格帧数达到 `unknown_min_quality_hits` - 该轨迹尚未稳定确认过已知人 - 在观察窗口内始终未满足已知人确认条件 可选附加条件: - top1 候选身份长期不稳定 - 多帧均处于低置信或模糊匹配状态后,才允许最终确认陌生人 一旦某条轨迹稳定进入 `unknown`: - 触发一次 `unknown_face` - 标记该轨迹 `reported_unknown = true` - 在该轨迹存活期间不再重复触发陌生人告警 ## 11. 告警去重与重入抑制 ### 11.1 轨迹内去重 在同一个活跃 `person_track_id` 内: - `known_person` 最多只允许触发一次 - `unknown_face` 最多只允许触发一次 ### 11.2 离场重入抑制 当前场景中的已知人告警,本质上是打卡行为,因此: - 同一个员工仍在画面中时,不应重复打卡 - 同一个员工短暂离开又回来时,也不应立即重复打卡 建议引入两类抑制 key: - 已知人:按 `gallery person_id` 做冷却 - 陌生人:按最近轨迹历史做冷却,后续可再增强为更稳定的陌生人指纹 建议增加两个可配置时间: - `known_reentry_cooldown_ms` - `unknown_reentry_cooldown_ms` 对于已知人,冷却时间应当相对较长,因为打卡行为本来就应当是稀疏的。 ## 12. 配置设计 建议在 `alarm` 侧新增一组专门的人脸轨迹聚合配置。可以挂在 face rule 相关路径下,或作为 alarm 的一个同级子配置。 建议字段如下: ```json { "face_track_aggregation": { "enable": true, "associate_with_person_track": true, "require_person_track": true, "person_match_mode": "face_center_in_person", "person_match_min_iou": 0.05, "quality": { "min_face_area_ratio": 0.001, "min_face_width": 32, "min_face_height": 32, "require_landmarks": true }, "known": { "accept": 0.45, "margin": 0.05, "min_hits": 3, "hit_window_ms": 3000, "reentry_cooldown_ms": 300000 }, "unknown": { "min_track_age_ms": 2000, "min_quality_hits": 4, "reentry_cooldown_ms": 300000 } } } ``` 说明: - 具体挂载位置可再根据现有配置风格微调 - 尽量保留现有 face rule 字段,避免一次性破坏旧配置 - 迁移时应优先保证兼容性和平滑切换 ## 13. 文件级改动建议 ### 13.1 数据结构 修改: - `include/face/face_result.h` 改动内容: - 给 `FaceRecogItem` 增加 `person_track_id` - 可选预留后续关联置信度等扩展字段 ### 13.2 人脸识别节点 修改: - `plugins/ai_face_recog/ai_face_recog_node.cpp` 改动内容: - 对每张识别结果做人脸与人体关联 - 将关联后的人体 `track_id` 写入 `FaceRecogItem` - 扩展 debug 日志,输出 `person_track_id` ### 13.3 告警节点 修改: - `plugins/alarm/alarm_node.cpp` 改动内容: - 增加按轨迹聚合的人脸身份状态 - 用按 `track_id` 的持续观察,替代当前单帧驱动的陌生人确认逻辑 - face vote key 优先使用 `person_track_id` - 增加已知人 / 陌生人的按轨迹去重和离场重入抑制 ### 13.4 测试 建议新增或修改以下平台无关测试: - 人脸与人体关联逻辑测试 - 按轨迹已知人确认测试 - 按轨迹陌生人抑制测试 - 离场重入冷却测试 ## 14. 兼容性与迁移策略 该设计应以“向后兼容优先”的方式落地。 建议策略: 1. 保留现有 face recognition 输出字段 2. 用新增字段而不是重命名旧字段 3. 当 track-aware aggregation 未开启时,继续支持当前旧行为 4. 在 rollout 期间允许旧 face rules 与新聚合模式并存,用于对比效果 这样可以实现: - 更安全的分阶段上线 - 便于对比新旧逻辑行为差异 - 更容易在 RK3588 上做联调和回归 ## 15. 验证策略 ## 15.1 本地代码级验证 本地验证只聚焦平台无关逻辑: - 人脸与人体关联行为 - 聚合状态机状态转换 - 已知人确认窗口逻辑 - 陌生人抑制逻辑 - 离场重入冷却逻辑 - 配置解析与兼容性 ## 15.2 RK3588 设备侧验证 最终验证必须在 RK3588 上完成: - 已知人从远到近进入画面 - 预期:延迟但稳定触发 `known_person` - 预期:不出现 `unknown_face` 误报 - 已知人短暂离场并快速重入 - 预期:不重复触发打卡 - 已知人长时间离场并超过冷却后再进入 - 预期:允许再次打卡 - 真正陌生人且人脸质量足够 - 预期:经过持续观察后触发一次 `unknown_face` - 低质量陌生人 - 预期:不触发告警 - 同帧多个人体 - 预期:人脸与人体关联正确,不串轨 ## 16. 风险与缓解 ### 风险 1:人脸与人体关联错误 影响: - 识别证据可能被挂到错误的人体轨迹上 缓解: - 初版先采用简单稳定的 center-in-box 匹配 - 在 debug 模式下输出 `person_track_id` 与关联决策 - 在 RK3588 多人场景中重点验证 ### 风险 2:陌生人确认过于保守 影响: - 陌生人告警触发变慢,或数量减少 缓解: - 所有陌生人阈值均做成可配置 - 在早期 rollout 阶段宁可少报,也不要在车间场景中误报 ### 风险 3:离场重入抑制过强 影响: - 合法的重复打卡事件可能被压掉 缓解: - 冷却时间全部做成可配置 - 在文档与配置说明中明确“当前业务语义是打卡型告警,而不是持续在场播报” ## 17. 推荐落地顺序 建议按以下顺序逐步落地: 1. 增加 `person_track_id` 传递和 debug 日志 2. 实现按轨迹的已知人确认 3. 实现保守的按轨迹陌生人确认 4. 加入离场重入抑制 5. 在 RK3588 上用已知人 / 陌生人视频做回归验证 分阶段落地可以降低风险,也更方便逐步对比行为变化。 ## 18. 预期效果 设计实现后,车间人脸识别告警行为应达到以下效果: - 低质量人脸观测被直接忽略 - 已知员工通过多帧聚合而非单帧偶然命中被确认 - 同一个已知人不会因为个别低分帧被误报为陌生人 - 同一个人在场期间最多触发一次身份类告警 - 人员短时离场再进入时不会重复打卡 - 陌生人告警数量减少,但可信度明显提高 这正是当前车间部署所需要的取舍方向:降低告警频率,提高告警精度。