当业务需要实现"摄像头画面里到底出现了谁"这一能力时,最常见的技术方案并不是一上来就上深度学习,而是一套轻量级的 OpenCV 人脸识别流程。本文将基于 Python + OpenCV 搭建一个完整的人脸识别系统:先用 Haar Cascade 定位画面中的人脸,再用 LBPH 算法训练每个参与人员的人脸特征模型,最后通过摄像头实时回答"你都看到了谁?"。无论你是计算机视觉初学者,还是准备在本地落地一个访客识别 Demo,这篇文章都可以作为一份可直接照做的实战笔记。
1. 先搞清楚:你要做的到底是"检测"还是"识别"?
"你都看到了谁?"这句话听起来像一句玩笑,但它恰好对应着两个容易混淆的计算机视觉问题。第一层问题是"画面里有没有人脸",第二层问题是"这张脸到底是谁"。前者叫"人脸检测",后者叫"人脸识别"。在动手写代码之前,一定先把这两件事分开。
1.1 人脸检测与人脸识别的区别
人脸检测的任务是在一张图片或一帧视频画面中找出所有人脸的位置,通常用矩形框来表示。它不需要知道这个人是谁,只需要回答"哪里有脸"。人脸识别则要更进一步,它会把检测到的人脸区域提取出来,再和已知的人脸库做特征比对,最终给出一句"这个人是 Alice"或"这个人是 Bob"。
在工程实现上,二者通常是串联关系:识别系统先做检测,定位人脸区域,然后把该区域交给分类模型或特征比对模型去判断身份。很多入门文章把这两个概念混在一起讲,导致读者写出了画框代码,却不知道如何输出身份信息。当你听到"你都看到了谁"这个需求时,第一件事就是先拆开这两个阶段,后面的代码结构才会清晰。
1.2 为什么选择 OpenCV + Haar Cascade + LBPH
OpenCV(Open Source Computer Vision Library)是一套成熟的开源计算机视觉库,提供了大量图像处理和机器学习算法。本方案中的人脸检测使用 OpenCV 自带的 Haar Cascade 分类器。这是一种基于 Haar 特征的级联分类器,优点是体积小、速度快,在普通 CPU 上就能实时运行,非常适合入门 Demo 和轻量级边缘设备。
人脸识别部分采用 Local Binary Patterns Histograms,中文通常翻译为"局部二值模式直方图",简称 LBPH。它是 OpenCV 中的经典人脸识别算法,不需要 GPU,训练数据需求量也比深度学习方法小很多,非常适合初学者理解人脸识别的完整流程。这套组合的缺点是识别精度不如 FaceNet、ArcFace 等深度学习方法,但作为"从 0 到 1 跑通流程"的教程来说,它能很好地帮你建立全链路认知:样本采集、特征训练、模型保存、实时推理。搞懂这些基础以后,再迁移到深度学习方案会轻松得多。
1.3 常见应用场景
这种轻量级方案常被用于办公室访客登记时识别"来的人是谁"、家庭摄像头里的常见人物标注、学校课程签到 Demo,以及各类智能硬件的人脸唤醒演示。生产环境如果要做门禁、考勤、支付等敏感场景,还需要配合活体检测、权限系统和加密存储,这部分会在后面的章节专门提醒。
2. 环境准备与项目结构
正式开始前,先把环境准备好。本教程以 Python + OpenCV 为例,代码在 Windows、macOS、Linux 上都可以运行,只要本机摄像头驱动正常即可。
2.1 安装 Python 与 OpenCV
建议使用 Python 3.8 及以上版本。由于代码中需要用到cv2.face模块,必须安装opencv-contrib-python,而不是普通的opencv-python。这两个包不能同时存在,否则 import 时可能会出现问题。推荐在虚拟环境中操作:
python -m venv .venv # Windows .venv\Scripts\activate # macOS / Linux source .venv/bin/activate pip install opencv-contrib-python安装后可以验证环境是否正常:
import cv2 print(cv2.__version__) print(cv2.face)如果最后一行能打印出类似<module 'cv2.face' ...>的信息,说明扩展模块安装成功;如果报错AttributeError: module 'cv2' has no attribute 'face',说明当前安装的是 opencv-python,需要先卸载再安装 opencv-contrib-python。如果你的下载速度比较慢,可以在 pip 命令后面加上镜像源参数,例如pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-contrib-python,只需要把安装地址切换为可用的 pip 镜像即可。
2.2 准备摄像头与样本人脸
采集样本需要一台可用的摄像头,笔记本自带摄像头或 USB 外接摄像头都可以。训练数据要尽量覆盖不同的光线、角度和表情,每个人建议采集 20 到 30 张正脸图片。如果只有一个人做演示,可以给自己拍 20 多张;如果想识别多人,就为每个人建立一个独立的样本文件夹。本教程以识别 Alice 和 Bob 两个人作为示例,实际人数可以根据需要调整。
2.3 项目目录结构
完整的项目结构如下:
face-recognizer/ ├── capture_samples.py # 采集人脸样本脚本 ├── train_model.py # 训练 LBPH 模型 ├── recognize_camera.py # 实时识别脚本 ├── data/ │ └── raw/ │ ├── alice/ # 第一个人的人脸样本 │ └── bob/ # 第二个人的人脸样本 └── models/ ├── lbph_model.yml # 训练后的人脸模型 └── label_map.json # 姓名与标签编号映射这个目录结构把采集、训练、识别三个流程彻底分开,逻辑清晰,后续扩展也方便。
3. 采集训练样本:让程序先"见"一遍每个人
机器并不认识"张三"或者"李四",它只能通过大量样本去学习这些面孔的纹理分布。所以第一步是收集人脸样本,这一步做得越规范,后面模型的效果就越好。
3.1 设计样本目录
每个参与人员的样本单独放在一个以姓名命名的子目录下。这里强烈建议使用英文或拼音命名,比如alice、bob、zhangsan,不要使用中文目录名。原因是 OpenCV 的imread函数在部分操作系统中不能很好地处理中文路径,一旦读取失败,训练样本就会为空,后面运行脚本会直接报错。
每个子目录下放若干张规格统一的人脸灰度图。手动裁剪没有必要,采集脚本会自动检测人脸区域,并统一缩放到200 x 200像素。统一尺寸是为了让每条训练样本进入模型时的特征维度一致,这也是 LBPH 训练过程的基本要求。
3.2 编写人脸采集脚本
在项目根目录创建capture_samples.py,代码如下。该脚本会打开摄像头,自动检测人脸并画框,按下s保存当前画面中面积最大的人脸,按下q退出:
# capture_samples.py import os import sys import cv2 face_cascade = cv2.CascadeClassifier( cv2.data.haarcascades + "haarcascade_frontalface_default.xml" ) user_name = input("请输入当前拍摄者的名字(拼音/英文,避免中文路径):") save_dir = os.path.join("data", "raw", user_name) os.makedirs(save_dir, exist_ok=True) cap = cv2.VideoCapture(0) if not cap.isOpened(): print("摄像头打开失败,请检查设备权限。") sys.exit(1) count = 0 while True: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale( gray, scaleFactor=1.1, minNeighbors=5, minSize=(60, 60) ) for (x, y, w, h) in faces: cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) cv2.imshow("Capture Samples: s save, q quit", frame) key = cv2.waitKey(1) & 0xFF if key == ord("s") and len(faces) > 0: # 只保存画面中面积最大的人脸,避免误保存多个小框 max_face = max(faces, key=lambda rect: rect[2] * rect[3]) x, y, w, h = max_face face_roi = gray[y:y + h, x:x + w] face_roi = cv2.resize(face_roi, (200, 200)) count += 1 filename = f"{user_name}_{count:03d}.jpg" filepath = os.path.join(save_dir, filename) cv2.imwrite(filepath, face_roi) print(f"已保存第 {count} 张样本:{filepath}") elif key == ord("q"): break cap.release() cv2.destroyAllWindows()这段代码把灰度转换、人脸检测、图像保存三个环节串起来了。detectMultiScale里的scaleFactor控制检测窗口的缩放比例,minNeighbors控制每个候选区域至少要被多少个邻近窗口命中才保留,minSize表示最小人脸尺寸。这些参数不是固定值,需要根据你的摄像头分辨率和人脸距离适当调整。
3.3 运行采集脚本
python capture_samples.py脚本运行后,参与采集的人需要正对摄像头,尽量让脸部处于绿色框内,然后每隔几秒按一次s。每拍 5 张就稍微转动一下头部或换一个表情,样本多样性会直接决定 LBPH 模型的鲁棒性。采集多人时,重复运行脚本,输入不同的姓名即可。如果画面里始终没有绿色检测框,可以先检查光线是否充足,再尝试调小minSize到(40, 40),或者调大scaleFactor。
需要再次强调:每一位参与训练的人都必须知情并同意被采集人脸样本。做本教程演示时,尽量只用自己的照片,或者使用公开的、允许用于实验的人脸数据集。不要未经许可抓拍同事、路人的脸部图片。
4. 训练 LBPH 模型:生成"认人"的特征模型
当样本图像准备完成以后,就可以进入训练环节。LBPH 会把每张人脸图像划分成若干小区域,在每个区域上计算局部二值模式直方图,再把所有区域的特征拼接起来,形成一张人脸的特征描述。训练过程就是把每个人的多张人脸特征和对应标签一起交给 OpenCV,最终得到一个可复用的人脸模型文件。
4.1 训练脚本核心逻辑
训练脚本的核心逻辑可以拆成四步:第一步,遍历data/raw目录下的每个子目录,子目录名就是人的姓名;第二步,为每个姓名分配一个从 0 开始的整数标签,同时保存姓名到标签的映射关系;第三步,用灰度图读取样本,统一缩放到200 x 200像素,放入图像列表和标签列表;第四步,调用cv2.face.LBPHFaceRecognizer_create()创建识别器,执行train()训练,并保存模型文件和标签映射文件。
这里的关键点是:图像列表必须全部是灰度图,而且尺寸要一致。很多人训练报错,就是因为读取的图片尺寸不一致,或者把 BGR 彩色图直接传给了train()。另一个容易忽略的点是标签必须是整数,不能直接把姓名字符串传给模型。
4.2 完整训练代码
在项目根目录创建train_model.py:
# train_model.py import json from pathlib import Path import cv2 import numpy as np raw_dir = Path("data/raw") model_dir = Path("models") model_dir.mkdir(exist_ok=True) label_map = {} images = [] labels = [] next_label = 0 for person_dir in raw_dir.iterdir(): if not person_dir.is_dir(): continue person_name = person_dir.name if person_name not in label_map: label_map[person_name] = next_label next_label += 1 for img_path in person_dir.glob("*.jpg"): img = cv2.imread(str(img_path), cv2.IMREAD_GRAYSCALE) if img is None: print(f"跳过无法读取的图片:{img_path}") continue img = cv2.resize(img, (200, 200)) images.append(img) labels.append(label_map[person_name]) if len(images) == 0: raise SystemExit("没有找到任何训练样本,请先运行采集脚本。") recognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.train(images, np.array(labels)) model_path = model_dir / "lbph_model.yml" recognizer.save(str(model_path)) with open(model_dir / "label_map.json", "w", encoding="utf-8") as f: json.dump(label_map, f, ensure_ascii=False, indent=2) print(f"训练完成,共使用 {len(images)} 张人脸样本。") print(f"模型已保存到:{model_path}") print(f"标签映射:{label_map}")这段代码中,Path.iterdir()用于遍历目录,person_dir.glob("*.jpg")用于读取该目录下所有 jpg 图片。np.array(labels)把 Python 列表转换成 NumPy 数组,因为 OpenCV 的train()接口接受这种格式。训练完成后,lbph_model.yml就是之后识别阶段要加载的模型文件,label_map.json则记录姓名和标签编号的对应关系。
4.3 预期输出
如果样本准备正常,运行python train_model.py后,终端会出现类似信息:
训练完成,共使用 45 张人脸样本。 模型已保存到:models/lbph_model.yml 标签映射:{'alice': 0, 'bob': 1}看到这个输出,说明模型训练成功。需要留意的是,LBPH 训练对样本数量很敏感,如果每个人只有三五张图片,模型几乎没有区分能力。如果训练数据特别少,程序可能抛出error: (-210) Unsupported format or combination of formats之类的异常,这时应该回到采集阶段补充样本,而不是继续调整模型参数。
5. 实时识别:在摄像头画面里回答"你都看到了谁?"
模型训练完成之后,就可以编写实时识别脚本。这个脚本会把检测和识别串联起来:每帧图像先转灰度,再做人脸检测,最后对每个人脸区域调用predict(),得到标签和置信度。
5.1 置信度与身份判定
LBPH 的predict()会返回两个值:label和confidence。label是识别器认为最接近的标签,confidence表示当前人脸和模型库中对应样本之间的距离。按照算法定义,数值越小表示匹配度越高。不同的 OpenCV 版本、不同的数据分布下,置信度的绝对范围会有差异,但通常可以采用下面这个主观参考:
| confidence 取值 | 含义 | 建议处理 |
|---|---|---|
| 0 - 50 | 匹配度较高 | 显示对应姓名 |
| 50 - 80 | 有一定相似度 | 显示姓名并标注置信度,或继续观察 |
| 大于 80 | 匹配度低 | 显示陌生人 |
这个阈值并不是绝对标准。你需要在自己的数据集上反复测试,把已知人脸和陌生人脸分别送进模型,观察置信度分布,再确定一个最适合自己业务的阈值。把阈值写死成 70 只能用于演示,不能直接作为生产判断依据。
5.2 实时识别完整代码
在项目根目录创建recognize_camera.py:
# recognize_camera.py import json import cv2 face_cascade = cv2.CascadeClassifier( cv2.data.haarcascades + "haarcascade_frontalface_default.xml" ) recognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.read("models/lbph_model.yml") with open("models/label_map.json", "r", encoding="utf-8") as f: label_map = json.load(f) reverse_label_map = {v: k for k, v in label_map.items()} confidence_threshold = 70 cap = cv2.VideoCapture(0) if not cap.isOpened(): print("摄像头打开失败,请检查设备权限。") exit(1) while True: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale( gray, scaleFactor=1.1, minNeighbors=5, minSize=(60, 60) ) for (x, y, w, h) in faces: face_roi = gray[y:y + h, x:x + w] face_roi = cv2.resize(face_roi, (200, 200)) label, confidence = recognizer.predict(face_roi) name = reverse_label_map.get(label, "Unknown") if confidence > confidence_threshold: name = "Stranger" cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2) text = f"{name} {confidence:.1f}" cv2.putText( frame, text, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2, ) cv2.imshow("Who do you see? - press q to quit", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()这段代码中,reverse_label_map用于把模型输出的整数标签转换回姓名。confidence_threshold控制陌生人判定:当置信度超过这个值时,即使模型返回了一个已知标签,也会显示为Stranger。识别框上方同时显示姓名和置信度,便于你调试阈值。注意,OpenCV 的putText不支持直接绘制中文,因此这份代码里的姓名建议保持为拼音或英文。
5.3 运行与验证
执行:
python recognize_camera.py摄像头画面打开后,把训练过的脸放到镜头前,识别框上方会显示姓名和置信度。再拿一张没有训练过的人脸照片放到镜头前,如果置信度超过阈值,程序会显示Stranger。
如果你发现自己的脸一直被识别成陌生人,可以先打印confidence值,观察已知人脸和陌生人脸在置信度上的差异,然后调整阈值。如果打印出的置信度普遍在 80 以上,说明训练样本太少、光线变化太大,或者模型已经失效,需要重新采集样本训练。整个过程应当按"采集 -> 训练 -> 测试 -> 调参"循环进行,直到识别结果稳定。
6. 识别效果优化与安全边界
Demo 跑通之后,你可能会发现真实场景里的识别率并没有想象中稳定。这里面有算法本身的局限,也有工程因素,更涉及敏感数据的合规使用。
6.1 影响识别效果的常见因素
第一个因素是光线。同一张脸在强光、逆光、夜晚昏暗环境下的纹理特征差异很大。LBPH 虽然对光照变化有一定鲁棒性,但极端光照仍然会导致特征漂移。第二个因素是角度和遮挡。Haar Cascade 对正面人脸检测效果最好,侧脸、低头、口罩、帽子都会显著降低检测成功率。识别模型如果训练的全是正脸样本,自然也无法应对侧脸场景。第三个因素是样本质量。如果训练样本全部来自同一个角度、同一种表情,模型会过度拟合这个固定状态,当用户换一个表情或戴上眼镜时,置信度就会剧烈波动。
因此,在采集阶段就要刻意增加变化:左右转动头部、上下轻微抬头、做出不同表情、戴上或不戴眼镜、开灯或关灯轮流拍摄。样本多样性永远是轻量级模型稳定性的最有效保障。对于光线变化剧烈的室外环境,还可以在预处理阶段做直方图均衡化,也就是把灰度图的对比度拉伸得更均匀,这通常能改善 LBPH 的表现。
6.2 不要忽略活体检测
视频画面中的人脸不等于真实的人。打印照片、手机屏幕、平板电脑里的人脸都能被摄像头拍到,而且可能被当前这套流程误判为"合法用户"。如果只是本地学习 Demo,这个问题可以不处理;但如果要做门禁、考勤、支付等敏感场景,必须额外集成活体检测,比如要求用户完成眨眼、张嘴、摇头等动作,或者使用红外深度摄像头判断人脸是否为真实立体结构。
活体检测是一个独立的工程模块,不能靠调高 LBPH 阈值来解决。任何公开的人脸识别教程,在接入生产系统之前都应该强调这一点。本文提供的是学习演示方案,不是生产级认证系统。
6.3 数据隐私与合规底线
人脸属于生物识别信息,具有非常强的个人属性。采集样本前必须获得对方明确授权,说明数据用途、保存周期、是否可以删除。不要为了测试识别效果随意收集同事、路人、陌生人的照片。项目代码和原始数据不要直接放进公开仓库,除非已经完成脱敏和授权处理。
工程实践中,建议将原始人脸样本加密存储,模型文件同样作为敏感资产管理,操作日志要记录采集、训练、删除等关键动作。本文示例中的模型和图片仅用于本机功能验证,不应直接照搬到未经评估的线上环境。
7. 常见问题与排查思路
下面是这套项目最常遇到的问题,我按阶段整理成三个表格,方便你快速定位。
7.1 安装依赖阶段
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
AttributeError: module 'cv2' has no attribute 'face' | 安装的是 opencv-python,不是 opencv-contrib-python | 卸载 opencv-python,重新安装 opencv-contrib-python |
| 安装包体积大、下载慢 | 网络原因导致下载缓慢 | 配置可用的 pip 镜像源后重试 |
| 导入 cv2 时崩溃 | OpenCV 版本与 Python 版本不兼容 | 检查 Python 版本,尝试升级或降级 OpenCV |
安装依赖时最好在虚拟环境中执行,避免污染全局 Python 环境。如果已经安装了多个 OpenCV 变体,可以通过pip list | findstr opencv(Windows)或pip list | grep opencv(macOS/Linux)查看当前环境中的包。
7.2 人脸检测阶段
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| 检测不到人脸 | 光线不足、人脸太小或离镜头太远 | 保证清晰正脸入镜,适当降低minSize到(40, 40) |
| 画面中出现大量误检框 | minNeighbors设置偏小 | 调大minNeighbors到 6 或 7 |
| 侧面或低头时人脸漏检 | Haar Cascade 对非正面人脸效果有限 | 调整角度重新入镜,或改用 OpenCV DNN 人脸检测器 |
| 摄像头打不开 | 系统权限未授权或设备编号错误 | 检查摄像头权限,尝试VideoCapture(1) |
在排查检测问题之前,建议先写一个三行脚本单独读取一帧并显示,确认摄像头采集链路是否正常。这样可以快速区分问题是出在设备层,还是出在算法层。
7.3 模型训练与识别阶段
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
train()报错样本为空 | 图片读取失败或目录结构错误 | 确认data/raw下存在子目录,且子目录内有.jpg图片 |
| 预测结果一直相同 | 训练样本太少或类别不均衡 | 增加每个人的样本量,并保证不同人的样本数量接近 |
| 自己的脸被识别为陌生人 | 阈值设置不合理 | 打印confidence值,观察已知人脸和陌生人脸的分界 |
| 不同人的脸互相误判 | 样本区分度不足或样本中有串脸 | 检查样本是否混入其他人的照片,必要时重新采集 |
需要特别提醒,识别模型的输出受阈值影响非常大。建议写一个简单的统计脚本,分别读取若干张已知人脸和陌生人脸,依次调用predict(),打印所有置信度,再用分位数确定阈值,而不是直接拍脑袋填一个数字。
8. 最佳实践与工程建议
如果你想把这套流程进一步落地成一个小系统,下面的建议可以帮你少走很多弯路。
8.1 样本采集规范
每人至少采集 20 到 30 张人脸,训练集要覆盖不同光线、角度和表情。采集时优先使用摄像头实时拍摄,不要使用身份证照片、社交平台头像等静态图片,因为这些图片的分辨率和拍摄条件与摄像头实时画面差异较大。模型输入尺寸统一为200 x 200的灰度图,并且采集、训练、识别三个阶段必须保持一致,任何一处不一致都会导致识别结果不稳定。
如果系统要逐步加入新用户,不需要每次都重新训练完整模型。可以在原模型基础上调用recognizer.update(new_images, new_labels)做增量更新,但前提是你还保留着旧的模型文件。这个功能适合小规模动态名单,生产系统更推荐用数据库保存特征向量和用户信息,而不是依赖单个模型文件。
8.2 阈值调优与模型评估
不要一上来就把置信度阈值写死。正确做法是准备一个独立的测试集,里面包含已知人员样本和陌生人样本,分别统计模型输出的置信度均值和方差,再选择一个能让误拒绝率和误接受率平衡的阈值。如果业务更看重安全,阈值就可以调低,让陌生人判断更严格;如果业务更看重操作便利性,可以适当放宽阈值。
LBPH 毕竟是轻量级算法,在人群规模变大以后性能会明显下降。一般建议这个方案只用于几十人以内的小型场景。如果人员数量成百上千,应当切换到基于深度学习特征嵌入的人脸识别方案,例如使用预训练模型提取人脸特征向量,再用向量检索库做身份匹配。
8.3 生产环境的架构建议
即使模型训练和识别脚本完全正确,也不能直接把脚本原封不动地部署到生产环境。生产系统至少要考虑四个方面:第一,摄像头采集与识别服务是否应该解耦,如果采用一边读摄像头一边推理的同步写法,一旦识别耗时波动,画面就会出现明显卡顿;第二,模型文件和原始人脸样本必须做权限控制,放到独立目录或对象存储中,并开启访问审计;第三,识别结果要与时间、摄像头编号、事件 ID 等元数据关联,方便事后追溯;第四,对外提供服务时要走统一鉴权和接口封装,不要把 OpenCV 推理逻辑直接暴露给上层调用者。
这些内容虽然更偏后端工程,但人脸识别从来不只是算法问题。它与数据管理、权限边界、系统可靠性强相关,先把本地流程跑通,再逐步工程化,是比较稳妥的路线。
9. 总结与下一步学习路线
9.1 核心收获
通过这篇文章,你应该已经走完了人脸识别的基础闭环:理解了人脸检测与人脸识别的区别,安装了opencv-contrib-python,完成了样本采集、LBPH 模型训练、摄像头实时识别,也清楚了置信度阈值调整和常见排错方法。这个项目虽然不大,但它覆盖了从数据准备到模型部署的完整链路,可以作为你学习计算机视觉的第一个可演示作品。
9.2 进阶方向
下一步可以按三个方向继续深入。第一,把 Haar Cascade 替换为 OpenCV DNN 的人脸检测模型,它能明显提高侧脸、遮挡和暗光场景下的检测率。第二,用深度学习模型替换 LBPH,例如基于人脸特征向量的预训练模型,配合向量检索库做大规模人脸搜索。第三,为当前系统加入活体检测和权限管理,使它从"实验室 Demo"变成"可评估的产品原型"。无论选择哪个方向,都建议先在一个小数据集上建立评估指标,再逐步扩展,而不是一开始就追求大而全的架构。
9.3 动手建议
如果你准备在本地复现,可以先完整跑一遍本文的三段脚本,然后调整采集脚本中的scaleFactor和minNeighbors,观察这两个参数对人脸检测结果的影响。这个实验本身也是对 OpenCV 图像处理流程很好的理解方式。等你把检测调稳了,再去做阈值统计和模型评估,识别准确率会更容易控制。