一、前言
继昨天学习了人脸检测(Haar级联分类器)之后,今天进一步深入人脸识别领域。与"检测"不同,"识别"是要判断这个人是谁,而不是仅仅找到人脸的位置。
OpenCV的face模块提供了三种经典的人脸识别算法:
- LBPH(局部二值模式直方图)
- EigenFace(特征脸)
- FisherFace(费舍尔脸)
本文将逐一解析这三个算法的使用方法和核心区别,并附上完整可运行的代码。
二、环境准备
bash
pip install opencv-python opencv-contrib-python numpy pillow
注意 :
cv2.face模块在opencv-contrib-python中,需要单独安装。
数据集准备
本文示例使用4张训练图片:
hg0.jpg、hg1.jpg→ 胡歌(标签0)pyy0.jpg、pyy1.jpg→ 彭于晏(标签1)- 待识别图片:
hg.jpg(胡歌的另一张照片)
三、算法一:LBPH(局部二值模式直方图)
核心原理
LBPH将图像分成若干小区域,对每个区域计算局部二值模式(LBP)直方图,然后串联成特征向量。对光照变化有较强的鲁棒性,是目前实际应用中较常用的方法。
完整代码
python
import cv2
import numpy as np
# 准备训练数据(灰度图)
images = []
images.append(cv2.imread('hg0.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('hg1.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('pyy0.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('pyy1.jpg', cv2.IMREAD_GRAYSCALE))
labels = [0, 0, 1, 1]
dic = {0: 'hg', 1: 'pyy', -1: '无法识别'}
# 待识别图片
predict_image = cv2.imread('hg.jpg', cv2.IMREAD_GRAYSCALE)
# 创建LBPH识别器(阈值80)
recognizer = cv2.face.LBPHFaceRecognizer_create(threshold=80)
# 训练
recognizer.train(images, np.array(labels))
# 预测
label, confidence = recognizer.predict(predict_image)
print("这人是:", dic[label])
print('置信度:', confidence)
关键参数说明
| 参数 | 说明 |
|---|---|
| threshold=80 | 置信度阈值,低于阈值认为匹配成功,否则返回-1 |
| confidence | 数值越小表示匹配度越高(0为完美匹配) |
运行结果
text
这人是: hg
置信度: 0.0
四、算法二:EigenFace(特征脸)
核心原理
EigenFace基于主成分分析(PCA),将高维人脸图像降维到低维"特征空间",通过比较投影后的特征向量进行识别。需要所有训练图像尺寸一致。
完整代码
python
import cv2
import numpy as np
images = []
# 统一尺寸为 120x180
a = cv2.imread('hg0.jpg', 0)
a = cv2.resize(a, (120, 180))
b = cv2.imread('hg1.jpg', 0)
b = cv2.resize(b, (120, 180))
c = cv2.imread('pyy0.jpg', 0)
c = cv2.resize(c, (120, 180))
d = cv2.imread('pyy1.jpg', 0)
d = cv2.resize(d, (120, 180))
images.extend([a, b, c, d])
labels = [0, 0, 1, 1]
pre_image = cv2.imread('hg.jpg', 0)
pre_image = cv2.resize(pre_image, (120, 180))
# 创建EigenFace识别器
recognizer = cv2.face.EigenFaceRecognizer_create()
recognizer.train(images, np.array(labels))
# confidence范围:0~20000,低于5000认为可靠
label, confidence = recognizer.predict(pre_image)
dic = {0: 'hg', 1: 'pyy', -1: '-1'}
print('这人是:', dic[label])
print('置信度为:', confidence)
# 在图片上标注
aa = cv2.putText(cv2.imread('hg.jpg'), dic[label], (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)
cv2.imshow('xx', aa)
cv2.waitKey(0)
关键参数说明
| 参数 | 说明 |
|---|---|
| confidence | 范围 0~20000,低于5000 认为结果可靠 |
| 尺寸要求 | 所有训练图片和待识别图片必须完全一致 |
五、算法三:FisherFace(费舍尔脸)
核心原理
FisherFace基于线性判别分析(LDA),不仅考虑降维,还考虑类间差异最大化、类内差异最小化,因此识别率通常高于EigenFace,尤其适合光照变化较大的场景。
完整代码
python
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
# 在图片上添加中文文字
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)
# 读取并统一尺寸
def image_re(image):
a = cv2.imread(image, 0)
a = cv2.resize(a, (120, 180))
images.append(a)
images = []
image_re('hg0.jpg')
image_re('hg1.jpg')
image_re('pyy0.jpg')
image_re('pyy1.jpg')
labels = [0, 0, 1, 1]
pre_image = cv2.imread('hg.jpg', 0)
pre_image = cv2.resize(pre_image, (120, 180))
# 创建FisherFace识别器(阈值5000)
recognizer = cv2.face.FisherFaceRecognizer_create(threshold=5000)
recognizer.train(images, np.array(labels))
label, confidence = recognizer.predict(pre_image)
dic = {0: '胡歌', 1: '彭于晏', -1: '无法识别'}
print('这人是:', dic[label])
print('置信度为:', confidence)
# 在图片上添加中文标注
image = cv2AddChineseText(cv2.imread('hg.jpg').copy(), dic[label], (30, 10),
textColor=(255, 0, 0))
cv2.imshow('xx', image)
cv2.waitKey(0)
关键参数说明
| 参数 | 说明 |
|---|---|
| threshold=5000 | 置信度阈值,高于阈值返回-1(无法识别) |
| confidence | 越小匹配度越高,阈值需根据实际数据调整 |
中文显示技巧
使用 PIL 绘制中文文字,因为OpenCV的putText默认不支持中文。
六、三大算法对比总结
| 对比维度 | LBPH | EigenFace | FisherFace |
|---|---|---|---|
| 核心原理 | 局部二值模式 + 直方图 | PCA主成分分析 | LDA线性判别分析 |
| 训练速度 | 较快 | 快 | 中等 |
| 识别速度 | 快 | 快 | 快 |
| 阈值可调 | (threshold) | (固定判断标准) | (threshold) |
| 尺寸要求 | 无需统一 | 必须统一 | 必须统一 |
| 置信度意义 | 越小越好 | 越小越好 | 越小越好 |
| 适用场景 | 实际项目首选 | 学术研究/入门 | 光照变化较大场景 |
置信度范围参考
| 算法 | 置信度范围 | 可靠阈值 |
|---|---|---|
| LBPH | 0 ~ 理论无穷大 | < 80(可调) |
| EigenFace | 0 ~ 20000+ | < 5000 |
| FisherFace | 0 ~ 理论无穷大 | < 5000(可调) |
七、常见问题与解决方案
1. AttributeError: module 'cv2' has no attribute 'face'
原因 :未安装 opencv-contrib-python
解决:
bash
pip install opencv-contrib-python
2. 所有图片尺寸不一致报错(EigenFace/FisherFace)
解决 :统一使用 cv2.resize() 调整尺寸
python
img = cv2.imread('hg0.jpg', 0)
img = cv2.resize(img, (120, 180))
3. 阈值设置不当导致识别失败
- LBPH:阈值过低会拒识,过高会误识,建议从 80 开始调试
- FisherFace:阈值从 5000 开始调试
4. 训练样本太少导致识别率低
每种人物至少准备 2~5 张不同角度/表情的照片。