使用Python,OpenCV,本地二进制模式(LBP)进行人脸识别

Posted 程序媛一枚~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Python,OpenCV,本地二进制模式(LBP)进行人脸识别相关的知识,希望对你有一定的参考价值。

使用Python,OpenCV与本地二进制模式(LBP)进行人脸识别

在深度学习和暹罗网络之前,面部识别算法依赖于特征提取和机器学习。

这篇博客将介绍如何使用本地二进制模式(Local Binary Patterns LBP),OpenCV和CV2.Face.LbphFacerEgnizer_Create进行人脸识别功能。

1. 效果图

2. 原理及步骤

2.1 原理

首先是应用CALTECH FACES数据集,这是评估面部识别算法的基准数据集。
然后审查了Ahonen等人介绍的LBPS面部识别算法。这种方法非常简单且有效。整个算法基本上由三个步骤组成:

  1. 将每个输入图像的面部划分为7×7等大小的单元格;
  2. 从每个单元中提取局部二进制模式。根据如何辨别每个细胞用于人脸识别来度量它们,最后连接7×7 = 49直方图以形成最终特征向量;
  3. 使用具有k = 1的的K-NN分类器和x^2距离度量来执行面部识别。

在Caltech面对数据集上训练脸部识别器,可获得98%的准确性。

2.2 步骤

  1. 给定数据集中的面部,算法的第一步是将面部划分为7×7等大小的单元。

  2. 然后,对于这些单元中的每一个,计算局部二进制模式直方图。

    根据定义,直方图抛出关于模式如何彼此定向的空间信息。然而,通过计算每个小区域的直方图,我们实际上能够编码诸如眼睛,鼻子,嘴巴等的空间信息水平。该空间编码还允许我们以不同方式从每个细胞的直方图中给出不同的加权值,表明更明显的面部特征的差异。

    可以看到原始的面部图像分为7×7个细胞(左)。然后,在右侧,我们可以看到每个单元的加权方案:

  3. 对于白色细胞(例如眼睛)的LBP直方图比其他细胞更多的重量为4倍。这简单意味着从白细胞区域采取LBP直方图并将它们乘以4(考虑到直方图的任何缩放/归一化)。

浅灰色细胞(嘴巴和耳朵)贡献2倍。
深灰色细胞(内颊和额头)只有贡献1x。
最后,黑细胞,如鼻子和外脸颊,完全忽略并称重0x。

Ahonen等人通过在其训练,验证和测试数据拆分之上运行HyperParameter调整算法等实验发现了这些加权值。
最后,加权的7×7 LBP直方图连接在一起以形成最终特征向量。

  1. 执行面部识别是使用 x^2 距离和最近的邻居分类器完成的:
  • 脸部呈现给系统

  • 以与训练数据相同的方式提取,加权和连接的Lbps

  • 使用 x^2 距离进行K-NN(带k = 1),以找到训练数据中最接近的面。

  • 选择最小的距离的脸部相关联的人的名称作为最终分类

用于面部识别算法的LBP并不复杂!提取局部二进制模式将提取方法扩展为计算7×7 = 49个细胞的直方图是简单的。

注意,面部识别算法的LBP具有可更新的额外益处,因为新的面部被引入数据集。

其他流行算法(例如特征缺口 EigenFaces)要求在训练时间出现要识别的所有面孔。这意味着如果将新的面部添加到数据集中,则必须重新培训整个特征文件分类器,这可以是非常重要的密集型的。

相反,用于面部识别算法的LBPS可以简单地插入新的面部样本,而无需重新培训 - 在使用与常规频率的数据集中添加或从数据集中删除的面部数据集时显而易见的益处。

3. 源码

# CALTECH FACES是面部识别算法的基准数据集。总的来说,数据集由450个图像组成约27人。如图4所示,在各种照明条件,背景场景和面部表情下捕获每个受试者。
# 本教程的总体目标是应用特征缺陷面部识别算法(Eigenfaces face recognition algorithm),以识别CALTECH FACES数据集中的每个拍摄对象。

# face_detector  目录包含OpenCV深度学习的面部探测器。该探测器既快速准确,能够实时运行,无需GPU。

# USAGE
# python lbp_face_reco.py --input caltech_faces

# 导入必要的包
from sklearn.preprocessing import LabelEncoder  # 加载类标签由String转为int类型
from sklearn.model_selection import train_test_split  # 训练和测试数据集分割
from sklearn.metrics import classification_report
from pyimagesearch.faces import load_face_dataset  # 加载CaltechFaces数据集
import numpy as np
import argparse
import imutils
import time
import cv2
import os

# 构建命令行参数及解析
# --input 输入图片数据集的路径
# --face 面部检测器模型的目录
# --confidence 面部检测的最小置信度(用于标识弱/假阳性结果的值)
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--input", type=str, required=True,
                help="path to input directory of images")
ap.add_argument("-f", "--face", type=str,
                default="face_detector",
                help="path to face detector model directory")
ap.add_argument("-c", "--confidence", type=float, default=0.5,
                help="minimum probability to filter weak detections")
args = vars(ap.parse_args())

# 从磁盘加载序列化的面部检测器模型
print("[INFO] loading face detector model...")
prototxtPath = os.path.sep.join([args["face"], "deploy.prototxt"])
weightsPath = os.path.sep.join([args["face"],
                                "res10_300x300_ssd_iter_140000.caffemodel"])
net = cv2.dnn.readNet(prototxtPath, weightsPath)

# 加载CALTECH faces数据集,要求置信度0.5,每个人最小样本量20
print("[INFO] loading dataset...")
(faces, labels) = load_face_dataset(args["input"], net,
                                    minConfidence=0.5, minSamples=20)
