OpenCV 实现人脸识别全流程:从人脸检测到 LBPH/Eigen/Fisher 三种算法实战

一、前言

人脸识别是计算机视觉领域的经典应用,在考勤、门禁、身份验证等场景中被广泛使用。OpenCV 作为计算机视觉领域的开源利器,提供了完整的人脸识别解决方案,从人脸检测 定位人脸区域,到三种经典人脸识别算法(LBPH、EigenFaces、FisherFaces)实现身份识别。

二、核心原理:人脸检测 vs 人脸识别

很多新手会混淆这两个概念,先明确核心区别:

  • 人脸检测 :判断图像中是否有人脸,并定位人脸的位置(框出人脸区域),是人脸识别的前置步骤。
  • 人脸识别 :在检测到人脸后,判断这张脸是谁,属于身份识别任务。

2.1 人脸检测:Haar 级联分类器原理

OpenCV 中最经典的人脸检测方案是Haar 级联分类器,核心原理如下:

  1. Haar 特征提取:通过边缘、线、中心环绕等矩形特征,计算白色区域与黑色区域的像素差,反映图像的灰度变化(比如人脸的眼睛区域比脸颊暗,符合 Haar 特征的灰度差特性)。
  2. 级联分类器结构:将多个简单弱分类器按顺序级联,前序分类器快速过滤大量负样本(非人脸),仅通过所有分类器的区域才判定为人脸,大幅提升检测效率。
  3. OpenCV 实现:OpenCV 提供了预训练好的 Haar 级联分类器 XML 文件,直接加载即可实现人脸检测,无需从零训练。

2.2 人脸识别:OpenCV 三大经典算法

OpenCV 提供了三种成熟的人脸识别算法,核心原理对比如下:

|-----------------------|-----------------------------------|--------------------------|-------------------|
| 算法 | 核心原理 | 核心优势 | 适用场景 |
| LBPH(局部二值模式直方图) | 基于 LBP 纹理特征,分区域统计直方图,对比直方图相似度识别 | 抗光照、缩放、旋转、平移,对图像尺寸无强制要求 | 通用场景,新手首选,实战效果最稳定 |
| EigenFaces(特征脸) | 基于 PCA 主成分分析,将人脸图像降维为特征向量,对比特征相似度 | 计算简单,适合小样本训练 | 光照均匀、姿态固定的场景 |
| FisherFaces(Fisher 脸) | 基于 LDA 线性判别分析,最大化类间差异、最小化类内差异 | 分类效果优于 EigenFaces,抗干扰性更强 | 多类别人脸识别,对精度要求高的场景 |

三、项目实战:三种算法完整实现

3.1 算法 1:LBPH 人脸识别

LBPH 是三种算法中最稳定、最适合实战的方案,核心步骤:

  1. 加载训练集,统一灰度读取
  2. 创建 LBPH 识别器,设置阈值(默认 80,置信度 < 80 判定为匹配)
  3. 训练模型,对测试集进行预测
  4. 输出识别结果与置信度

完整代码

python 复制代码
import cv2
import numpy as np

