本文使用OpenCV实现摄像头实时LBP人脸识别,这里不讲解LBP人脸识别的原理,小路孩会另外专门写特征提取的系列博客,到时会详细讲解LBP特征,敬请关注。才疏学浅,有错误在所难免,欢迎指正。
系统:Windows7;OpenCV版本:2.4.10.
人脸识别的简单流程一般包括:人脸检测、图像预处理、特征提取和人脸识别。下面分别进行介绍。
人脸检测,使用Haar+adaboost算法,通过OpenCV人脸检测实现,在人脸识别系列博客第二篇已给出代码。
图像预处理,一般对检测到的人脸图像作直方图或者滤波处理,以可以更好的提取特征。
特征提取,通过提取人脸特征,然后对这些特征进行分类进而实现人脸识别,用于描述人脸的特征一般有LBP、Gabor、HOG和SIFT等,目前十分火热的卷积神经网络也是在提取特征。
人脸识别,换句话说就是人脸分类器,将提取出的特征进行分类,一般的分类器包括欧式距离、马氏距离、SVM、贝叶斯分类器等等。
首先,还是说一下LBP特征的原理,方便后面的阐述。
原始的LBP算法的基本思想是在3*3的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该像素点的位置被标记为1,否则为0。这样,3*3邻域内的8个点经过比较可产生8位二进制数,如图1中00010011(通常转换为十进制数即LBP码,共256种),即得到该窗口中心像素点的LBP值,并用这个值来反映该区域的纹理信息。如下图所示:
通过对全局图像进行LBP特征提取得到LBP图,LBP特征图是不能直接来作人脸识别的,需要对LBP特征图进行分块并计算每个分块的直方图,通过直方图的统计信息进行识别,最后将各块的直方图首尾相连就得到一张图片最终的LBP特征描述向量。计算两张图片的LBP特征向量的相似度即可实现人脸识别。
OpenCV中LBPH人脸识别类如下进行创建
Ptr LBPHRecog = createLBPHFaceRecognizer(1, 8 ,3, 3, 50); //构造LBPH人脸识别类的对象并初始化
CV_EXPORTS_W Ptr createLBPHFaceRecognizer(int radius=1, int neighbors=8,
int grid_x=8, int grid_y=8, double threshold = DBL_MAX);
构造好LBPH人脸识别的对象,下面分别来看看训练和识别的函数:
LBPHRecog->train(trainPic, labels); //LBP人脸识别训练函数
result = LBPHRecog->predict(recogPic);//进行识别,并返回识别结果
下面直接来看代码,程序会打开笔记本的摄像头,实现实时人脸识别,并将识别结果显示在画面上。
//头文件
#include
#include
#include
#include
#include
#include
//命名空间
using namespace std;
using namespace cv;
CascadeClassifier faceDetect; //人脸检测对象
//函数声明
vector FaceDetector(Mat img);//检测人脸,并返回人脸区域
void DrawFace(Mat img, vector faces);//将人脸标注出来
void GetFilesName(string path, vector& filesName);//获取文件夹里的所有文件名称
int main()
{
//变量
Mat frame;
Mat src;
Mat facePic;
Mat recogPic;
vector faces;
vector filesName;
string path = "..\\TrainPic";
string pic;
vector trainPic;//训练图片
vector labels;//与训练图片一一对应的标签
int result;
map labelsInfo;
faceDetect.load("../models/haarcascade_frontalface_alt2.xml");
Ptr LBPHRecog = createLBPHFaceRecognizer(1, 8 ,3, 3, 50);//构造LBPH人脸识别类的对象并初始化
//加载人脸库
GetFilesName(path, filesName);
for(int i = 0; isetLabelsInfo(labelsInfo);
LBPHRecog->train(trainPic, labels); //LBP人脸识别训练函数
VideoCapture cap(0);//打开摄像头
int c=0;
if(!cap.isOpened())
{
cerr<<"摄像头无法打开"<>frame;
flip(frame, frame, 1);
recogPic = Mat::zeros(200, 200, frame.type());
double t = (double)getTickCount();//检测的时间
faces = FaceDetector(frame);
t = ((double)getTickCount() - t)/getTickFrequency();
cout<predict(recogPic);//进行识别
//将识别结果显示在实时画面上
if(result ==-1)
putText(frame, "unknow", Point(faces[i].x, faces[i].y), 3, 0.5, Scalar(0, 255, 255), 1);
else
putText(frame, filesName[result], Point(faces[i].x, faces[i].y), 3, 0.5, Scalar(0, 255, 255), 1);
}
imshow("1", frame);
c =waitKey(1);
}
return 0;
}
vector FaceDetector(Mat img)
{
Mat src = Mat::zeros(240, 320, img.type());
vector faces;
cvtColor(img, img, CV_RGB2GRAY);
resize(img, src, src.size());
faceDetect.detectMultiScale(src, faces, 1.2, 6, 0,Size(30,30));
for(int i=0; i faces)
{
for(size_t num = 0; num& filesName)
{
//文件句柄
long hFile = 0;
//文件信息
struct _finddata_t fileinfo;
string p;
if((hFile = _findfirst(p.assign(path).append("\\*").c_str(),&fileinfo)) != -1)
{
do
{
//如果是目录,迭代之
//如果不是,加入列表
if((fileinfo.attrib & _A_SUBDIR))
{
if(strcmp(fileinfo.name,".") != 0 && strcmp(fileinfo.name,"..") != 0)
GetFilesName( p.assign(path).append("\\").append(fileinfo.name), filesName );
}
else
{
filesName.push_back(p.assign(path).append("\\").append(fileinfo.name));
}
}while(_findnext(hFile, &fileinfo) == 0);
_findclose(hFile);
}
}
注意:上述代码中人脸图片的训练部分并不具有通用性,需要根据实际运用进行修改,这部分就由读者自己来完成吧 :)
代码运行的结果图就不贴上去了,见谅~