print("[INFO] {} images in dataset".format(len(faces)))

# 编码类标签由String转为Int
le = LabelEncoder()
labels = le.fit_transform(labels)

# 构建训练和测试集分组(训练集75%,测试集25%)
(trainX, testX, trainY, testY) = train_test_split(faces,
                                                  labels, test_size=0.25, stratify=labels, random_state=42)

# 训练LBP面部识别器
print("[INFO] training face recognizer...")
# 虽然Ahonen等人的原始训练建议使用7×7网格,我更喜欢使用8×8网格,允许更高的粒度,从而提高准确度。
# 这种准确度的提高是以(1)更长的特征提取/比较时间(由于将从49到64跳跃的LBP直方图的数量)为代价(由于从49到64跳跃),但也许更重要的是,(2)相当多的内存消耗存储特征向量。
# 在实践中,自己的数据集上您应该调整grid_x和grid_y,并查看哪些值产生最高准确度。
recognizer = cv2.face.LBPHFaceRecognizer_create(
    radius=2, neighbors=16, grid_x=8, grid_y=8)
start = time.time()
# 训练模型
recognizer.train(trainX, trainY)
end = time.time()
print("[INFO] training took {:.4f} seconds".format(end - start))

# 初始化预测结果和置信度list
print("[INFO] gathering predictions...")
predictions = []
confidence = []
start = time.time()

# 遍历测试数据集
for i in range(0, len(testX)):
    # 执行面部识别预测
    # 更新预测list和置信度分数list
    # 返回(1)预测的2元组(即主题的整数标签)和(2)CONF(信心短暂),它只是当前测试矢量和训练数据中最近的数据点之间的x^2距离。距离越低,两个面部属于同一个人的可能性越大。
    (prediction, conf) = recognizer.predict(testX[i])
    predictions.append(prediction)
    confidence.append(conf)

# 度量预测数据集耗时
end = time.time()
print("[INFO] inference took {:.4f} seconds".format(end - start))

# 展示分类结果
print(classification_report(testY, predictions,
                            target_names=le.classes_))

# 生成测试数据的样本
idxs = np.random.choice(range(0, len(testY)), size=10, replace=False)

# 便利测试数据样本
for i in idxs:
    # 获取预测面部名称和实际名称
    predName = le.inverse_transform([predictions[i]])[0]
    actualName = le.classes_[testY[i]]

    # 获取面部图片并等比例缩放为宽度250,因此可以很好的展示在屏幕上
    face = np.dstack([testX[i]] * 3)
    face = imutils.resize(face, width=250)

    # 显示预测名称和实际名称在图像上
    cv2.putText(face, "pred: {}".format(predName), (5, 25),
                cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)
    cv2.putText(face, "actual: {}".format(actualName), (5, 60),
                cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)

    # 展示预测名称,实际名称,预测置信度文本值在图像上,预测置信度值越小,预测越准确;
    print("[INFO] prediction: {}, actual: {}, confidence: {:.2f}".format(
        predName, actualName, confidence[i]))

    # 显示面部到屏幕
    cv2.imshow("Face", face)
    cv2.waitKey(0)

参考

尽管近期识别领域发展迅速,但在规模上有效地实施面部核查和识别会对目前的方法产生严重挑战。在本文中,我们提出了一个称为FaceNet的系统。该系统直接从面部图像到紧凑的欧几里德空间学习,其中距离直接对应于面部相似度的量度。一旦产生了该空间,可以使用具有FaceNet Embeddings作为特征向量的标准技术来容易地实现诸如面部识别,验证和聚类的任务。

我们使用深度卷积的网络训练,直接优化嵌入本身,而不是在以前的深度学习方法中的中间瓶颈层。训练模型时我们使用小说在线三联挖掘方法产生的大致对齐/非匹配面补丁的三胞胎。这个方法的好处是更大的代表性效率:仅利用每张面部128字节实现最先进的面部识别性能。

在被广泛使用的Wild(LFW)数据集中,FaceNet系统实现了99.63%的新记录准确度。在YouTube面部DB数据集中,它达到了95.12%。我们的系统与两个数据集中的最佳已发布结果相比削减了错误率。

我们还介绍了谐波嵌入以及谐波三态损失的概念,描述了彼此兼容的不同版本的面部嵌入式(由不同的网络产生),并且允许彼此之间的直接比较。

OpenFace是一个Python和 Torch 的人脸识别与深神经网络的人脸识别,并基于CVPR 2015纸张面孔:谷歌·施罗夫,德米特里卡莱尼科和詹姆斯菲尔宾的面部识别和聚类统一嵌入。Torch 允许在CPU或CUDA上执行网络。

使用深神经网络表示(或嵌入)128维单元间距的面部。嵌入是通用的操作。与其他面部表示不同,这种嵌入具有良好的特性,即两个面部嵌入之间的距离更大的距离意味着面部可能不具有同一个人。该属性使得聚类,相似性检测和分类任务更容易。

以上是关于使用Python,OpenCV,本地二进制模式(LBP)进行人脸识别的主要内容,如果未能解决你的问题,请参考以下文章

与已知图像匹配的局部二进制模式

OpenCV中LBPH人脸识别器识别人脸实战(附Python源码)

使用 LBP、深度学习和 OpenCV 进行实时人脸识别

如何使用 Python/Opencv 分割二进制图像中的附近元素

SWIG Python 绑定到本地代码不适用于 OpenCV 2.1

使用Python+Opencv从摄像头逐帧读取图片保存在本地