03_LBPH人脸识别算法原理与实战

OpenCV 之人脸识别:LBPH 算法原理与完整代码实现


摘要 :本文详细讲解 OpenCV 中 LBPH(局部二值模式直方图)人脸识别算法的原理与完整实现。首先介绍 LBP 特征的计算原理(基本算子与圆形扩展),接着说明如何从 LBP 特征图划分单元格、统计直方图并拼接成特征向量,然后梳理训练与识别两个阶段的核心流程。文章给出可直接运行的环境安装命令与完整 Python 代码,并对 LBPHFaceRecognizer_createtrainpredict 等关键 API 逐一详解,最后总结提高准确率的实用技巧与 LBPH 的优缺点,适合人脸识别入门读者参考。

前言

前两篇我们学习了人脸检测 ------也就是在图像中找到人脸的位置。从本篇开始,我们进入更高级的人脸识别领域:不仅要找到人脸在哪里,还要判断出「这个人是谁」。

OpenCV 提供了三种经典的人脸识别算法:

  • LBPH(Local Binary Patterns Histograms,局部二值模式直方图)
  • EigenFace(特征脸,基于 PCA)
  • FisherFace(基于 LDA)

三种算法各有特点,其中 LBPH 是最容易理解、对光照变化最不敏感的一种,非常适合作为人脸识别的入门算法。

本篇我们就来详细讲解 LBPH 的原理,并给出完整的训练和识别代码。


一、什么是 LBPH

LBPH 全称 Local Binary Patterns Histograms ,中文叫「局部二值模式直方图」。它的核心思想是:用局部纹理特征来描述人脸

每个人的脸部纹理都是独一无二的------皱纹分布、毛孔排列、皮肤纹理......这些微观特征组合起来,就是一个人的「面部指纹」。LBPH 就是通过提取这些局部纹理信息,再统计成直方图,作为人脸的特征向量。

LBPH 的优势:

  • 对光照变化不敏感:因为它比较的是相邻像素的相对大小,而不是绝对亮度
  • 原理简单,容易理解:没有复杂的数学推导
  • 单张图片也能训练:不需要大量样本

二、LBP 特征计算原理

2.1 基本 LBP 算子

LBP 的计算非常直观,对每个像素点,我们做以下操作:

  1. 以该像素为中心,取周围 8 个邻居像素(3×3 邻域)
  2. 把周围像素和中心像素比较:
    • 如果周围像素 ≥ 中心像素,标记为 1
    • 如果周围像素 < 中心像素,标记为 0
  3. 从某个位置开始(通常是正上方顺时针),把这 8 个 0/1 值连成一个 8 位二进制数
  4. 把这个二进制数转换成十进制,就是该像素的 LBP 值

举个例子:

复制代码
邻域像素(3×3):
  10   20   30
  40   25   60      中心像素 = 25
  70   80   90

逐个比较(≥25 记为 1,<25 记为 0):
  0    0    1
  1    .    1
  1    1    1

从正上方顺时针排列:0 1 1 1 1 1 1 0
二进制 01111110 = 十进制 126
所以中心像素的 LBP 值 = 126

就这样,一张灰度图经过 LBP 运算后,变成了一张「LBP 特征图」,每个像素的值是 0~255 之间的整数,代表了该位置的局部纹理模式。

2.2 圆形 LBP(扩展版)

基本 LBP 用的是 3×3 的正方形邻域,但后来研究者提出了圆形 LBP------在一个圆上均匀采样多个点,这样可以控制半径和采样点数,灵活性更高。

OpenCV 中 LBPH 使用的就是圆形 LBP:

  • radius:圆形邻域的半径
  • neighbors:圆上采样点的数量,通常是 8 个

半径越大,捕捉的纹理范围越大;采样点越多,描述越精细。但计算量也会随之增加。默认参数通常效果就不错。


三、从 LBP 图到 LBPH 直方图

光有 LBP 特征图还不够------两张相同人脸的图片,人脸位置可能略有不同,直接逐像素比较肯定不准。

怎么办?答案是划分区域 + 统计直方图

步骤

  1. 把 LBP 特征图划分成若干个单元格(cell)

    • 比如划分为 8×8 = 64 个单元格
    • OpenCV 中用 grid_xgrid_y 控制水平和垂直方向的单元格数
  2. 对每个单元格统计 LBP 值的直方图

    • 每个单元格统计一个 256 维的直方图(因为 LBP 值是 0~255)
    • 直方图统计的是「每种 LBP 模式出现了多少次」
  3. 把所有单元格的直方图拼接成一个长向量

    • 8×8 个单元格 × 256 维 = 16384 维特征向量
    • 这个向量就是整张人脸的特征表示

