PRD:全离线生成 `face_gallery.db`(每人 1 条 centroid,Windows+Python+ONNX) 1. 背景与目标 • 在 Windows 电脑上离线处理“注册照片”,为每个人生成 1 条 512D 人脸特征(centroid),写入 SQLite 数据库 face_gallery.db。 • RK3588 运行时 ai_face_recog 以 gallery.backend=sqlite 读取该库,实现识别(无需改线上阈值/配置逻辑)。 ────────────────────────────────────────── 2. 范围(In/Out) In Scope • 数据集扫描(按人目录) • 人脸检测(含 5 点关键点)+ 对齐到 112×112 • ArcFace/MobileFaceNet ONNX 推理生成 512D embedding • 每人多图聚合为 centroid(L2 normalize 后平均,再 L2 normalize) • 生成 SQLite:person、embedding 两表 • 生成构建报告(统计、异常、可选相似度抽检) Out of Scope • 在线注册/写库接口 • RKNN 推理/设备端工具 • 人脸库增量热更新(只生成 db 文件) ────────────────────────────────────────── 3. 用户与使用方式 目标用户 • 开发/测试人员(在 Windows 上离线准备人脸库) 使用方式(CLI) 提供脚本:build_gallery.py 示例: bash python build_gallery.py ^ --dataset "D:\faces\dataset" ^ --db_out "D:\faces\face_gallery.db" ^ --det_model "D:\models\face_det.onnx" ^ --recog_model "D:\models\mobilefacenet_arcface_bs1.onnx" ^ --expected_dim 512 ^ --max_imgs_per_person 10 ^ --pick_face largest ^ --min_face_size 80 ^ --fail_on_empty true ────────────────────────────────────────── 4. 输入数据规范 目录结构 dataset/ 张三/ 001.jpg 002.jpg 李四/ a.png b.png • 文件夹名作为 person.name(UTF-8) • 每人建议 3~10 张图(允许混合:标准大头照 + 摄像头位照片) 图片支持格式 • jpg/jpeg/png/bmp(由 OpenCV 读取) ────────────────────────────────────────── 5. 模型与前处理规范(必须严格一致) 识别模型(已确定) • 输入:float32 [1,3,112,112],输出:float32 [1,512] • 输入图像为 对齐后的 112×112 RGB • 归一化:(x - 127.5) / 128.0,其中 x 为 uint8 0..255 • HWC→CHW→NCHW 检测模型(你不要求我管来源,但脚本必须满足) • det ONNX 推理输出至少包含:bbox + 5 landmarks • 必须明确 landmark 顺序(开发在配置/代码中固定) 对齐目标点(112×112,必须固定为以下值) • (38.2946, 51.6963) • (73.5318, 51.5014) • (56.0252, 71.7366) • (41.5493, 92.3655) • (70.7299, 92.2041) 对齐方法: • 基于 5 点求相似变换(Similarity / affine partial)→ warpAffine 到 112×112,双线性插值 ────────────────────────────────────────── 6. 特征生成与聚合(每人 1 条 centroid) 对每张有效图片: 1. 检测 → 选择人脸(默认:最大脸) 2. 5 点对齐 → 112×112 RGB 3. 预处理 + ONNX 推理 → 512D embedding 4. L2 normalize(单样本) 对每个人: • 取最多 max_imgs_per_person 张有效样本 embedding(不足也可) • centroid 计算: • centroid = mean(emb_i)(对已归一化 emb 做均值) • centroid = L2_normalize(centroid) • 只写入 1 条 embedding(centroid) ────────────────────────────────────────── 7. SQLite 数据库规范(必须与现有插件兼容) 文件 • 输出文件名:face_gallery.db(路径由 --db_out 指定) 表结构(最小要求) sql CREATE TABLE IF NOT EXISTS person ( id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE ); CREATE TABLE IF NOT EXISTS embedding ( person_id INTEGER NOT NULL, emb BLOB NOT NULL, FOREIGN KEY(person_id) REFERENCES person(id) ); CREATE INDEX IF NOT EXISTS idx_embedding_person_id ON embedding(person_id); 写入规则 • person.name = 文件夹名 • embedding.emb = centroid 向量的 float32 原始字节(BLOB) • 长度必须为 expected_dim * 4(512→2048 bytes) • 每个 person 仅 1 行 embedding ────────────────────────────────────────── 8. 质量控制与异常处理 过滤规则(可配置) • min_face_size:bbox 宽或高小于阈值则丢弃 • 检测不到脸:记录为失败样本 • 多脸:默认选最大脸;可配置 --pick_face(largest/first/highest_score) 容错策略(可配置) • 单人所有图片都失败:该 person 不写入库,并在报告中列出 • --fail_on_empty true:若最终 person 数为 0 或 embedding 数为 0,则脚本返回非 0 退出码 ────────────────────────────────────────── 9. 输出报告(必须) 脚本运行结束输出: • 总人数、成功入库人数、总图片数、成功样本数、失败样本数 • 每人使用的样本数量 • 失败原因统计(no_face / small_face / align_fail / infer_fail 等) • 数据库自检: • COUNT(person)、COUNT(embedding) • 随机抽查 N 条 length(emb)==2048 (可选增强)打印每人 centroid 的 L2 norm(应接近 1.0) ────────────────────────────────────────── 10. 依赖与运行环境 • Windows 10/11 • Python 3.9+ • 依赖包: • numpy • opencv-python • onnxruntime • sqlite3:使用 Python 标准库 ────────────────────────────────────────── 11. 验收标准(可直接验) 1. 生成的 face_gallery.db 能被你当前 ai_face_recog 加载,设备日志出现:gallery loaded: n=<入库人数> dim=512 2. SQLite 校验: • SELECT COUNT(*) FROM person; == 入库人数 • SELECT COUNT(*) FROM embedding; == 入库人数 • SELECT length(emb) FROM embedding LIMIT 5; 全为 2048 3. 实测:对至少 3 人,每人 3 张注册图 + 1 条现场图,识别能输出对应姓名(阈值用现有配置不强制修改) ────────────────────────────────────────── 12. 与设备端配置的对接要求(提醒开发) • gallery.backend="sqlite" • gallery.path 指向拷贝后的 face_gallery.db • gallery.expected_dim=512 • threshold.margin 保持现有值即可(因为每人只有 1 条 centroid,不会出现“同人占 top2 导致 margin 过小”的问题)