opencv计算机视觉--LBPH&EigenFace&FisherFace人脸识别

一、LBPH(Local Binary Patterns Histograms)原理

1. LBP(局部二值模式)基础

LBP是一种用于图像纹理分析的算子,其基本思想是:

  • 以每个像素为中心,比较其与周围像素的灰度值

  • 将比较结果编码为二进制数,再转换为十进制数

  • 公式:LBP(x_c, y_c) = \\sum_{p=0}\^{P-1} s(g_p - g_c) \\times 2\^p

    其中 s(x) = \\begin{cases} 1 \& \\text{if } x \\geq 0 \\ 0 \& \\text{else} \\end{cases}

2. LBPH人脸识别流程
复制代码
原始图像 → 提取LBP特征 → 分块直方图 → 连接直方图 → 形成特征向量 → 分类识别

代码中使用的重要函数详解

1. cv2.face.LBPHFaceRecognizer_create()
python 复制代码
recognizer = cv2.face.LBPHFaceRecognizer_create(
    radius=1,          # LBP半径,默认1
    neighbors=8,       # 采样点数量,默认8
    grid_x=8,          # 水平方向网格数
    grid_y=8,          # 垂直方向网格数
    threshold=80       # 识别阈值
)
参数说明:
  • radius:半径值,表示从中心像素到周围像素的距离

  • neighbors:采样点数量,通常为8、12、16等

  • grid_x/grid_y:将图像划分的网格数,用于提取局部直方图

  • threshold:置信度阈值,高于此值认为无法识别

2. recognizer.train(images, labels)
python 复制代码
recognizer.train(images, np.array(labels))

功能:训练LBPH模型

  • images:训练图像列表(必须为灰度图)

  • labels :对应的标签数组
    内部过程

    1. 对每张图像提取LBP特征

    2. 将图像划分为grid_x × grid_y个单元格

    3. 为每个单元格计算LBP直方图

    4. 连接所有直方图形成特征向量

    5. 存储特征向量和标签的映射关系

3. recognizer.predict(src)
python 复制代码
label, confidence = recognizer.predict(predict_image)

功能:识别人脸并返回结果

  • 返回值label:识别出的标签,-1表示无法识别

  • 返回值confidence:置信度分数(越低表示匹配度越高)

置信度说明

  • 0-50:高度匹配

  • 50-80:一般匹配

  • 80:可能不匹配(具体阈值可调整)

LBPH算法特点

优点:
  1. 光照不变性:对光照变化不敏感

  2. 计算简单:实时性好,适合嵌入式系统

  3. 旋转不变性:可通过扩展实现旋转不变性

  4. 内存占用小:特征向量维度相对较低

缺点:
  1. 对姿态变化敏感

  2. 需要人脸对齐预处理

  3. 受遮挡影响较大

实际应用

python 复制代码
import cv2
import numpy as np