这样做的好处:

  • 具有一定的平移不变性:人脸稍微移动一点,每个单元格内的直方图变化不大
  • 保留了空间信息:不同位置的单元格是分开的,不是整张图一个直方图,所以能区分眼睛在上面、嘴巴在下面的空间结构

四、人脸识别过程

有了 LBPH 特征向量之后,人脸识别怎么进行呢?

训练阶段

  1. 收集已知身份的人脸图像(每人若干张)
  2. 对每张人脸图像计算 LBPH 特征向量
  3. 把特征向量和对应的身份标签存起来,形成「人脸库」

识别阶段

  1. 对待识别的人脸图像计算 LBPH 特征向量
  2. 和人脸库中的每个特征向量计算距离(相似度)
  3. 找到距离最近的那个人脸,其身份就是识别结果
  4. 如果最近距离超过了阈值,说明库中没有这个人,返回「无法识别」

LBPH 通常使用 直方图相交距离欧氏距离 来衡量相似度。距离越小,说明两张脸越相似。


五、环境准备

LBPH 人脸识别器在 opencv-contrib-python 包中,所以除了基础的 opencv-python,还需要安装 contrib 包:

bash 复制代码
pip install opencv-python opencv-contrib-python

注意:两个包的版本号最好保持一致,否则可能出现兼容性问题。


六、完整代码实现

下面是 LBPH 人脸识别的完整代码,包含训练和预测两个步骤:

python 复制代码
import cv2
import numpy as np