# ===================== 1. 加载训练样本 =====================
images = []
# 灰度读取训练人脸图片
images.append(cv2.imread('hg01.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('hg02.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('pyy01.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('pyy02.jpg', cv2.IMREAD_GRAYSCALE))

# 标签:0=胡歌,1=彭于晏
labels = [0, 0, 1, 1]
# 结果映射字典
name_dict = {0: '胡歌', 1: '彭于晏', -1: '无法识别'}

# ===================== 2. 加载待识别图片 =====================
predict_image = cv2.imread('hg.jpg', cv2.IMREAD_GRAYSCALE)

# ===================== 3. 创建LBPH识别器并训练 =====================
# threshold=80:置信度阈值,>80判定为无法识别
recognizer = cv2.face.LBPHFaceRecognizer_create(threshold=80)
# 训练模型
recognizer.train(images, np.array(labels))

# ===================== 4. 预测识别 =====================
label, confidence = recognizer.predict(predict_image)

# ===================== 5. 输出结果 =====================
print('识别结果:', name_dict[label])
print('置信度(越小越匹配):', round(confidence, 2))

# ===================== 6. 图片标注(可选) =====================
result_img = cv2.imread('hg.jpg').copy()
cv2.putText(
    result_img,
    f"{name_dict[label]} (置信度: {round(confidence, 1)})",
    (10, 30),
    cv2.FONT_HERSHEY_SIMPLEX,
    0.9,
    (0, 0, 255),
    2
)
cv2.imshow('LBPH人脸识别结果', result_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码说明
  • LBPH 算法无需统一训练集图片尺寸,这是它相比另外两种算法的最大优势
  • 阈值threshold=80为经验值,可根据实际效果微调:阈值越低,识别越严格,越容易出现 "无法识别";阈值越高,越容易误识别
  • 置信度confidence越小,代表匹配度越高,LBPH 中通常 < 80 为有效识别

3.2 算法 2:EigenFaces 人脸识别

EigenFaces 基于 PCA 降维,核心要求训练集与测试集图片尺寸必须完全一致,否则会报错。

完整代码

python 复制代码
import cv2
import numpy as np

# ===================== 1. 加载训练样本(必须统一尺寸) =====================
images = []
# 统一缩放到120x180尺寸
a = cv2.imread('hg01.jpg', 0)
a = cv2.resize(a, (120, 180))
b = cv2.imread('hg02.jpg', 0)
b = cv2.resize(b, (120, 180))
c = cv2.imread('pyy01.jpg', 0)
c = cv2.resize(c, (120, 180))
d = cv2.imread('pyy02.jpg', 0)
d = cv2.resize(d, (120, 180))

images.append(a)
images.append(b)
images.append(c)
images.append(d)

# 标签:0=胡歌,1=彭于晏
labels = [0, 0, 1, 1]
name_dict = {0: '胡歌', 1: '彭于晏', -1: '无法识别'}

# ===================== 2. 加载待识别图片(必须和训练集尺寸一致) =====================
pre_image = cv2.imread('hg.jpg', 0)
pre_image = cv2.resize(pre_image, (120, 180))

# ===================== 3. 创建EigenFaces识别器并训练 =====================
# threshold=5000:置信度阈值,<5000判定为匹配
recognizer = cv2.face.EigenFaceRecognizer_create(threshold=5000)
recognizer.train(images, np.array(labels))

# ===================== 4. 预测识别 =====================
label, confidence = recognizer.predict(pre_image)

# ===================== 5. 输出结果 =====================
print('识别结果:', name_dict[label])
print('置信度(越小越匹配):', round(confidence, 2))

# ===================== 6. 图片标注 =====================
result_img = cv2.imread('hg.jpg').copy()
cv2.putText(
    result_img,
    name_dict[label],
    (10, 30),
    cv2.FONT_HERSHEY_SIMPLEX,
    0.9,
    (0, 0, 255),
    2
)
cv2.imshow('EigenFaces人脸识别结果', result_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码说明
  • EigenFaces 对光照、姿态敏感,仅适合训练集与测试集环境一致的场景
  • 必须严格统一所有图片尺寸,否则train()方法会直接报错
  • 阈值threshold=5000为经验值,EigenFaces 置信度范围通常为 0~20000,<5000 为有效识别

3.3 算法 3:FisherFaces 人脸识别

FisherFaces 基于 LDA 线性判别分析,分类效果优于 EigenFaces,同时解决了 PCA 丢失关键分类信息的问题。本版本新增中文标注功能 ,解决 OpenCVputText无法显示中文的问题。

完整代码

python 复制代码
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont

# ===================== 工具函数:OpenCV添加中文 =====================
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):
    """
    向OpenCV图像中添加中文文本
    :param img: 输入图像
    :param text: 要添加的中文文本
    :param position: 文本位置 (x, y)
    :param textColor: 文本颜色 (B, G, R)
    :param textSize: 文本大小
    :return: 添加中文后的图像
    """
    if isinstance(img, np.ndarray):
        # OpenCV格式转PIL格式
        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        draw = ImageDraw.Draw(img)
        # 加载宋体字体(需确保simsun.ttc文件在当前目录)
        fontStyle = ImageFont.truetype("simsun.ttc", textSize, encoding="utf-8")
        # 绘制文本
        draw.text(position, text, textColor, font=fontStyle)
        # PIL格式转回OpenCV格式
        return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)

# ===================== 工具函数:统一尺寸加载图像 =====================
def load_resize_image(image_path, size=(120, 180)):
    img = cv2.imread(image_path, flags=0)
    return cv2.resize(img, dsize=size)

# ===================== 1. 加载训练样本 =====================
images = []
images.append(load_resize_image('hg01.jpg'))
images.append(load_resize_image('hg02.jpg'))
images.append(load_resize_image('pyy01.jpg'))
images.append(load_resize_image('pyy02.jpg'))

# 标签:0=胡歌,1=彭于晏
labels = [0, 0, 1, 1]
name_dict = {0: '胡歌', 1: '彭于晏', -1: '无法识别'}

# ===================== 2. 加载待识别图片 =====================
pre_image = load_resize_image('hg.jpg')

# ===================== 3. 创建FisherFaces识别器并训练 =====================
recognizer = cv2.face.FisherFaceRecognizer_create(threshold=5000)
recognizer.train(images, np.array(labels))

# ===================== 4. 预测识别 =====================
label, confidence = recognizer.predict(pre_image)

# ===================== 5. 输出结果 =====================
print('识别结果:', name_dict[label])
print('置信度(越小越匹配):', round(confidence, 2))

# ===================== 6. 中文标注并显示 =====================
# 读取原图,添加中文标注
original_img = cv2.imread('hg.jpg').copy()
result_img = cv2AddChineseText(
    original_img,
    f"{name_dict[label]} (置信度: {round(confidence, 1)})",
    position=(30, 10),
    textColor=(255, 0, 0),  # 红色
    textSize=30
)

cv2.imshow('FisherFaces人脸识别结果(中文标注)', result_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
代码说明
  • FisherFaces 同样要求统一图片尺寸,分类精度高于 EigenFaces,适合多类别识别
  • 中文标注函数通过 PIL 实现,解决了 OpenCV 原生不支持中文的痛点,需提前准备simsun.ttc字体文件
  • 封装了图像加载函数,简化代码结构,提升可维护性

四、三种算法对比与选型建议

4.1 核心差异对比

|------|----------------|---------------|------------------|
| 特性 | LBPH | EigenFaces | FisherFaces |
| 核心原理 | LBP 纹理特征 + 直方图 | PCA 主成分分析 | LDA 线性判别分析 |
| 尺寸要求 | 无需统一 | 必须统一 | 必须统一 |
| 抗干扰性 | 强(抗光照、旋转、缩放) | 弱(对光照 / 姿态敏感) | 中(优于 EigenFaces) |
| 训练速度 | 快 | 快 | 中等 |
| 识别精度 | 高 | 低 | 高 |
| 适用场景 | 通用场景 | 实验室固定环境 | 多类别高精度识别 |

相关推荐
落羽的落羽2 小时前
【Linux系统】入门线程:线程介绍与线程控制
linux·服务器·c++·人工智能·stm32·单片机·机器学习
u86882 小时前
Maixin AICC智能呼叫中心:以AI语音助力新能源车企优质客服
人工智能·大模型电话对接·ai语音智能体
CS创新实验室2 小时前
AI时代社会与职业变迁系统综述
人工智能·百度
翼龙云_cloud2 小时前
阿里云代理商:OpenClaw 技能安全部署指南与高口碑扩展精选
人工智能·安全·云计算·openclaw
oh LAN2 小时前
主流 AI 编码工具对比表(2026 最新)
人工智能·编辑器·工具·代码
这张生成的图像能检测吗2 小时前
(论文速读)嵌入式GPU上的实时多目标视觉追踪
人工智能·深度学习·目标检测·目标跟踪·iot边缘设备
悟乙己2 小时前
能够替代 Claude Code 的本地大语言模型选项推荐
人工智能·语言模型·自然语言处理
知兀2 小时前
【ai agent?ai工具】prompt/context/harness ;mcp;skills;个人使用skills
人工智能