摘要
本章区分人脸检测(定位人脸位置) 与**人脸识别(判断人脸身份)**两大核心环节。OpenCV 传统人脸识别提供 3 套算法:EigenFace(特征脸)、FisherFace、LBPH(局部二值模式直方图)。
一. 人脸检测: Haar 级联预训练 XML 分类器
人脸检测 ≠ 人脸识别。 人脸检测只定位图像中人脸所在坐标,输出人脸矩形框,无法判断这个人是谁。
1.1 预训练 XML 分类器介绍
OpenCV 官方提供大量已训练完成的 Haar / LBP 预训练分类器,以 .xml 文件格式保存,内部存储大量人脸正负样本训练得到的特征模板。常用人脸相关 XML 文件:
- haarcascade_frontalface_default.xml:Haar 特征,正面人脸检测器,最常用。
- haarcascade_frontalface_alt.xml:优化版正面人脸检测器。
- lbpcascade_frontalface.xml:LBP 人脸检测器,速度更快。
- lbpcascade_animeface.xml:动漫人脸检测器(网络寻找)
**文件获取方式:**方式一:OpenCV 源码包 data 目录自带这些 XML 文件;

方式二:OpenCV 官方 GitHub 仓库下载;
方式三:网络开源资源下载。

1.2 detectMultiScale 接口与参数详解
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| python faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml") faces = faceCascade.detectMultiScale(gray, scaleFactor, minNeighbors, minSize, maxSize) |
|--------------|----------------------------------------------------------------|
| 参数 | 说明 |
| image | 输入图像,必须为灰度单通道图像。 |
| scaleFactor | 图像金字塔缩放系数,多尺度扫描图片时每次窗口的缩放比例。常用 1.05 或 1.1;数值越大检测速度越快,但更容易漏检人脸。 |
| minNeighbors | 候选框邻居阈值,重叠候选框数量大于等于该值才判定为人脸。数值越大误检越少,但容易漏检,常用取值 3--9。 |
| minSize | 人脸最小像素尺寸,小于该尺寸的目标直接过滤,可过滤微小噪声干扰。 |
| maxSize | 人脸最大像素尺寸,大于该尺寸的目标直接过滤;不需要时可省略。 |
返回值 faces : 数组,每一组 (x, y, w, h) 代表一张人脸:x、y 为人脸矩形左上角坐标,w 为人脸框宽度,h 为人脸框高度。
1.3 人脸检测完整代码
python
import cv2
# 读取图像
image = cv2.imread("moreface.png")
# Haar 检测器要求输入灰度图
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 加载官方预训练正面人脸 xml 分类器(相对路径,xml 放在项目目录)
faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
# 多尺度人脸检测
faces = faceCascade.detectMultiScale(gray, scaleFactor=1.05, minNeighbors=9, minSize=(8, 38))
print(f"检测到 {len(faces)} 张人脸")
print(f"人脸位置信息(x,y,w,h):{faces}")
# 绘制人脸矩形框
for (x, y, w, h) in faces:
cv2.rectangle(image, (x, y), (x + w, y + h), (0, 255, 0), 2)
cv2.imshow("face_detect", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
二. 传统人脸识别总览
人脸检测拿到人脸区域之后,裁剪人脸 ROI,送入人脸识别模型完成身份判断。
2.1 三大传统人脸识别算法对比
|----------------|-------------------|-----------------|---------------|-----------|----------------|
| 算法 | 核心原理 | 图像约束 | 优点 | 缺点 | 适用场景 |
| EigenFace(特征脸) | PCA 主成分分析,全局像素降维 | 训练集图片必须统一宽高、灰度图 | 计算速度快,原理简单 | 对光照变化非常敏感 | 光照稳定的室内场景 |
| FisherFace | LDA 线性判别分析,拉大类别间距 | 训练集图片必须统一宽高、灰度图 | 小样本分类效果较好 | 对光照敏感 | 样本数量较少的分类任务 |
| LBPH | 局部二值模式直方图,提取纹理特征 | 无强制尺寸要求 | 抗光照、表情变化,鲁棒性强 | 运算速度略慢 | 普通非受控环境,工程优先选用 |
2.2 统一执行流程
- 准备人脸样本,转为灰度图像。
- 构造人脸图片列表 images 与标签列表 labels,同一个人分配同一个数字标签。
- 创建识别器对象。
- 调用 recognizer.train(images, np.array(labels)) 执行训练。
- 调用 label, confidence = recognizer.predict(test_gray_img) 执行预测。
返回值说明:
- label:预测输出的数字标签。
- confidence:代表距离,不是概率,数值越小代表匹配相似度越高。EigenFace 置信度范围 0--20000,一般小于 5000 认为匹配可靠;LBPH 置信度一般小于 80 认为匹配可靠。不同算法置信度范围不能直接对比。
三. EigenFace 特征脸实战
原理:PCA 主成分分析,将高维人脸像素映射到低维特征脸子空间,计算距离完成匹配。训练集、预测图片尺寸必须完全一致。
python
import cv2
import numpy as np
# 构建训练人脸样本
images = []
a = cv2.imread("zhaoliyin1.png", cv2.IMREAD_GRAYSCALE)
a = cv2.resize(a, (120, 180))
b = cv2.imread("zhaoliyin2.png", cv2.IMREAD_GRAYSCALE)
b = cv2.resize(b, (120, 180))
c = cv2.imread("yangmi1.png", cv2.IMREAD_GRAYSCALE)
c = cv2.resize(c, (120, 180))
d = cv2.imread("yangmi2.png", cv2.IMREAD_GRAYSCALE)
d = cv2.resize(d, (120, 180))
images.append(a)
images.append(b)
images.append(c)
images.append(d)
labels = [0, 0, 1, 1]
name_dict = {0: "zhaoliyin", 1: "yangmi", -1: "unknown"}
# 待预测图片,尺寸与训练样本保持一致
predict_image = cv2.imread("zhaoliyin3.png", cv2.IMREAD_GRAYSCALE)
predict_image = cv2.resize(predict_image, (120, 180))
# 创建 EigenFace 识别器并训练
recognizer = cv2.face.EigenFaceRecognizer_create()
recognizer.train(images, np.array(labels))
# 执行预测
label, confidence = recognizer.predict(predict_image)
print("识别结果:", name_dict[label])
print(f"置信度(距离): {confidence:.2f}")
# 在原图绘制识别文字
src_show = cv2.imread("zhaoliyin3.png").copy()
cv2.putText(src_show, name_dict[label], (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
cv2.imshow("eigen_result", src_show)
cv2.waitKey(0)
cv2.destroyAllWindows()
四. LBPH 局部二值模式直方图实战
LBPH(Local Binary Patterns Histograms)提取人脸局部纹理特征,抗光照、表情干扰,不需要强制统一图片尺寸,是传统人脸识别工程优先选择。
python
import cv2
import numpy as np
images = []
images.append(cv2.imread("zhaoliyin1.png", cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread("zhaoliyin2.png", cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread("yangmi1.png", cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread("yangmi2.png", cv2.IMREAD_GRAYSCALE))
labels = [0, 0, 1, 1]
name_dict = {0: "zhaoliyin", 1: "yangmi", -1: "unknown"}
predict_image = cv2.imread("zhaoliyin3.png", cv2.IMREAD_GRAYSCALE)
# 创建 LBPH 识别器,训练模型
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.train(images, np.array(labels))
# 预测
label, confidence = recognizer.predict(predict_image)
print("识别结果:", name_dict[label])
print(f"置信度(距离): {confidence:.2f}")
五. 常见问题总结
- XML 分类器读取失败:检查文件路径,博客与项目开发建议使用相对路径,XML 文件放置项目根目录。
- EigenFace / FisherFace:训练样本、预测样本图片尺寸必须完全一致,只能输入灰度图像,否则运行报错;LBPH 无强制尺寸约束。
- confidence 不是概率:它代表特征空间距离,数值越小相似度越高,不同算法置信阈值不能互相混用。
- Haar 检测器容易误检人脸:调大 minNeighbors、设置合理 minSize 过滤噪声。
- 传统人脸识别短板:对侧脸、强光照、人脸遮挡识别效果差;现代项目大多采用深度学习人脸识别方案。
六. 本章小结
- Haar 预训练 XML 分类器实现人脸检测,只输出人脸位置框,不能识别人的身份;XML 文件使用相对路径更适合博客与项目迁移。
- EigenFace、FisherFace 基于全局像素降维,对光照敏感,要求样本尺寸统一;LBPH 提取局部纹理,鲁棒性更好,工程优先选用。
- 业务标准流程:先检测人脸,裁剪人脸区域,再做人脸识别。
- confidence 是距离度量,数值越小匹配度越高,不同算法阈值不通用。