diff --git a/docs/config_guide.md b/docs/config_guide.md index ecce9eb..9b83632 100644 --- a/docs/config_guide.md +++ b/docs/config_guide.md @@ -213,6 +213,101 @@ input_rtsp - 稳定人框 - 为鞋子关联和按人节流提供 `track_id` +### 3.4.1 人脸检测和识别 + +完整流程中,人脸检测/识别建议放在 `person_trk` 之后,让人脸识别可以复用人体跟踪结果: + +```text +pre_rgb -> face_det -> person_det -> person_trk -> face_recog -> ... +``` + +人脸检测可使用 `ai_scrfd_sliding`,在 1080p 高机位画面中建议按左右窗口滑动检测: + +```json +{ + "id": "face_det", + "type": "ai_scrfd_sliding", + "enable": true, + "infer_fps": 3, + "model_path": "./models/scrfd_500m_640.rknn", + "model_w": 640, + "model_h": 640, + "windows": [ + {"x": 0, "y": 0, "w": 960, "h": 1080}, + {"x": 960, "y": 0, "w": 960, "h": 1080} + ], + "conf_thresh": 0.5, + "nms_thresh": 0.4, + "max_faces": 50 +} +``` + +人脸识别节点示例: + +```json +{ + "id": "face_recog", + "type": "ai_face_recog", + "enable": true, + "infer_fps": 2, + "infer_phase_ms": 120, + "model_path": "./models/mobilefacenet_arcface.rknn", + "align": true, + "emit_embedding": false, + "max_faces": 50, + "person_class_id": 0, + "track_state_key": "full_pipeline_1080p_workshoe", + "track_state_max_age_ms": 1000, + "input_format": "rgb", + "input_dtype": "uint8", + "threshold": { + "accept": 0.45, + "margin": 0.05 + }, + "gallery": { + "backend": "sqlite", + "path": "./models/face_gallery.db", + "load_on_start": true, + "expected_dim": 512, + "dtype": "auto" + }, + "debug": { + "enabled": true, + "log_matches": true, + "min_log_interval_ms": 0 + } +} +``` + +关键参数: + +| 参数 | 作用 | 当前建议 | +|------|------|----------| +| `face_det.infer_fps` | 人脸检测频率 | `3`,多人/小脸测试时可提高,性能紧张时降低 | +| `face_recog.infer_fps` | 人脸识别频率 | `2`,与人体/鞋检测错峰运行 | +| `infer_phase_ms` | 推理错峰 | `120` 左右,避免多个 NPU 节点同一时刻抢资源 | +| `align` | 使用 5 点关键点做人脸对齐 | 建议 `true` | +| `threshold.accept` | 识别为已知人的最低相似度 | 当前测试用 `0.45` | +| `threshold.margin` | top1 与 top2 的最小差值 | 当前测试用 `0.05`,用于降低相似人员误认 | +| `gallery.path` | SQLite 人脸库路径 | `./models/face_gallery.db` | +| `gallery.expected_dim` | embedding 维度 | `512`,需与识别模型一致 | +| `track_state_key` | 读取人体跟踪状态的 key | 必须与 `tracker.state_key` 一致 | +| `track_state_max_age_ms` | 可接受的跟踪状态最大年龄 | `1000` 左右 | +| `debug.log_matches` | 打印每次人脸匹配结果 | 测试阶段开启,正式运行可关闭 | + +识别状态含义: + +- `known`:满足 `threshold.accept` 和 `threshold.margin`,可以作为“已知人”证据。 +- `uncertain`:像某个已知人,但证据不足;不会直接当作陌生人。 +- `unknown`:保留给明确陌生人语义。当前人脸识别节点主要输出 `known` / `uncertain`,陌生人告警由 alarm 结合 track 聚合、质量门槛和“没有已知人证据”来判断。 + +人脸库说明: + +- SQLite 人脸库支持同一个人多条 embedding。 +- 建议每个人至少提供正脸,条件允许时增加左/右侧脸或不同光照照片。 +- 运行时检索会先按 `person_id` 聚合,同一个人的多张照片不会互相抢 top1/top2。 +- 真实场景只有几十人时,不需要担心多 embedding 带来的库大小问题。 + ### 3.5 ai_shoe_det ```json @@ -442,6 +537,72 @@ input_rtsp - 蓝框稳定出现 2 次以上,且持续约 `800ms`,才触发 - 触发后进入 `15s` 冷却,避免反复刷屏 +完整流程中还可以配置人脸告警: + +```json +{ + "face_track_aggregation": { + "known": { + "min_hits": 1, + "hit_window_ms": 3000, + "reentry_cooldown_ms": 8000 + }, + "unknown": { + "min_track_age_ms": 2000, + "min_quality_hits": 4 + } + }, + "face_rules": [ + { + "name": "unknown_face", + "type": "unknown", + "cooldown_ms": 7000, + "min_sim": 0.35, + "min_hits": 1, + "hit_window_ms": 1500, + "min_face_area_ratio": 0.001, + "min_face_aspect": 0.6, + "max_face_aspect": 1.6 + }, + { + "name": "known_person", + "type": "person", + "cooldown_ms": 7000, + "min_sim": 0.45, + "min_hits": 1, + "hit_window_ms": 1500, + "min_face_area_ratio": 0.0002, + "min_face_aspect": 0.6, + "max_face_aspect": 1.6 + } + ] +} +``` + +人脸告警关键参数: + +| 参数 | 作用 | 设置建议 | +|------|------|----------| +| `face_track_aggregation.known.min_hits` | 同一人体 track 需要多少次 `known` 才触发已知人告警 | 验证链路用 `1`;正式运行建议 `2` 或 `3` | +| `face_track_aggregation.known.hit_window_ms` | `known` 证据累计窗口 | `3000`,人脸出现时间短可适当加大 | +| `face_track_aggregation.known.reentry_cooldown_ms` | 同一已知人短时间离开再进入时的抑制时间 | 打卡场景建议开启,例如 `8000` 以上 | +| `face_track_aggregation.unknown.min_track_age_ms` | 陌生人候选 track 至少持续多久 | 建议 `2000` 起,避免一闪而过的小脸误报 | +| `face_track_aggregation.unknown.min_quality_hits` | 陌生人候选需要多少次有效质量帧 | 建议 `4` 起,保证陌生人告警更准 | +| `face_rules[].min_sim` | 进入该规则的最低相似度条件 | `known_person` 当前测试为 `0.45` | +| `face_rules[].min_face_area_ratio` | 过滤小脸框 | 1080p 下 `0.0002` 约等于 `415px²`,`0.001` 约等于 `2074px²` | +| `face_rules[].cooldown_ms` | 同一规则冷却 | 测试可 `7000`,正式按后台接收频率调整 | +| `face_rules[].min_face_aspect / max_face_aspect` | 过滤异常长宽比人脸框 | 默认 `0.6` 到 `1.6` | + +`min_face_area_ratio` 取值参考,按 1920x1080 画面计算: + +| 参数值 | 面积阈值 | 典型含义 | +|--------|----------|----------| +| `0.0001` | 约 `207px²` | 很宽松,容易放过极小脸 | +| `0.0002` | 约 `415px²` | 当前测试值,可过滤明显小框,同时保留 `22x36` 级别人脸 | +| `0.0003` | 约 `622px²` | 更稳,适合人脸稍大的现场 | +| `0.0005` | 约 `1037px²` | 较严格,适合近距离较清晰人脸 | +| `0.001` | 约 `2074px²` | 对高机位远景视频通常过严 | + --- ## 4. 连接关系 @@ -511,6 +672,10 @@ input_rtsp | `shoe_assoc` | `max_shoe_width_ratio` | 控制偏宽大框是否被过滤 | 双鞋合并框、大鞋框更少 | 更容易放过双鞋框和裤腿大框 | | `shoe_assoc` | `max_shoe_area_ratio` | 控制偏大面积鞋框是否被过滤 | 大误框更少 | 大误框更容易进入颜色判断 | | `shoe_assoc` | `max_shoe_roi_width_ratio / max_shoe_roi_height_ratio / max_shoe_roi_area_ratio` | 控制相对脚部 ROI 的鞋框上限 | 更能拦住整块脚区误框 | 更容易保留整块 ROI 级误报 | +| `face_recog` | `threshold.accept` | 控制已知人识别最低相似度 | 误认减少,但 known 变少 | known 变多,但误认风险升高 | +| `face_recog` | `threshold.margin` | 控制 top1 和 top2 的区分度 | 相似人员误认减少,但 known 变少 | known 变多,但相似人员更容易混淆 | +| `known_person` | `min_face_area_ratio` | 控制已知人告警可接受的人脸最小尺寸 | 小脸告警减少,更稳 | 更容易触发,但小脸质量风险升高 | +| `face_track_aggregation.known` | `min_hits` | 控制已知人需要多少次稳定识别才告警 | 更稳,适合正式打卡 | 更灵敏,适合验证链路 | | `alarm` | `min_duration_ms` | 控制要稳定多久才报警 | 更稳,但慢一点 | 更灵敏,但更容易闪报 | | `alarm` | `cooldown_ms` | 控制两次告警间隔 | 减少重复告警 | 同一事件会更频繁重复报 | @@ -546,6 +711,20 @@ input_rtsp - 再降低 `face_recog.infer_fps` - 再考虑降低 `dynamic_roi.max_rois` +- 已知人识别有 `known`,但没有 `known_person` 告警: + - 先看日志中是否有 `status=known` + - 再看 `person_track_id` 是否为有效值,`-1` 不能用于按人稳定聚合 + - 检查 `known_person.min_sim` + - 检查 `known_person.min_face_area_ratio` + - 检查 `face_track_aggregation.known.min_hits` + - 验证链路时可临时用 `min_hits=1`;正式打卡场景建议恢复到 `2` 或 `3` + +- 大量 `uncertain`,known 较少: + - 先确认人脸库是否加载:日志应有 `gallery loaded: n=<数量> dim=512` + - 确认同一个人是否录入了正脸、侧脸等多张照片 + - 检查人脸框尺寸,远景小脸通常 best_sim 和 margin 都偏低 + - 不要把 `uncertain` 当作陌生人直接上报 + --- ## 7. 常见问题 @@ -573,7 +752,22 @@ input_rtsp 这通常说明问题在输入解码兼容性,而不是 AI 链路。 +### Q4: 为什么日志里有 known,但后台没有 known_person 告警? + +`known` 只是识别节点给出的单帧结果。告警还需要通过 `known_person` 的质量门槛和 `face_track_aggregation.known` 的稳定聚合。 + +优先检查: + +- `person_track_id` 是否有效,`-1` 无法按人聚合。 +- `known_person.min_face_area_ratio` 是否过高。1080p 下 `0.001` 约等于 `2074px²`,远景小脸常常达不到。 +- `face_track_aggregation.known.min_hits` 是否过高。测试触发链路可用 `1`,正式打卡建议 `2` 或 `3`。 +- `known_person.cooldown_ms` 和 `known.reentry_cooldown_ms` 是否正在抑制重复上报。 + +### Q5: unknown 和 uncertain 有什么区别? + +`uncertain` 表示“像某个已知人,但证据不足”,不能当作陌生人。`unknown_face` 应用于“持续存在、质量足够、且没有形成已知人证据”的人体 track。这样可以避免远处小脸、合成人脸或短暂模糊帧被误报成陌生人。 + --- -**版本**:v2.0 -**更新日期**:2026-03-15 +**版本**:v2.1 +**更新日期**:2026-04-16