# 提前训练的人脸照片
images = []
images.append(cv2.imread('qingzi/qz1.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('qingzi/qz2.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('qingzi/qz3.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('qingzi/qz4.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('susu/ss1.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('susu/ss2.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('susu/ss3.jpg', cv2.IMREAD_GRAYSCALE))
images.append(cv2.imread('susu/ss4.jpg', cv2.IMREAD_GRAYSCALE))

labels = [0, 0, 0, 0, 1, 1, 1, 1]
dic = {0: 'qz', 1: 'ss', -1: '无法识别'}

predict_image = cv2.imread('qingzi/qz5.jpg', cv2.IMREAD_GRAYSCALE)  # 待识别人脸
# predict_image = cv2.imread('susu/ss5.jpg', cv2.IMREAD_GRAYSCALE)  # 待识别人脸

# 创建一个LBPH的人脸特征识别器
# 函数说明:
# radius: 可选参数,圆度与半径的平方根,建议使用默认值
# neighbors: 可选参数,圆度与半径的平方根,建议使用默认值
# grid_x: 可选参数,水平方向上的像素数,默认值为8,即将LBP特征图在水平方向上划分为8个单元
# grid_y: 可选参数,垂直方向上的像素数,默认值为8,建议使用默认值
# threshold: 可选参数,人脸识别时使用的阈值,建议使用默认值
recognizer = cv2.face.LBPHFaceRecognizer_create(threshold=80)  # 修正:facce应为face

# 函数train用给定的数据和相关标签训练生成的实例模型
# 语法格式:None = 识别对象.train(src, labels)
# 参数说明:
# src: 训练图像,用来学习的人脸图像
# labels: 标签,人脸图像对应的标签
recognizer.train(images, np.array(labels))

# 函数predict()对一个待识别的人脸图像进行判断,寻找与当前图像距离最近的人脸图像
# 参数与返回值的含义如下:
# src: 需要识别的原始图像
# label: 返回的识别结果标签,返回-1表示无法识别当前人脸
# confidence: 返回的置信度评分,用来衡量识别结果与原有模型之间的差异
# 评价标准是不同距离,但若是高于80,则认为识别结果与原有模型差距大
label, confidence = recognizer.predict(predict_image)

print('这人是:', dic[label])  # 修正:应为dic[label]而不是字符串
print('置信度:', confidence)  # 修正:应为confidence变量而不是字符串

二、EigenFace

1.EigenFace(特征脸)原理

核心思想

EigenFace是基于**主成分分析(PCA)**的人脸识别方法,核心思想是将人脸图像从高维像素空间转换到低维特征空间。

数学原理
复制代码
1. 数据准备:将所有训练人脸图像拉直为列向量
   X = [x₁, x₂, ..., xₙ] ∈ ℝ^(m×n)

2. 计算平均脸:
   ψ = (1/n) Σ xᵢ

3. 计算差值矩阵:
   A = [x₁-ψ, x₂-ψ, ..., xₙ-ψ]

4. 计算协方差矩阵:
   C = A·Aᵀ ∈ ℝ^(m×m)  # 维度极大,直接计算困难

5. 使用SVD求解特征向量(特征脸):
   Aᵀ·A·vᵢ = λᵢ·vᵢ  # 先计算小矩阵的特征向量
   uᵢ = A·vᵢ  # 再得到特征脸

6. 选取前k个最大特征值对应的特征脸构成投影矩阵
特征脸可视化
python 复制代码
import matplotlib.pyplot as plt

# 获取特征脸
mean_face = recognizer.getMean()  # 平均脸
eigenfaces = recognizer.getEigenVectors()  # 特征脸

# 显示平均脸
plt.subplot(1, 5, 1)
plt.title("Mean Face")
plt.imshow(mean_face.reshape(140, 120), cmap='gray')

# 显示前4个特征脸
for i in range(4):
    plt.subplot(1, 5, i+2)
    plt.title(f"Eigenface {i+1}")
    plt.imshow(eigenfaces[:, i].reshape(140, 120), cmap='gray')
plt.show()

2、 代码中使用的函数详解

1 .cv2.face.EigenFaceRecognizer_create()
python 复制代码
recognizer = cv2.face.EigenFaceRecognizer_create(
    num_components=0,    # PCA保留的主成分数量
    threshold=7000       # 识别阈值
)

参数说明:

  • num_components

    • 0或None:保留所有特征向量(默认)

    • N:保留前N个最大的特征向量

    • 建议值:通常取80-150,保留总方差的85%-95%

  • threshold

    • 识别阈值,高于此值认为无法识别

    • EigenFace的confidence范围:0~20000

    • <5000:可靠匹配

    • 5000-7000:可能匹配

    • 7000:可能不匹配

2.recognizer.train(images, labels)

训练过程:

python 复制代码
recognizer.train(images, np.array(labels))

内部步骤:

  1. 将图像转换为列向量(140×120 → 16800维)

  2. 计算平均脸(所有训练图像的平均)

  3. 计算协方差矩阵的特征值和特征向量

  4. 选择前num_components个特征向量(特征脸)

  5. 将训练图像投影到特征脸空间

  6. 存储投影系数和标签

3 .recognizer.predict(pre_image)
python 复制代码
label, confidence = recognizer.predict(pre_image)

识别过程:

  1. 将测试图像减去平均脸

  2. 投影到特征脸空间得到特征向量

  3. 与所有训练样本的特征向量比较(欧氏距离)

  4. 返回最近邻的标签和距离

返回值:

  • label:识别结果标签,-1表示无法识别

  • confidence:欧氏距离,值越小表示越相似

3. EigenFace算法特点

优点:
  1. 降维效果好:将高维人脸数据降至几十维

  2. 计算相对简单:数学原理清晰

  3. 光照处理:通过减去平均脸,部分消除光照影响

  4. 存储效率高:只需存储特征脸和投影系数

缺点:
  1. 对光照敏感:仍需较好的光照条件

  2. 姿态要求严格:需要严格对齐的人脸

  3. 表情影响大:表情变化会影响识别效果

  4. 背景干扰:需要准确的人脸裁剪

EigenFace是经典的人脸识别算法,虽然现在有更先进的深度学习方法,但其原理简单、计算高效的特点使其在特定场景下仍有应用价值。

4.实际应用

python 复制代码
import cv2
import numpy as np

images = []  # 读取训练图像,注意:图片大小需要一致

# 读取并调整图像大小
a = cv2.imread('../qingzi/qz1.jpg', 0)  # flags=0 表示以灰度模式读取
a = cv2.resize(a, (120, 140))

b  = cv2.imread('../qingzi/qz2.jpg', 0)
b = cv2.resize(b, (120, 140))

c  = cv2.imread('../qingzi/qz3.jpg', 0)
c = cv2.resize(c, (120, 140))

d = cv2.imread('../susu/ss1.jpg', 0)
d = cv2.resize(d, (120, 140))

e = cv2.imread('../susu/ss2.jpg', 0)
e = cv2.resize(e, (120, 140))

f = cv2.imread('../susu/ss3.jpg', 0)
f = cv2.resize(f, (120, 140))

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

labels = [0, 0, 0, 1, 1, 1]

# 读取并调整待预测图像大小
# pre_image = cv2.imread('susu/ss4.jpg', 0)
pre_image = cv2.imread('../qingzi/qz4.jpg', 0)
pre_image = cv2.resize(pre_image, (120, 140))

# 创建Eigenfaces人脸识别器
# 作用: 创建一个EigenFace的人脸特征识别器
# num_components: 在PCA中要保留的分量个数。该参数值通常要根据输入数据来具体确定
# 一般程序中,取80即可(降维成多少个特征)
# threshold: 进行人脸识别所采用的阈值
recognizer = cv2.face.EigenFaceRecognizer_create(threshold=7000)  # threshold=5000或4000

# 使用训练数据(images和labels)来训练识别器
# 函数FaceRecognizer.train()用给定的数据和相关标签训练生成的实例模型
# 参数的含义如下:
# src: 训练图像,用来学习的人脸图像
# labels: 标签,人脸图像对应的标签
recognizer.train(images, np.array(labels))

# 对预测图像(pre_image)进行人脸识别预测
# confidence: 大小介于0到20000,只要低于5000都被认为是可靠的结果
label, confidence = recognizer.predict(pre_image)

dic = {0: 'qz', 1: 'susu', -1: '无法识别'}
print('这是:', dic[label])
print('置信度为:', confidence)

# 在原图上标注识别结果并显示
# original_img = cv2.imread('susu/ss4.jpg').copy()
original_img = cv2.imread('../qingzi/qz4.jpg').copy()
original_img=cv2.resize(original_img,dsize=None,fx=0.5,fy=0.5)
# 在图像上添加文本
result_text = dic[label]
cv2.putText(original_img, result_text, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)

cv2.imshow('susu', original_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

三、FisherFace

1. FisherFace(费舍尔脸)原理

核心思想

FisherFace是基于线性判别分析(LDA) 的人脸识别方法,与EigenFace的PCA不同,LDA是有监督的降维方法,旨在最大化类间距离同时最小化类内距离。

数学原理(Fisher线性判别)
复制代码
目标:找到最佳投影方向w,使得投影后的数据:
1. 类间散度(between-class scatter)最大
2. 类内散度(within-class scatter)最小

定义:
- 类内散度矩阵:Sw = Σ Σ (x - μᵢ)(x - μᵢ)ᵀ
- 类间散度矩阵:Sb = Σ nᵢ(μᵢ - μ)(μᵢ - μ)ᵀ
- 总体散度矩阵:St = Sw + Sb

优化目标:J(w) = (wᵀSb w) / (wᵀSw w) → 最大化

求解:通过广义特征值分解 Sb·w = λ·Sw·w
取前(C-1)个最大特征值对应的特征向量(C为类别数)
FisherFace vs EigenFace
特征 EigenFace (PCA) FisherFace (LDA)
监督性 无监督 有监督
目标 最大方差方向 最大类间区分度
特征脸数量 可任意选择 最多C-1个(C为类别数)
适用场景 数据降维、可视化 分类任务
小样本问题 相对较好 容易过拟合

2. 代码中使用的函数详解

2.1 cv2.face.FisherFaceRecognizer_create()
python 复制代码
recognizer = cv2.face.FisherFaceRecognizer_create(
    num_components=0,    # LDA保留的特征数量
    threshold=2600       # 识别阈值
)

参数说明:

  • num_components

    • 0或None:保留C-1个特征向量(C为类别数)

    • N:保留前N个特征向量(N ≤ C-1)

    • 例如:2个人 → 最多1个特征向量

    • 例如:10个人 → 最多9个特征向量

  • threshold

    • 识别阈值,高于此值认为无法识别

    • FisherFace的confidence范围:0~10000+

    • <2000:高度可靠

    • 2000-2600:一般可靠

    • 2600:可能不可靠

2.2 recognizer.train(images, labels)
python 复制代码
recognizer.train(images, np.array(labels))

内部训练步骤:

  1. 为每个类别计算均值向量(类中心)

  2. 计算总体均值向量

  3. 计算类内散度矩阵Sw

  4. 计算类间散度矩阵Sb

  5. 求解广义特征值问题:Sb·w = λ·Sw·w

  6. 选择前num_components个特征向量

  7. 将数据投影到FisherFace空间

2.3 recognizer.predict(pre_image)
python 复制代码
label, confidence = recognizer.predict(pre_image)

识别过程:

  1. 将测试图像投影到FisherFace空间

  2. 计算与各类别中心的距离

  3. 使用最近邻分类器

  4. 返回最近邻的标签和距离

3. 实际应用

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

# 1个用法
def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30):
    """向图片中添加中文"""
    if isinstance(img, np.ndarray):  # 判断是否OpenCV图片类型
        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))  # 实现array到image的转换
    draw = ImageDraw.Draw(img)  # 在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格式

# 4个用法
def image_re(image):
    a = cv2.imread(image, 0)
    a = cv2.resize(a, (120, 180))
    images.append(a)

images = []
image_re('../qingzi/qz1.jpg')
image_re('../qingzi/qz2.jpg')
image_re('../qingzi/qz3.jpg')
image_re('../susu/ss1.jpg')
image_re('../susu/ss2.jpg')
image_re('../susu/ss3.jpg')

Labels = [0, 0, 0, 1, 1, 1]
pre_image = cv2.imread('../susu/ss4.jpg', 0)  # 读取待识别图像
# pre_image = cv2.imread('qingzi/qz5.jpg', 0)  # 读取待识别图像
pre_image = cv2.resize(pre_image, (120, 180))

# 创建一个FisherFace的人脸特征识别器
recognizer = cv2.face.FisherFaceRecognizer_create(threshold=2600)

# 训练模型
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('../susu/ss4.jpg').copy(), dic[label], (30, 10), textColor=(255, 0, 0))
# image = cv2AddChineseText(cv2.imread('qingzi/qz5.jpg').copy(), dic[label], (30, 10), textColor=(255, 0, 0))


