人脸识别就是找到一个可以表征每个人脸特征的模型,在进行识别是先提取当人脸的特征,再从已有的特征集这种找到最为接近的人脸样本,从而得到当前人脸的标签。
在如今的世界,人脸识别也变得越来越重要,应用越来越广泛,比如人脸识别可用于身份认证、摄影、支付、视频等领域。
在Opencv中提供了LPBH、EigenFishfaces和FisherFace三种人脸识别方法。
一、LBPH算法
LBPH所使用的模型基于LBP算法,其基本原理是将图像(灰度图,如果是彩色图则先转为灰度图)中某个像素点的值与其最临近的3×3邻域8个像素点的值逐一比较,如果该点像素值大于其邻近点的像素值,则得到0,反之,如果该点像素值小于其临界点的像素值,则得到1,最后,将该像素点与其周围8个像素点比较所得到的0和1组合,并依次排列,得到一个8位的二进制序列,将该二进制序列转换为十进制数作为该像素点的LBP值。
上述是原始的LBPH 算法,后续又有人将其改进,将3×3邻域拓展到任意区域,并用圆形代替了正方形邻域,改进后的 LBP 算子允许在半径为 R 的圆形邻域内有任意多个像素点。从而得到了诸如半径为R的圆形区域内含有P个采样点的LBP算子。
以下是LBPH特征提取的C++代码:
#include <opencv2\opencv.hpp>
#include <iostream>
#include <opencv2\imgproc\types_c.h>
using namespace std;
using namespace cv;
int main(int argc, char** argv)
{
Mat src, gray_src;
src = imread("E:\\picture\\1.png");
if (src.empty())
{
cout << "could not read image ... " << endl;
getchar();
return -1;
}
//namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
cvtColor(src, gray_src, CV_BGR2GRAY);
//cvtColor(src, gray_src,10);
int width = gray_src.cols;
int height = gray_src.rows;
Mat lbpImage = Mat::zeros(height - 2, width - 2, CV_8SC1);
for (int row = 1; row < height - 1; row++)
{
for (int col = 1; col < width - 1; col++)
{
uchar c = gray_src.at<uchar>(row, col);
uchar code = 0;
code |= (gray_src.at<uchar>(row - 1, col - 1) > c) << 7;
code |= (gray_src.at<uchar>(row - 1, col ) > c) << 6;
code |= (gray_src.at<uchar>(row - 1, col + 1) > c) << 5;
code |= (gray_src.at<uchar>(row , col + 1) > c) << 4;
code |= (gray_src.at<uchar>(row + 1, col + 1) > c) << 3;
code |= (gray_src.at<uchar>(row + 1, col ) > c) << 2;
code |= (gray_src.at<uchar>(row + 1, col - 1) > c) << 1;
code |= (gray_src.at<uchar>(row , col - 1) > c) << 0;
lbpImage.at<uchar>(row - 1, col - 1) = code;
}
}
imshow("output image", gray_src);
waitKey(0);
return 0;
}
右图是原图像,左图是经过LBPH特征提取输出图像。
如果将以上得到的LBPH图直接用于人脸识别,其实和不提取LBP特征没什么区别,在实际的LBP应用中一般采用LBPH特征谱的统计直方图作为特征向量进行分类识别,并且可以将一幅图片划分为若干的子区域,对每个子区域内的每个像素点都提取LBP特征,然后,在每个子区域内建立LBPH特征的统计直方图。
如此一来,每个子区域,就可以用一个统计直方图来进行描述,整个图片就由若干个统计直方图组成,这样做的好处是在一定范围内减小图像没完全对准而产生的误差,分区的另外一个意义在于我们可以根据不同的子区域给予不同的权重,比如说我们认为中心部分分区的权重大于边缘部分分区的权重,意思就是说中心部分在进行图片匹配识别时的意义更为重大。
例如:一幅100×100像素大小的图片,划分为10×10=100个子区域(可以通过多种方式来划分区域),每个子区域的大小为10×10像素;在每个子区域内的每个像素点,提取其LBP特征,然后,建立统计直方图;这样,这幅图片就有10×10个子区域,也就有了10×10个统计直方图,利用这10×10个统计直方图,就可以描述这幅图片了。之后,我们利用各种相似性度量函数,就可以判断两幅图像之间的相似性了。关于相似度度量函数,跟人脸识别一样有很多方法,在这就不逐一分析了,知道LBPH的原理就可以。
以下是LBPH人脸识别的Python实现:
#导入库
import cv2 as cv
import numpy as np
#创建记录读取的训练数据集的列表
images = []
#往列表里添加训练集图片,这里的地址根据数据集在你电脑上放置的位置进行修改,数目可以增加,数目越多识别准确度越高。
images.append(cv.imread("E:/picture/11.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/12.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/13.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/21.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/22.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/23.png", cv.IMREAD_GRAYSCALE))
#创建标签
labels = [0,0,0,1,1,1]
#利用opencv中的FisherFace算法,生成Fisher识别器模型
recognizer = cv.face.LBPHFaceRecognizer_create()
#训练数据集
recognizer.train(images,np.array(labels))
#读取待检测的图像
predict_image1 = cv.imread("E:/picture/1.png",cv.IMREAD_GRAYSCALE)
predict_image2 = cv.imread("E:/picture/2.png",cv.IMREAD_GRAYSCALE)
#识别图像
label1,configence1 = recognizer.predict(predict_image1)
label2,configence2 = recognizer.predict(predict_image2)
#输出识别结果
print("label1= ",label1)
print("confidence1= ",configence1)
print("label2= ",label1)
print("confidence2= ",configence1)
数据集:
结果:
label1= 0
confidence1= 31.010053777159456
label2= 0
confidence2= 31.010053777159456
二、用FisherFace与EignFaces算法进行人脸识别
#导入库
import cv2 as cv
import numpy as np
#创建记录读取的训练数据集的列表
images = []
#往列表里添加训练集图片,这里的地址根据数据集在你电脑上放置的位置进行修改,数目可以增加,数目越多识别准确度越高。
images.append(cv.imread("E:/picture/11.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/12.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/13.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/21.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/22.png", cv.IMREAD_GRAYSCALE))
images.append(cv.imread("E:/picture/23.png", cv.IMREAD_GRAYSCALE))
#创建标签
labels = [0,0,0,1,1,1]
#利用opencv中的FisherFace算法,生成Fisher识别器模型
recognizer1 = cv.face.FisherFaceRecognizer_create()
#利用opencv中的EigenFace算法,生成Eign识别器模型
recognizer2 = cv.face.EigenFaceRecognizer_create()
#训练数据集
recognizer1.train(images,np.array(labels))
recognizer2.train(images,np.array(labels))
#读取待检测的图像
predict_image1 = cv.imread("E:/picture/1.png",cv.IMREAD_GRAYSCALE)
predict_image2 = cv.imread("E:/picture/2.png",cv.IMREAD_GRAYSCALE)
#识别图像
label1,configence1 = recognizer1.predict(predict_image1)
label2,configence2 = recognizer2.predict(predict_image2)
#输出识别结果
print("label1= ",label1)
print("confidence1= ",configence1)
print("label2= ",label2)
print("confidence2= ",configence2)
此代码使用的数据集和上面LBPH算法使用的一样,输出结果为:
label1= 0
confidence1= 3683.4028152276414
label2= 1
confidence2= 4493.339622323507
如果在用以上Python代码实现人脸识别的时候,出现一下错误:
Traceback (most recent call last):
File "C:/Users/13611/Desktop/import cv2.py", line 25, in <module>
recognizer1.train(images,np.array(labels))
cv2.error: OpenCV(4.0.1) C:\ci\opencv-suite_1573470242804\work\opencv_contrib-4.0.1\modules\face\src\fisher_faces.cpp:81: error: (-210:Unsupported format or combination of formats) In the Fisherfaces method all input samples (training images) must be of equal size! Expected 111000 pixels, but was 53088 pixels. in function 'cv::face::Fisherfaces::train'
这是数据集这几张图片像素大小不一样,是用截图或者ps修改一下,也可以给我留言,给我要一下我使用的数据集。