# opencv_train_demo **Repository Path**: createmaker/opencv_train_demo ## Basic Information - **Project Name**: opencv_train_demo - **Description**: various-scenario face recognition demo - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-05-07 - **Last Updated**: 2026-06-11 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # OpenCV 自动识别 Demo 套件 > 12 个开箱即用的 OpenCV 自动识别 demo —— 经典 CV + DNN 各类任务全覆盖, > 含完整人脸识别**双流水线**: > · 经典 CV (LBPH/Eigen/Fisher) — Demo 08 + 11,离线零依赖 > · DNN 商业级 (YuNet + 5pt 对齐 + SFace + 眨眼活体) — Demo 12,等价阿里云 API 核心逻辑 > 双击 `setup.bat` 装好环境,再双击 `start.bat` 进菜单选 demo。 --- ## 一、内置 demo 一览 | # | 名称 | 关键字 | 技术栈 | 需要 | |---|---|---|---|---| | **1** | 人脸 / 眼睛 / 微笑 | `face` | Haar 级联多分类器 | 摄像头 | | **2** | 运动检测 | `motion` | MOG2 背景差分 | 摄像头 | | **3** | 颜色追踪 | `color` | HSV + TrackBar | 摄像头 | | **4** | 形状识别 | `shape` | Canny + 多边形逼近 | 摄像头 | | **5** | 二维码识别 | `qr` | cv2.QRCodeDetector | 摄像头 | | **6** | ORB 特征匹配 | `match` | ORB + 单应性矩阵 | 摄像头 | | **7** | YOLO 物体检测 | `yolo` | DNN + YOLOv4-tiny (24MB) | 摄像头 + 联网(首次) | | **8** | LBPH 人脸识别 | `recog` | Haar + LBPH (contrib) | 摄像头 | | **9** | 手部 / 数手指 | `hand` | YCrCb 肤色 + 凸缺陷 | 摄像头 | | **10**| 文档扫描 | `scan` | 边缘 + 透视矫正 + 二值 | 摄像头 | | **11**| **人脸识别训练/评估**| `train` | 三算法对比 (LBPH/Eigen/Fisher) + 80/20 评估 + 最佳阈值 | 已录入数据 | | **12**| **DNN 人脸识别(商业级)**| `dnn` | YuNet 检测 + 5pt 对齐 + SFace embedding + 眨眼活体 | 摄像头 + 联网(首次下 38MB) | --- ## 二、最快启动(Windows) ``` 1. 双击 setup.bat (首次,建 venv + 装依赖,约 2-5 分钟) 2. 双击 start.bat (进菜单) ``` 详细机制见下一节。 --- ## 三、启动脚本工作流(详解) ### 3.1 三层入口的关系 ``` ┌──────────────────────────────────────────────────────────────┐ │ 用户操作 │ └──────────┬───────────────────────────────┬───────────────────┘ │ 首次(一次性) │ 每次启动 ▼ ▼ ┌──────────────┐ ┌──────────────┐ │ setup.bat │ │ start.bat │ │ │ │ │ │ 建 venv │ │ 校验 venv │ │ 装依赖 │ │ 透传参数 │ │ 验证 cv2 │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ 生成 .venv/ │ 调用 │ ┌──────────────┐ ▼ └──▶│ .venv/ │ ┌──────────────┐ │ Scripts/ │ │ main.py │ │ python.exe │◀────┤ │ │ │ │ 解析 argv │ │ Lib/site- │ │ 菜单/直跑 │ │ packages/ │ │ lazy import │ │ cv2 ... │ └──────┬───────┘ └──────────────┘ │ │ 加载 ▼ ┌──────────────────┐ │ demos/d0X_*.py │ │ 每个有 run() │ └──────────────────┘ ``` ### 3.2 `setup.bat` —— 一次性环境搭建 **触发**:用户首次双击;或想重置环境时手工再跑。 **执行流程**(按顺序): | 步骤 | 命令 | 说明 | |---|---|---| | 1. 控制台编码 | `chcp 65001` + `set PYTHONIOENCODING=utf-8` | Windows 默认 cmd 是 GBK,会让 Python 输出的中文变成乱码。必须切到 UTF-8 | | 2. 切到脚本所在目录 | `cd /d "%~dp0"` | `%~dp0` 是 .bat 自身的目录,避免在其他位置双击时找错路径 | | 3. 选 Python 解释器 | 依次试 `py -3.12` → `py -3.13` → `py -3.11` → `py -3.10` → `python` | opencv-python 4.10 不支持 3.14,所以**优先 3.12**(最稳)。Windows 自带 `py` launcher 可以选具体版本 | | 4. 创建虚拟环境 | ` -m venv .venv` | 在项目根生成 `.venv/`,与系统 Python 完全隔离 | | 5. 升级 pip | `.venv\Scripts\python.exe -m pip install --upgrade pip` | 老 pip 解析 deps 慢/有时报错 | | 6. 安装依赖 | `pip install -r requirements.txt` | 装 4 个包,约 60-100MB(opencv 占大头) | | 7. 验证 OpenCV | `python -c "import cv2; print('OpenCV', cv2.__version__, 'OK')"` | 任何一步失败都会停在这里报错 | **成功标志**:终端最后一行打印 `OpenCV 4.10.0 OK`。 **失败处理**(脚本会停下并 `pause`): | 现象 | 原因 | 修复 | |---|---|---| | `[ERROR] 没找到 Python` | py launcher 和 python 都不在 PATH | 装 [Python 3.12](https://www.python.org/downloads/) 时勾选 "Add to PATH" | | `创建 venv 失败` | 已有同名 `.venv/` 损坏 | 删掉 `.venv/` 重跑 | | 安装 opencv 时网络超时 | pypi 国内访问慢 | 改用清华源:
`pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt` | | `OpenCV 导入失败` | Python 3.14(轮子还没发) | 卸载 venv,让 setup.bat 选到 3.12 | > 输出**完全幂等**:再跑一次 setup.bat 不会破坏现有 `.venv/`(venv 不存在才建;pip 是增量)。但通常没必要重跑。 ### 3.3 `start.bat` —— 每次启动入口 **触发**:用户每次想跑 demo 时双击;或带参数从命令行调用。 **执行流程**: ```bat 1. chcp 65001 + PYTHONIOENCODING=utf-8 ← 中文不乱码 2. cd 到脚本所在目录 3. if not exist .venv\Scripts\python.exe → 报错并提示先跑 setup.bat 4. 调用 .venv\Scripts\python.exe main.py %* - %* 把所有命令行参数原样透传给 main.py - 所以 `start.bat 7` 等价于 `python main.py 7` 5. 如果 main.py 退出码非 0,pause 让用户看到错误 ``` **用法**: ```bat start.bat :: 进菜单 start.bat 1 :: 直接跑 demo 1(人脸) start.bat face :: 用关键字 start.bat --list :: 列出所有 demo(不进菜单) ``` ### 3.4 `main.py` —— 实际程序入口 启动后做这几件事: ``` parse argv │ ├─ argv 为空 ─────────► interactive_loop() │ while True: │ print_menu() 打印 11 个 demo │ choice = input 等用户输入 │ if 0/q → return │ d = find_demo(choice) │ run_demo(d) 跑 demo(异常被捕获) │ ├─ argv[0] == --list ───► 打印 demo 列表后 exit 0 ├─ argv[0] == --help ───► 打印 docstring 后 exit 0 │ └─ 其他 ──────────────► find_demo + run_demo + exit ``` **关键设计**: | 机制 | 实现 | 为什么 | |---|---|---| | **Lazy import** | `_lazy("d01_face_eye_smile")` 返回一个 closure,调 demo 时才 `import` | 启动菜单时不加载所有 demo,避免任意一个 demo 出错导致 launcher 崩 | | **关键字匹配** | `find_demo()` 支持编号 / 短 key / 中文标题模糊匹配 | 用户可以打 `1` / `face` / `人脸` 任一种 | | **异常隔离** | `run_demo()` 用 try/except 包住每个 demo 的 `run()` | demo 崩了打印 traceback,按回车回菜单,launcher 不受影响 | | **ANSI 颜色** | Windows 10+ 用 `kernel32.SetConsoleMode` 启 VT 模式 | 菜单有颜色更醒目;老终端不支持时自动降级到无色 | | **退出语义** | demo 内部按 Q/ESC 退出 `cv2.imshow` 循环 → `run()` 返回 → 回菜单 | 不需要重启 launcher 就能切 demo | ### 3.5 demo 运行时(每个 demo 共同的生命周期) 所有 10 个 demo 都遵循相同骨架: ```python def run() -> None: cap = open_camera() # ① 打开摄像头(DSHOW + 重试 + 预热) fps = FpsMeter() # ② 帧率计量 try: while True: ok, frame = read_frame(cap, mirror=True) # ③ 读帧(自拍镜像) if not ok: break # ④ 业务识别逻辑(每个 demo 不同) ... fps.tick() fps.overlay(frame) # ⑤ 顶部画 FPS frame = draw_hint_bar(...) # ⑥ 底部画提示条 cv2.imshow("Demo XX - ...", frame) if cv2.waitKey(1) & 0xFF in (ord("q"), 27): # ⑦ Q/ESC 退出 break finally: cap.release() # ⑧ 不论怎么退都释放摄像头 cv2.destroyAllWindows() ``` **对应的工具函数**: | 工具 | 文件 | 责任 | |---|---|---| | `open_camera()` | `utils/camera.py` | Windows 优先 DSHOW 后端(启动快),最多重试 3 次,预热 5 帧丢掉首帧曝光异常 | | `read_frame()` | `utils/camera.py` | 读一帧,可选水平镜像(自拍体验更自然) | | `FpsMeter` | `utils/overlay.py` | 指数滑动平均 FPS,避免数字跳动 | | `draw_zh()` | `utils/overlay.py` | 用 PIL 在 cv2 frame 上写中文(cv2.putText 不支持中文)| | `draw_hint_bar()` | `utils/overlay.py` | 底部半透明黑条 + 操作提示文字 | | `ensure_yolov4_tiny()` | `utils/models.py` | 仅 demo 07 用:第一次自动下载 24MB 权重到 `data/models/` | ### 3.6 完整启动流程(一图看完) ``` ┌─ 你 ──────────────────────────────────────────────────────────┐ │ 双击 start.bat 1 │ └──┬───────────────────────────────────────────────────────────┘ │ ▼ ┌─ start.bat ────────────────────────────────────────────────────┐ │ chcp 65001 (UTF-8) │ │ cd /d "%~dp0" │ │ test .venv\Scripts\python.exe (有 → 继续;无 → 提示 setup) │ │ exec .venv\Scripts\python.exe main.py 1 │ └──┬───────────────────────────────────────────────────────────┘ │ ▼ ┌─ main.py ──────────────────────────────────────────────────────┐ │ argv = ["1"] │ │ d = find_demo("1") │ │ → DemoEntry(num=1, key="face", runner=_lazy("d01_...")) │ │ run_demo(d): │ │ print "启动: 1. 人脸 / 眼睛 / 微笑" │ │ d.runner() │ └──┬───────────────────────────────────────────────────────────┘ │ ▼ ┌─ demos/d01_face_eye_smile.py ─────────────────────────────────┐ │ load Haar cascades (OpenCV 自带) │ │ cap = open_camera() ← DSHOW,1280x720,预热 5 帧 │ │ while True: │ │ frame = read_frame(cap, mirror=True) │ │ faces = face_cas.detectMultiScale(gray) │ │ 画框、画眼睛、检测微笑、画 FPS、画提示条 │ │ cv2.imshow("Demo 01 - Face / Eye / Smile", frame) │ │ key = cv2.waitKey(1) │ │ if key in (Q, ESC): break │ │ if key == S: cv2.imwrite("data/snapshots/...") │ │ cap.release(); cv2.destroyAllWindows() │ └──┬───────────────────────────────────────────────────────────┘ │ 返回到 main.run_demo() ▼ ┌─ main.run_demo() ─────────────────────────────────────────────┐ │ 无异常:函数返回 │ │ 有异常:打印 traceback + input("按回车回到菜单...") │ └──┬───────────────────────────────────────────────────────────┘ │ ▼ ┌─ start.bat ────────────────────────────────────────────────────┐ │ python 退出码 = 0 → bat 退出 │ │ 退出码 != 0 → pause(让你看到错误) │ └────────────────────────────────────────────────────────────────┘ ``` ### 3.7 在哪些文件里改什么 | 想改的事 | 改这里 | |---|---| | 加一个新 demo | 1) 写 `demos/d11_xxx.py` 含 `run()`
2) `main.py::DEMOS` 加一行 `DemoEntry(11, "xxx", ...)` | | 默认摄像头 index 从 0 换 1 | `utils/camera.py::open_camera(index=...)`,或在每个 demo 里 `open_camera(index=1)` | | 摄像头分辨率 / FPS | `utils/camera.py::open_camera(width=, height=, fps=)` | | 中文字体 | `utils/overlay.py::_FONT_CANDIDATES_WIN` 加路径 | | YOLO 换更大模型 | `utils/models.py` 加新 `ModelSpec`,`demos/d07_dnn_yolo.py::run()` 调 `ensure_model(your_spec)` | | 控制台 Python 版本偏好 | `setup.bat` 第 9-37 行的 `py -3.X --version` 顺序 | | 安装源换镜像 | `setup.bat::pip install` 那行加 `-i https://pypi.tuna.tsinghua.edu.cn/simple` | ### 3.8 常见启动失败排查表 | 现象 | 看哪里 | 解决 | |---|---|---| | 双击 start.bat 闪一下就关了 | `start.bat` 末尾加 `pause` 看错误 | 多半是 venv 缺失 → 跑 setup.bat | | 终端打印中文像 `锟斤拷` | `chcp` 没切到 65001 | 用我们提供的 .bat(已内置);不要直接 `python main.py` | | `[ERROR] 摄像头打不开` | 摄像头被占用 | 关掉微信视频/钉钉/相机 App;或换 index:`open_camera(index=1)` | | Demo 启动后窗口黑屏 | DSHOW 预热不够 | 调大 `open_camera(warmup_frames=10)` | | Demo 07 卡在下模型 | GitHub 慢 | Ctrl+C 停掉,手工下到 `data/models/`(链接见下方 Q4) | | Demo 08 报 `cv2.face 不存在` | contrib 没装上 | `.venv\Scripts\pip.exe install opencv-contrib-python` | | 中文显示成方块 | `_FONT_CANDIDATES_WIN` 里的字体都不存在 | 编辑 `utils/overlay.py` 加你机器上的字体路径 | --- ## 四、命令行使用 ```bash # 进入 venv(Windows) .venv\Scripts\activate # 显示菜单 python main.py # 直接跑某个 demo python main.py 1 # 编号 python main.py face # 关键字 python main.py recog # LBPH 人脸识别 # 列出所有 demo python main.py --list ``` 每个 demo 模块也可以独立跑: ```bash python -m demos.d01_face_eye_smile python -m demos.d07_dnn_yolo ``` --- ## 五、目录结构 ``` opencv_train_demo/ ├── main.py # 菜单 launcher ├── requirements.txt ├── setup.bat / start.bat # 一键脚本 ├── README.md ├── utils/ │ ├── camera.py # 跨平台 / 重试 / DSHOW │ ├── overlay.py # FPS / 中文文字 / 提示条 │ └── models.py # DNN 模型自动下载 ├── demos/ │ ├── d01_face_eye_smile.py │ ├── d02_motion_detect.py │ ├── d03_color_tracker.py │ ├── d04_shape_detect.py │ ├── d05_qr_detect.py │ ├── d06_feature_match.py │ ├── d07_dnn_yolo.py # 联网(首次下模型) │ ├── d08_face_recognize.py │ ├── d09_hand_skin.py │ └── d10_doc_scan.py └── data/ # 运行时生成 ├── models/ # YOLOv4-tiny 等 DNN 权重 ├── faces/ # LBPH 录入的人脸样本 └── snapshots/ # 用户按 S 保存的截图 ``` --- ## 六、各 demo 操作说明 | Demo | 通用键 | 专用键 | |---|---|---| | 全部 | **Q / ESC** 退出 | | | 01 face | | **S** 截图 | | 02 motion | | **R** 重置背景, **+/-** 调最小目标面积 | | 03 color | | **1-5** 切色:红/绿/蓝/黄/橘 + TrackBar 微调 | | 04 shape | | **E** 切边缘视图, **+/-** 调 Canny 阈值 | | 05 qr | (无) | | | 06 match | | **C** 用画面中心当模板, **L** 加载默认棋盘模板 | | 07 yolo | | **+/-** 调置信度 | | 08 recog | | **E** 多姿势录入(5 姿势 × 15 帧 = 75 帧/人)
**T** 重新训练(不录入,只重训)
**D** 清空数据 + 模型
**TrackBar** 实时调阈值(越小越严格) | | 09 hand | | **+/-** 调最小面积 | | 10 scan | | **S** 保存矫正后文档(彩色 + 黑白 双份) | | 11 train | (无 GUI,命令行报告) | 自动跑 LBPH/Eigen/Fisher 三算法对比 + 找最佳阈值 | | 12 dnn | | **E** 录入(先眨眼活体 → 5 姿势)
**T** 重建 embedding 库
**D** 清空库(保留 png 样本)
**TrackBar** 调相似度阈值 × 100(默认 40 = 0.40) | --- ## 六.1 人脸识别准确度提升完整流程(Demo 08 + Demo 11) > 单独把这一章拎出来,因为"录人脸 → 识别"看着简单,但要做到**真用得上**需要一整套训练流水线。 ### 当前实现(v2 增强版) | 维度 | v1(之前) | v2(现在) | |---|---|---| | 单人样本量 | 30 张 | **5 姿势 × 15 张 = 75 张原始 → 6× 增强 = 450 张训练样本** | | 姿态多样性 | 用户随便晃 | **引导式**:正脸 / 转左 / 转右 / 抬头 / 低头 | | 光照鲁棒性 | 单环境 | augment 自动模拟 ±30 亮度变化 | | 几何鲁棒性 | 仅原始 | augment 加 ±6° 旋转 + 水平翻转 | | 算法 | LBPH 唯一 | **三选一**:LBPH / Eigen / Fisher | | 阈值 | 硬编码 75 | TrackBar 实时调;Demo 11 自动找最优 | | 模型持久化 | ❌ 每次启动重训 | ✅ `data/faces/_model/lbph.yml` 启动自动加载 | | 准确度量化 | ❌ 没有 | ✅ Demo 11 输出准确率 / P/R / 混淆矩阵 | | Top-K 候选 | ❌ 只显示最佳 | ✅ Demo 08 实时显示 Top-3(看模型对比强度)| ### 标准训练流程(推荐做法) ``` Step 1. 录入数据(Demo 08) - 进 Demo 08,按 E - 输入名字 → 跟着屏幕提示完成 5 个姿势采集 - 每人耗时约 30-45 秒 - 录至少 2 个人物(评估需要 ≥ 2 类) Step 2. 训练 + 评估(Demo 11) python main.py train - 加载 data/faces/* 全部样本(带 6× 增强) - 80/20 分层划分(每人都参与训练 + 测试) - 训 LBPH/Eigen/Fisher 三种,打印对比表 - 自动扫描最佳阈值并保存模型 Step 3. 实时识别(回 Demo 08) python main.py recog - 自动加载 Demo 11 训练好的最优模型 + 最优阈值 - 头顶看到名字 + 距离值(越小越像) - 下方看到 Top-3 候选 Step 4. 准确度不够? - 录更多人 → 训练数据多样性 ↑ - 用 TrackBar 调阈值找适合你环境的值 - 录入时光照尽量贴近实际使用场景 - 极端情况下:清空 (D) 后重头来一遍 ``` ### Demo 11 输出样例 ``` === LBPH 评估报告 === 总样本: 90, 正确: 87, 准确率: 96.67% 各人 P/R: name TP FP FN Prec Rec alice 45 1 1 97.83% 97.83% bob 42 2 2 95.45% 95.45% 混淆矩阵 (行=真, 列=预测): alice bob alice 45 1 bob 2 42 最佳阈值: 65.0 (acc 97.8%) 训练耗时: 240ms 评估耗时: 30ms [step 4] 算法对比 =========================================== 算法 准确率 最佳阈值 阈值后 训练 LBPH 96.7% 65.0 97.8% 240ms Eigen 91.1% 8200.0 93.3% 1230ms Fisher 94.4% 4500.0 95.6% 890ms [step 5] 最佳算法: LBPH(acc 97.8% @ threshold=65) ``` ### 三种算法的特性对比 | 算法 | 原理 | 优势 | 劣势 | 推荐场景 | |---|---|---|---|---| | **LBPH** | 局部二值模式直方图 | 对光照变化最稳;增量训练快 | 对大角度旋转敏感 | **首选**,95%+ 场景够用 | | **Eigen** | PCA 主成分分析 | 训练后识别快 | 对光照敏感;阈值数量级很大(~8000)| 光照可控的环境 | | **Fisher** | LDA 线性判别 | 类间区分度高 | 需要每类样本均衡 | 多人识别且每人样本充足 | Demo 11 训练时全跑一遍,自动选最准的那个保存。 ### 数据文件位置 ``` data/faces/ ├── alice/ # 用户录入的原始样本 │ ├── front_xxxxx_0.png │ ├── left_xxxxx_5.png │ ├── right_xxxxx_10.png │ └── ... ├── bob/ │ └── ... └── _model/ # Demo 11 训练保存的模型(自动加载) ├── lbph.yml ├── eigen.yml ├── fisher.yml └── label_map.json # {label_id: name, threshold, ...} ``` 清空:`Demo 08 按 D` 或 `rm -rf data/faces/`。 ### 进一步提升(未来工作) 如果当前精度仍不够: 1. **换 DNN embedding** —— 用 OpenCV 自带的 `face_recognizer_sf`(SFace 模型)或 `face_detector_yn` + ArcFace 嵌入。准确度跳一个台阶(97% → 99.5%+),但需要下模型。 2. **加人脸对齐** —— 用 5 点关键点把眼睛拉到水平线再训练。可消除头部倾斜带来的方差。 3. **换更鲁棒的检测器** —— `cv2.dnn` + Caffe MobileNet 人脸检测器替换 Haar,对侧脸/遮挡更宽容。 这三步本仓库未做(保持纯经典 CV + LBPH 套件的简洁)。需要我加吗?告诉我哪一项就行。 --- ## 六.2 DNN 升级路径(Demo 12) > 在 Demo 08(LBPH)之上把整套流水线换成深度学习实现,**算法骨架等价于阿里云人脸识别 API 的核心 1:1 验证逻辑**。 ### Demo 12 vs Demo 08 | 步骤 | Demo 08 (LBPH) | Demo 12 (DNN) | |---|---|---| | 检测 | Haar 级联(2001) | **YuNet ONNX**(2023,1MB),同时给 5 关键点 | | 对齐 | 仅 resize 到 200×200 灰度 | **5pt 仿射变换 → ArcFace 模板 112×112 BGR** | | 特征 | LBP 直方图(手工) | **SFace 128 维 embedding**(CNN 学到的语义身份) | | 距离 | Chi-squared 距离 | **余弦相似度**(已 L2 归一化) | | 阈值 | 75(距离,越小越像) | 0.40(相似度,越大越像) | | 训练数据 | 你录的 75 张 | OpenCV-Zoo 已在 ~5M 张人脸预训练 | | 活体检测 | ❌ | ✅ 眨眼引导(双眼亮度 dip) | | LFW 准确率 | ~92% | ~99.6% | ### 4 步合并到 Demo 12 ``` Step 1️⃣ YuNet DNN 检测器 → 检测同时给 5 关键点(后面 3 步全靠它) Step 2️⃣ 5 关键点对齐 → 仿射到 ArcFace 标准模板,眼睛拉直 Step 3️⃣ SFace 128 维 embedding → 余弦相似度比较 Step 4️⃣ 眨眼活体(录入时引导) → 防静态照片攻击 ``` ### 推荐工作流 ```bash # 1. 录数据(含眨眼活体引导) python main.py dnn # 按 E → 输入名字 → 先眨眼 2 次(活体)→ 5 个姿势采集 # data/faces//{front,left,right,up,down}_*.png # LBPH 用 # data/faces//{...}_aligned.png # SFace 用(已对齐 112x112) # 2. 库会自动构建并保存 # data/faces/_dnn_db.npz (numpy 压缩包,128 维 embedding) # 3. 实时识别 — 看到的是 cosine 相似度(0.0-1.0) # 头顶绿色 cos=0.85 = 相当肯定是这个人 # 头顶橙色 cos=0.32 = 陌生人 # 4. 想跟 LBPH 跑对比?同样的 png 数据两边都能用 python main.py train # Demo 11 跑 LBPH 评估 python main.py recog # Demo 08 跑 LBPH 实时识别 python main.py dnn # Demo 12 跑 SFace 实时识别 # 两套数字摆一起对比 ``` ### Demo 12 技术细节 | 组件 | 文件 | 关键 API | |---|---|---| | 检测 + 关键点 | `utils/face_dnn.py::detect_faces` | `cv2.FaceDetectorYN` | | 5 点对齐 | `utils/face_dnn.py::align_face` | `cv2.estimateAffinePartial2D` | | Embedding | `utils/face_dnn.py::extract_embedding` | `cv2.FaceRecognizerSF.feature` | | 1:N 搜索 | `utils/face_dnn.py::FaceDB` | `numpy` 暴力遍历(< 10万人够用) | | 眨眼活体 | `utils/face_dnn.py::BlinkCounter` | 双眼亮度 dip 检测 | ### 阈值经验值 SFace 余弦相似度的官方推荐阈值 0.363。本 demo 默认 0.40(更严)。**实际使用建议**: 1. 录完数据后,Demo 12 → 自己照镜子 → 看 cos 多少 → 设阈值 = 该值的 0.85 倍 2. 一般 0.35-0.55 都合理,光照差时可降到 0.30 ### 模型来源 + 大小 | 模型 | 大小 | 来源 | 用途 | |---|---|---|---| | `face_detection_yunet_2023mar.onnx` | ~1MB | [opencv_zoo](https://github.com/opencv/opencv_zoo) | YuNet 检测器 | | `face_recognition_sface_2021dec.onnx` | ~37MB | [opencv_zoo](https://github.com/opencv/opencv_zoo) | SFace 识别器 | 首次运行 Demo 12 自动从 GitHub 下载到 `data/models/`。 ### 为什么不用更大的 ArcFace ResNet-100? OpenCV 的 SFace(来自[原论文](https://ieeexplore.ieee.org/document/9318547))是为移动端/CPU 优化的轻量版,准确率 ~99.6%(LFW),比 ArcFace ResNet-100 的 ~99.83% 略低,但模型小 6 倍、CPU 上快 5 倍。**本仓库目标是 demo + 教学**,足够。 要冲到 99.83%+:换 [insightface](https://github.com/deepinsight/insightface) 仓库的 ResNet-100 ArcFace(~250MB),配合 GPU。 --- ## 七、技术栈对照表 | | 经典 CV | 深度学习 (DNN) | |---|---|---| | **找物体** | 06 ORB 特征匹配 | 07 YOLO | | **找人脸** | 01 Haar 检测 | (需要更复杂的 DNN,本套件未包含)| | **认人脸** | 08 LBPH/Eigen/Fisher + 11 训练评估器 | **12 SFace embedding(已包含!)+ 5pt 对齐 + 眨眼活体** | | **找手** | 09 肤色 + 凸缺陷 | (MediaPipe/手部关键点,未包含)| | **找文字** | 10 文档扫描 + 透视矫正 | (需 EasyOCR/PaddleOCR)| > 想看深度学习的 OCR / Pose / Segmentation?告诉我,我可以补上 EasyOCR / MediaPipe 集成版本。 --- ## 八、常见问题 ### Q1:摄像头打不开 - 检查是否被微信视频 / 钉钉 / 相机 App 占用 - Windows 隐私设置 → 相机 → 允许桌面应用访问 - 多个摄像头时改 `utils/camera.py::open_camera(index=1)` ### Q2:OpenCV 安装失败 - Python 3.14 暂时没有 opencv-python 轮子,setup.bat 会自动选 3.12 - 如果网络慢,改用清华源: ``` pip install -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt ``` ### Q3:人脸识别(Demo 08)报错 "cv2.face 不存在" - 缺 `opencv-contrib-python`:`pip install opencv-contrib-python` ### Q4:YOLO(Demo 07)下载模型失败 - 检查能否访问 GitHub(需要联网) - 可手工下载放到 `data/models/`: - `yolov4-tiny.weights` (https://github.com/AlexeyAB/darknet/releases/download/yolov4/yolov4-tiny.weights) - `yolov4-tiny.cfg` (https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov4-tiny.cfg) - `coco.names` (https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names) ### Q5:中文显示成方块 - `utils/overlay.py` 用 PIL + 微软雅黑/黑体渲染中文。 - 如果你机器上找不到字体,会降级到 `[zh]` 占位。可以在 `_FONT_CANDIDATES_WIN` 里加路径。 --- ## 九、扩展方向 想加什么 demo 都可以,参考 `demos/d01_face_eye_smile.py` 模板: ```python def run() -> None: cap = open_camera() fps = FpsMeter() try: while True: ok, frame = read_frame(cap) if not ok: break # ... 你的识别逻辑 ... fps.tick() fps.overlay(frame) frame = draw_hint_bar(frame, "Q 退出 ...") cv2.imshow("My Demo", frame) if cv2.waitKey(1) & 0xFF in (ord("q"), 27): break finally: cap.release() cv2.destroyAllWindows() ``` 然后在 `main.py::DEMOS` 里加一行即可。