image=cv2.resize(image,dsize=None,fx=0.6,fy=0.6)
cv2.imshow('susu', image)
# cv2.imshow('qingzi', image)
cv2.waitKey(0)

4. FisherFace的适用场景和限制

适用场景:
  1. 类别数较少(通常<50)

  2. 每个类别样本充足

  3. 需要强判别性的分类任务

  4. 数据维度高但样本相对有限

限制和解决方案:
  1. 小样本问题(SSS问题)

    • 问题:当样本数小于特征维度时,Sw矩阵奇异

    • 解决:PCA + LDA(两步法),或使用正则化

  2. 最多C-1个特征

    python

    复制代码
    # 两步法:先PCA降维,再LDA
    # 1. 使用PCA降维到适当维度
    # 2. 再使用FisherFace进行分类
  3. 类别不平衡

    python

    复制代码
    # 对少数类样本进行数据增强
    # 或使用加权LDA

5. 三种人脸识别算法对比

算法 原理 特征数 监督性 优点 缺点
EigenFace PCA 任意 无监督 计算简单,降维效果好 判别性不强
FisherFace LDA ≤C-1 有监督 判别性强,分类效果好 小样本问题
LBPH 局部二值模式 固定 有监督 光照鲁棒性好 对姿态敏感

推荐选择策略:

  • 样本充足且需要强判别性:FisherFace

  • 样本较少或需要降维:EigenFace

  • 光照变化大:LBPH

  • 实际应用:可结合多种方法进行集成

相关推荐
工程师老罗5 小时前
举例说明YOLOv1 输出坐标到原图像素的映射关系
人工智能·yolo·计算机视觉
猫头虎5 小时前
手动部署开源OpenClaw汉化中文版过程中常见问题排查手册
人工智能·langchain·开源·github·aigc·agi·openclaw
小陶的学习笔记5 小时前
python~基础
开发语言·python·学习
多恩Stone5 小时前
【3D AICG 系列-9】Trellis2 推理流程图超详细介绍
人工智能·python·算法·3d·aigc·流程图
ID_180079054735 小时前
Python结合淘宝关键词API进行商品价格监控与预警
服务器·数据库·python
整得咔咔响5 小时前
贝尔曼最优公式(BOE)
人工智能·算法·机器学习
2501_946961475 小时前
极简大气创业融资 PPT 模板,适合路演、项目宣讲
人工智能·排序算法
得一录5 小时前
AI 语音助手:如何用大模型优化智能语音交互?
人工智能
玄同7655 小时前
Python 自动发送邮件实战:用 QQ/163 邮箱发送大模型生成的内容
开发语言·人工智能·python·深度学习·机器学习·邮件·邮箱