基于 OpenCV 的 FisherFaceRecognizer 人脸识别与中文标签显示实践
基于 OpenCV 的 FisherFaceRecognizer 人脸识别与中文标签显示实践
在人脸识别的世界里,特征提取与分类器设计是核心环节。OpenCV 提供了多种经典的人脸识别方法,其中 EigenFaceRecognizer(基于主成分分析 PCA)和 FisherFaceRecognizer(基于线性判别分析 LDA)是两种经典的算法,适用于小样本、灰度人脸的学习和分类。本篇文章将从原理讲解、代码拆解、参数说明到实际运行效果,全方位介绍如何使用 OpenCV 的 FisherFaceRecognizer 进行人脸识别,并且在预测结果上支持中文显示。
一、FisherFaceRecognizer 原理概述
1.1 PCA vs. LDA
在人脸识别中,常用的降维方法有 PCA 和 LDA。
PCA(主成分分析):通过寻找数据最大方差方向,将高维人脸数据投影到低维空间,保留主要信息,降低噪声和冗余。缺点是它只考虑方差,不关注类别信息。
LDA(线性判别分析):与 PCA 不同,LDA 不仅考虑数据分布,还考虑类别可分性。它试图找到一个投影方向,使得同类样本的投影尽可能接近,而不同类样本的投影尽可能远,从而提升分类性能。
1.2 FisherFace 的优势
FisherFace 是 PCA + LDA 的组合:
先用 PCA 将高维人脸降到一个较低维度,避免协方差矩阵奇异。
再用 LDA 进行判别投影,最大化类间方差,最小化类内方差。
它比单独使用 PCA 更适合做分类任务,尤其是在光照、表情变化较多的情况下,鲁棒性更好。
二、代码逐行拆解
下面我们逐行解析这段代码,理解每一步的功能。
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
cv2:OpenCV 的 Python 接口,提供图像处理、人脸识别等功能。
numpy:用于矩阵运算,OpenCV 图像本质上是 NumPy 数组。
PIL:用于支持中文绘制,OpenCV 的
cv2.putText()
不能直接显示中文。
2.1 添加中文函数
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):if (isinstance(img, np.ndarray)):img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))draw = ImageDraw.Draw(img)fontStyle = ImageFont.truetype("simsun.ttc", textSize, encoding="utf-8")draw.text(position, text, textColor, font=fontStyle)return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
将 OpenCV 图像转成 PIL 图像。
使用
ImageFont.truetype()
加载宋体(simsun.ttc
),支持中文。绘制完文本后再转换回 OpenCV 格式,便于后续显示。
注意:simsun.ttc
字体需要存在于系统中,否则会报错,可以替换成其他中文字体路径。
2.2 训练图像加载
images = []
def image_re(image):a = cv2.imread(image, flags=0)# a = cv2.resize(a, dsize=(120, 180))images.append(a)image_re('face1.jpg')
image_re('face2.jpg')
image_re('face4.jpg')
image_re('face5.jpg')
使用
cv2.imread(..., flags=0)
以灰度模式读取人脸图像,简化计算。如果训练图像尺寸不一致,需要先
cv2.resize()
,否则训练器会报错。所有图像存入
images
列表,作为训练数据。
2.3 标签定义
labels = [0, 0, 1, 1]
这里定义了四张人脸图像的类别标签:
0 表示第一类人(例如刘亦菲)
1 表示第二类人(例如胡歌)
这样,训练器才能学习“同一类”人脸的共同特征。
2.4 预测图像准备
pre_image = cv2.imread('face1.jpg')
pre_image_copy = np.copy(pre_image)
pre_image = cv2.cvtColor(pre_image, cv2.COLOR_BGR2GRAY)
读取待识别人脸。
pre_image_copy
用于保留彩色版本,后续在上面绘制中文。转灰度后送入识别器。
2.5 创建 FisherFaceRecognizer
recognizer = cv2.face.FisherFaceRecognizer_create(threshold=5000)
参数说明:
threshold=5000
:阈值,表示如果识别到的最近距离超过此值,则返回-1
(无法识别)。可调节该值以控制识别的严格程度。
2.6 模型训练
recognizer.train(images, np.array(labels))
训练过程:
images
是训练图像的列表。labels
是每张图像的类别标签。训练完成后,模型会生成特征向量和分类决策边界。
2.7 预测与输出
label, confidence = recognizer.predict(pre_image)
dic = {0: '刘亦菲', 1: '胡歌', -1: '无法识别'}
print('这人是:', dic[label])
print('置信度为:', confidence)
predict()
返回两个值:label
:预测的类别编号。confidence
:置信度,越低表示越接近训练数据。
用字典
dic
把数字标签映射成中文名字,提升可读性。
2.8 显示识别结果
image = cv2AddChineseText(pre_image_copy, dic[label], position=(30, 10), textColor=(255, 0, 0))
cv2.imshow('xx', image)
cv2.waitKey(0)
调用我们写的中文显示函数,将结果写到图像上。
最后用 OpenCV 窗口显示。
三、关键参数与调试技巧
图像尺寸统一
FisherFaceRecognizer 要求所有输入图像尺寸一致。推荐使用cv2.resize()
对训练图像和预测图像统一到同一大小,例如120x180
。阈值调整
threshold
越低,越严格,可能导致误拒绝。threshold
越高,越宽松,可能导致误识别。
建议先打印多张图片的confidence
,找到合适的分界值。
训练样本数量
LDA 需要至少每类 2 张以上样本才能工作,否则会报错。建议每类收集 5~10 张不同表情、光照的图片。中文显示兼容性
Windows 可以直接使用simsun.ttc
,Linux 需要安装中文字体并指定路径。
四、实验结果与分析
在实际运行中,若训练集为同一人多张照片,预测图像为训练集中某一张:
预测
label
应该正确返回该人的编号。confidence
一般小于 1000,说明高度匹配。
如果换一张完全陌生的人脸:
预测结果可能是
-1
(阈值生效),提示“无法识别”。如果置信度仍然很低,说明阈值需要调高。
五、应用场景与扩展
小规模人脸识别:适用于考勤机、门禁、桌面应用等小型项目。
身份验证:在用户数量不多时,FisherFaceRecognizer 能提供较快的训练速度和较好的识别效果。
教学与研究:非常适合初学者学习 LDA 和人脸识别算法的原理。
扩展方向:
换用 LBPHFaceRecognizer,它对光照更鲁棒。
引入人脸检测(如
cv2.CascadeClassifier
)自动截取人脸区域。用深度学习替代 FisherFace,例如 OpenCV DNN 模块或 FaceNet。
六、总结
本文通过完整的代码示例,展示了如何:
使用 OpenCV 加载人脸图像并统一尺寸。
用 FisherFaceRecognizer 进行训练和预测。
利用 PIL 在 OpenCV 图像上显示中文名字。
调整阈值与训练样本来提升识别准确率。
FisherFaceRecognizer 是一种经典的人脸识别方法,虽然已经被深度学习替代,但在学习阶段和小型项目中仍然有价值。通过本文的解析,你不仅能理解代码,还能掌握调试思路和改进方向,为后续的人脸识别研究打下坚实基础。