# ========== 1. 准备训练数据 ==========
# images 列表存放训练用的人脸灰度图
images = []
# 每人 2 张训练图片,标签分别为 0 和 1
images.append(cv2.imread('wyz1.png', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('wyz2.png', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('yy1.png', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('yy2.png', cv2.IMREAD_GRAYSCALE))

# 标签:与 images 一一对应
# 0 代表 wyz,1 代表 yy
labels = [0, 0, 1, 1]

# 标签到姓名的映射字典,-1 表示无法识别
dic = {0: 'wyz', 1: 'yy', -1: '无法识别'}

# ========== 2. 读取待识别的图像 ==========
predict_image = cv2.imread('wyz.png', cv2.IMREAD_GRAYSCALE)

# ========== 3. 创建 LBPH 人脸识别器 ==========
# cv2.face.LBPHFaceRecognizer_create(radius, neighbors, grid_x, grid_y, threshold)
# 参数说明:
#   radius    - 圆形LBP的半径,默认 1
#   neighbors - 采样点数量,默认 8
#   grid_x    - 水平方向单元格数,默认 8
#   grid_y    - 垂直方向单元格数,默认 8
#   threshold - 识别阈值,距离超过阈值则返回 -1(无法识别)
recognizer = cv2.face.LBPHFaceRecognizer_create(threshold=80)

# ========== 4. 训练识别器 ==========
# recognizer.train(训练图像列表, 标签数组)
# 注意:标签需要转换为 numpy 数组
recognizer.train(images, np.array(labels))

# ========== 5. 进行预测 ==========
# recognizer.predict(待识别图像) 返回 (label, confidence)
#   label      - 预测的标签,-1 表示无法识别
#   confidence - 置信度(距离),越小表示越相似,通常 80 以下认为可靠
label, confidence = recognizer.predict(predict_image)

# ========== 6. 输出结果 ==========
print('这人是:', dic[label])
print('置信度:', confidence)

七、API 详解

7.1 创建识别器

python 复制代码
recognizer = cv2.face.LBPHFaceRecognizer_create(
    radius=None,
    neighbors=None,
    grid_x=None,
    grid_y=None,
    threshold=None
)
参数 默认值 含义
radius 1 圆形 LBP 的半径,值越大捕捉的纹理范围越广
neighbors 8 圆形邻域的采样点数,值越大特征越丰富
grid_x 8 水平方向划分的单元格数
grid_y 8 垂直方向划分的单元格数
threshold DBL_MAX 识别阈值,距离超过此值返回 -1

7.2 训练模型

python 复制代码
recognizer.train(src, labels)
参数 类型 含义
src list 训练图像列表,每张都是灰度图,尺寸可以不同
labels np.array 对应的标签数组,整数类型

注意:和 EigenFace / FisherFace 不同,LBPH 不要求训练图像尺寸一致,因为它统计的是直方图,和图像绝对大小无关。这是 LBPH 的一大优势。

7.3 预测识别

python 复制代码
label, confidence = recognizer.predict(src)
返回值 含义
label 预测的标签(整数),-1 表示无法识别
confidence 置信度评分(距离),越小越相似

关于置信度的说明:

  • LBPH 的置信度本质上是「距离」,值越小表示越相似
  • 经验值:低于 80 通常认为是比较可靠的匹配
  • 高于 80 说明差异较大,可能不是同一个人
  • 如果设置了 threshold 参数,超过阈值会直接返回标签 -1

八、运行与测试

准备数据

你需要准备以下图片(和代码放在同一目录下):

复制代码
wyz1.png  wyz2.png    # 第一个人的 2 张训练图
yy1.png   yy2.png     # 第二个人的 2 张训练图
wyz.png               # 待测试的图片(可以是 wyz 的新照片)

训练图片建议:

  • 都是正面人脸,光线均匀
  • 大小适中,人脸占主要部分
  • 每人至少 2 张,越多识别越准确

运行结果

运行代码后,控制台输出:

复制代码
这人是: wyz
置信度: 71.13878086125617

识别结果图:

置信度 71.14 在 80 以下,说明识别结果比较可靠,模型正确地识别出了测试图片中的人脸身份。


九、提高准确率的技巧

1. 增加训练样本

每人的训练图片越多,识别越准确。建议每人至少 3~5 张,涵盖不同表情、不同角度。

2. 人脸对齐

训练前先用 Haar 级联分类器检测人脸,裁剪出人脸区域再训练。这样可以排除背景干扰,让特征更集中。

3. 直方图均衡化

对训练和测试图片都做直方图均衡化,减少光照差异的影响:

python 复制代码
gray = cv2.equalizeHist(gray)

4. 调整阈值

根据实际场景调整 threshold

  • 安全要求高的场景(如门禁),阈值设小一点,宁可漏识别也不要误识别
  • 一般场景,阈值 80 左右比较合适

5. 调整 grid 参数

grid_xgrid_y 越大,空间分辨率越高,但特征维度也越高,可能过拟合。默认 8×8 通常够用。


十、LBPH 的优缺点

优点 缺点
原理简单,容易理解 识别准确率一般,不如深度学习方法
对光照变化不敏感 对姿态变化(侧脸)较敏感
单张图片也能训练 特征维度较高,识别速度随样本数线性下降
不要求图像尺寸一致 对表情变化、遮挡的鲁棒性一般
训练速度快

小结

本篇详细讲解了 LBPH 人脸识别算法的原理和实现。核心要点:

  1. LBP 算子:比较中心像素和邻域像素,生成二进制编码,描述局部纹理
  2. LBPH 直方图:将图像划分为单元格,每个单元格统计 LBP 直方图,拼接成特征向量
  3. 识别原理:计算待识别图像与库中图像的特征距离,取最近邻作为结果
  4. API 用法LBPHFaceRecognizer_createtrainpredict 三步走
  5. 参数调优:阈值、grid 大小、训练样本数量都会影响准确率

相关推荐
Yanjun2i1 小时前
Agent学习记录四:多工具时如何处理
人工智能·python·学习·agent
李少兄2 小时前
Java 中只有值传递吗?
java·开发语言·python
名字还没想好☜2 小时前
Spring @EventListener 事件驱动解耦实战:同步转异步、事务绑定与顺序控制
java·数据库·后端·python·spring
ellenwan20262 小时前
看到“最新 AI 量化学习”时,先让表达变清楚
人工智能·python
海宇数据3 小时前
零信任架构实战:基于海宇柠檬查出险-登记证构建自动化残值评估网关
人工智能·python·架构·自动化
李可以量化4 小时前
Tornado 如何增加网页操作(下)
python
zhangzeyuaaa4 小时前
深入理解 pip install .:安装当前目录项目的正确姿势
人工智能·python·pip
Jazz_z4 小时前
纯 Python 环境下 Excel 文件的读取与导入详解
python
Thomas.Sir5 小时前
第38课:TensorFlow|可视化工具TensorBoard全用法【日志写入、指标监控、网络可视化】
人工智能·python·tensorflow