483 lines
14 KiB
Markdown
483 lines
14 KiB
Markdown
# 人脸识别按轨迹聚合告警设计
|
||
|
||
## 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. 预期效果
|
||
|
||
设计实现后,车间人脸识别告警行为应达到以下效果:
|
||
|
||
- 低质量人脸观测被直接忽略
|
||
- 已知员工通过多帧聚合而非单帧偶然命中被确认
|
||
- 同一个已知人不会因为个别低分帧被误报为陌生人
|
||
- 同一个人在场期间最多触发一次身份类告警
|
||
- 人员短时离场再进入时不会重复打卡
|
||
- 陌生人告警数量减少,但可信度明显提高
|
||
|
||
这正是当前车间部署所需要的取舍方向:降低告警频率,提高告警精度。
|