OrangePi3588Media/FaceRecognition_SchemeB.md
sladro 7f30d70d5a
Some checks are pending
CI / host-build (push) Waiting to run
CI / rk3588-cross-build (push) Waiting to run
测试人脸识别功能,刚刚开发完成
2026-01-07 17:15:07 +08:00

8.5 KiB
Raw Blame History

人脸识别方案 Bai_face_det + ai_face_recog设计文档

目标:在现有 Graph(DAG)+Plugin Node 框架中,实现“有人脸库,可识别具体姓名/陌生人”。

约束:

  • 插件化接入:新能力以 Node 插件形式加入 pipeline不改动主业务流程即可启用/禁用。
  • 与现有 publishFrame::user_meta 的使用不冲突。
  • 运行平台RK3588RKNN/NPU 优先CPU 负责检索与业务逻辑。

1. 总体架构

1.1 现有框架要点(与本方案的衔接)

  • Node 插件接口:INodeInit/Start/Process/Stop/UpdateConfig),通过 REGISTER_NODE 导出符号加载。
  • 数据承载:Frame 内含图像数据DMA/CPU以及元数据
    • frame->det:当前用于通用检测(DetectionResult
    • frame->user_meta:扩展元数据(当前 publish 会写入编码包 meta
  • 推理:AiScheduler 支持 RKNN 模型加载与推理(可复用)。

1.2 方案 B 的节点拆分

新增两个 Filter 插件:

  1. ai_face_det:人脸检测(可选输出关键点)
  • 输入RGB/BGR/NV12根据你的 preprocess 输出)
  • 输出:人脸框列表(可含 5 点关键点)、检测置信度
  1. ai_face_recog:人脸对齐/裁剪 + 特征提取 + 人脸库检索 + 陌生人判定
  • 输入:原始 Frame + ai_face_det 的检测结果
  • 输出识别结果person_id/name/similarity/unknown、可选把“姓名”写回可视化/告警侧

推荐拓扑:

[input_*] → [preprocess] → [ai_face_det] → [ai_face_recog] → [osd/alarm/publish/storage]

2. 数据与元数据协议(关键设计点)

2.1 为什么不直接复用 Frame::user_meta

当前 publish 节点会写 frame->user_meta(编码包 meta。如果 ai_face_* 也直接写同一字段,会出现覆盖/冲突。

2.2 推荐的元数据承载方式(二选一)

选项 1推荐长期干净:扩展 Frame 结构新增专用字段,例如:

  • std::shared_ptr<FaceDetResult> face_det;
  • std::shared_ptr<FaceRecogResult> face_recog;

优点:不与 user_meta 冲突,类型清晰,插件协作简单。

选项 2兼容性强侵入更小引入“MetaBundle”统一承载多类 meta并把 Frame::user_meta 变成 bundle。

  • user_meta 保存 std::shared_ptr<MetaBundle>,由 bundle 内部维护多个 typed slot例如 publish_meta、face_meta…

优点:不新增 Frame 字段;缺点:需要先统一改造现有写 user_meta 的插件(至少 publish/alarm

本文后续描述以 选项 1 为主(更直观)。

2.3 FaceDetResult 数据结构(建议)

  • faces[]:每个元素包含
    • bboxx,y,w,h图像坐标
    • score
    • landmarks[5](可选:左眼/右眼/鼻尖/左嘴角/右嘴角)
    • track_id(可选,后续可加跟踪)

2.4 FaceRecogResult 数据结构(建议)

  • items[]:每个元素与一个人脸对应
    • bbox
    • best_person_id / best_name / best_sim
    • unknownbool
    • second_sim(可选,用于 margin 判定/调试)
    • embedding(可选:用于注册/调试;生产可关闭以省内存)

3. 算法与模型选型

3.1 检测模型ai_face_det

推荐轻量SCRFD/RetinaFace 类人脸检测(可带 5 点)。

  • 输入分辨率320/640 任选(权衡精度与速度)
  • 输出bbox + score +可选5 点

3.2 特征模型ai_face_recog

推荐ArcFace 系列轻量 backboneMobileFaceNet 等)。

  • 输入112x112 aligned face
  • 输出128D 或 512D embedding
  • 后处理L2 normalize

3.3 相似度与陌生人判定

  • 相似度cosine归一化后点积
  • 判定规则建议:
    • top1_sim >= T_accept 且(可选)top1_sim - top2_sim >= T_margin → 识别为该人
    • 否则 unknown

阈值需要按你的数据集标定(不同模型差别大),但架构层支持动态配置。


4. 人脸库Gallery设计

4.1 存储形态

建议分两层:

  • 内存索引:运行时检索用(向量矩阵 + person 映射)
  • 持久化存储:用于重启恢复/管理

持久化方案:

  1. SQLite推荐

    • person(id, name, created_at, updated_at, extra_json)
    • embedding(person_id, emb BLOB, normed, created_at)
  2. 文件(简化版):

    • gallery.bin(向量)+ gallery.jsonperson 映射)

4.2 多样本策略

  • 每人保存 N 个样本 embedding建议 3~10
  • 运行时维护 centroid(平均向量再归一化)提高稳定性;检索可先比 centroid再必要时比多样本。

4.3 检索实现

  • 小库≤几千人CPU 暴力点积足够。
  • 大库(≥几万人):再考虑 ANNHNSW/Faiss属于后续优化不影响方案 B 的接口。

5. 两个节点的职责、接口与配置

5.1 ai_face_det插件

职责

  • Frame 获取图像(必要时做色彩/resize
  • 调用 AiScheduler 推理检测模型
  • 生成 FaceDetResult 写入 frame->face_det

配置建议(示例)

{
  "id": "face_det",
  "type": "ai_face_det",
  "role": "filter",
  "enable": true,
  "model_path": "/models/scrfd_640.rknn",
  "conf": 0.6,
  "nms": 0.4,
  "max_faces": 10,
  "output_landmarks": true,
  "input_format": "rgb" 
}

5.2 ai_face_recog插件

职责

  • 读取 frame->face_det
  • 对每个 face
    • (可选)按 5 点对齐affine
    • crop/resize 到识别模型输入
    • AiScheduler 推理得到 embedding并 L2 normalize
    • 在人脸库检索,输出 best match 或 unknown
  • 写入 frame->face_recog

配置建议(示例)

{
  "id": "face_recog",
  "type": "ai_face_recog",
  "role": "filter",
  "enable": true,
  "model_path": "/models/arcface_112.rknn",
  "gallery": {
    "backend": "sqlite",
    "path": "/data/face_gallery.db",
    "load_on_start": true,
    "cache_in_memory": true
  },
  "threshold": {
    "accept": 0.45,
    "margin": 0.05
  },
  "max_faces": 10,
  "align": true,
  "emit_embedding": false
}

6. 与 OSD / Alarm / Publish 的集成策略

6.1 OSD 显示姓名

现状:osd 只读 frame->det 并通过 cls_id → labels 显示类别名,不支持动态姓名。

推荐方案:

  • 扩展 osd:若 frame->face_recog 存在,则在 bbox 处绘制 name(sim);否则保持原逻辑。
  • 或新增 osd_face 插件专门画人脸识别结果(与原 osd 并存)。

6.2 Alarm 规则与上报

推荐:在 alarm 中新增一种事件源:

  • 读取 frame->face_recog,按规则触发(例如:出现黑名单人员、陌生人出现、某人出现次数/停留时间)。

6.3 Publish/Storage

  • 与人脸识别无强耦合:只要不覆盖 user_meta,推流/录像可照常工作。

7. 性能与线程模型建议

  • ai_face_detai_face_recog 都是 filter 节点,由 GraphMgr 驱动 Process(frame)
  • 推理层复用 AiScheduler(其内部对每个 model context 有互斥保护),可减少重复加载。
  • 关键优化点:
    • 尽量在 preprocess 输出 RGB/BGR避免在两个节点重复色彩转换。
    • 对齐与裁剪尽量复用 CPU SIMD 或 RGA若你已有 RGA 路径)。
    • 检索使用批量点积(向量矩阵乘),人数不大时可用简单循环即可。

8. 一步步实现计划(后续按此执行)

你确认开始开发后,我们将严格按以下步骤逐步实现与验证。

Step 0确定元数据承载方式必须先定

  • 选择“Frame 新字段face_det/face_recog”或“MetaBundle”。
  • 若选择新字段:需要同步更新相关 include、序列化/metrics如有以及 OSD/Alarm 读取逻辑。

Step 1新增公共头文件与数据结构

  • 定义 FaceDetResult / FaceRecogResultinclude 目录下)。

Step 2实现插件 ai_face_det

  • CMake 加入新插件目标
  • 使用 AiScheduler 加载/推理检测模型
  • 输出 FaceDetResult

Step 3实现插件 ai_face_recog

  • 读取 FaceDetResult
  • 对齐/裁剪/推理/归一化
  • 实现 GallerySQLite 或文件(先做最简单可用版本)
  • 输出 FaceRecogResult

Step 4OSD/Alarm 接入(最小可用)

  • OSD显示 name/unknown
  • Alarm支持“陌生人出现/指定人员出现”触发

Step 5配置与热更新

  • UpdateConfig 支持阈值、gallery reload 等

Step 6验证

  • 使用样例视频/RTSP 流验证:识别准确率、误认率、性能、内存