【OpenCV人脸识别入门教程之四】LBP人脸识别
2015-11-10 20:33
453 查看
本文使用OpenCV实现摄像头实时LBP人脸识别,这里不讲解LBP人脸识别的原理,小路孩会另外专门写特征提取的系列博客,到时会详细讲解LBP特征,敬请关注。才疏学浅,有错误在所难免,欢迎指正。
系统:Windows7;OpenCV版本:2.4.10.
人脸检测,使用Haar+adaboost算法,通过OpenCV人脸检测实现,在人脸识别系列博客第二篇已给出代码。
图像预处理,一般对检测到的人脸图像作直方图或者滤波处理,以可以更好的提取特征。
特征提取,通过提取人脸特征,然后对这些特征进行分类进而实现人脸识别,用于描述人脸的特征一般有LBP、Gabor、HOG和SIFT等,目前十分火热的卷积神经网络也是在提取特征。
人脸识别,换句话说就是人脸分类器,将提取出的特征进行分类,一般的分类器包括欧式距离、马氏距离、SVM、贝叶斯分类器等等。
原始的LBP算法的基本思想是在3*3的窗口内,以窗口中心像素为阈值,将相邻的8个像素的灰度值与其进行比较,若周围像素值大于中心像素值,则该像素点的位置被标记为1,否则为0。这样,3*3邻域内的8个点经过比较可产生8位二进制数,如图1中00010011(通常转换为十进制数即LBP码,共256种),即得到该窗口中心像素点的LBP值,并用这个值来反映该区域的纹理信息。如下图所示:
通过对全局图像进行LBP特征提取得到LBP图,LBP特征图是不能直接来作人脸识别的,需要对LBP特征图进行分块并计算每个分块的直方图,通过直方图的统计信息进行识别,最后将各块的直方图首尾相连就得到一张图片最终的LBP特征描述向量。计算两张图片的LBP特征向量的相似度即可实现人脸识别。
OpenCV中LBPH人脸识别类如下进行创建
下面看一下构造函数的原型,进而解释一下参数的含义
可以看到,参数是有默认值得,各个参数的含义如下:
int radius = 1 :中心像素点到周围像素点的距离,相邻像素距离为1,以此类推
int neighbors = 8 :选取的周围像素点的个数
int grid_x= 8 :将一张图片在x方向分成8块
int grid_y = 8 :将一张图片在y方向分成8块
double threshold = DBL_MAX :LBP特征向量相似度的阈值,只有两张图片的相似度小于阈值才可认为识别有效,大于阈值则返回-1
构造好LBPH人脸识别的对象,下面分别来看看训练和识别的函数:
训练函数参数中的trainPic是一个vector,所有需要训练的图片都被包含在内,labels也是vector,存储与trainPic中对应训练图片的名字,这样从trainPic中得到的与识别的图片最相似的图片的名字即可在labels中查找到。
返回的识别结果即是对应的labels中的名字。
注意:上述代码中人脸图片的训练部分并不具有通用性,需要根据实际运用进行修改,这部分就由读者自己来完成吧 :)
代码运行的结果图就不贴上去了,见谅~
系统:Windows7;OpenCV版本:2.4.10.
一、准备工作
1、人脸识别的简单流程
人脸识别的简单流程一般包括:人脸检测、图像预处理、特征提取和人脸识别。下面分别进行介绍。人脸检测,使用Haar+adaboost算法,通过OpenCV人脸检测实现,在人脸识别系列博客第二篇已给出代码。
图像预处理,一般对检测到的人脸图像作直方图或者滤波处理,以可以更好的提取特征。
特征提取,通过提取人脸特征,然后对这些特征进行分类进而实现人脸识别,用于描述人脸的特征一般有LBP、Gabor、HOG和SIFT等,目前十分火热的卷积神经网络也是在提取特征。
人脸识别,换句话说就是人脸分类器,将提取出的特征进行分类,一般的分类器包括欧式距离、马氏距离、SVM、贝叶斯分类器等等。
2、OpenCV-LBP人脸识别相关类和函数
首先,还是说一下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<FaceRecognizer> LBPHRecog = createLBPHFaceRecognizer(1, 8 ,3, 3, 50); //构造LBPH人脸识别类的对象并初始化
下面看一下构造函数的原型,进而解释一下参数的含义
CV_EXPORTS_W Ptr<FaceRecognizer> createLBPHFaceRecognizer(int radius=1, int neighbors=8, int grid_x=8, int grid_y=8, double threshold = DBL_MAX);
可以看到,参数是有默认值得,各个参数的含义如下:
int radius = 1 :中心像素点到周围像素点的距离,相邻像素距离为1,以此类推
int neighbors = 8 :选取的周围像素点的个数
int grid_x= 8 :将一张图片在x方向分成8块
int grid_y = 8 :将一张图片在y方向分成8块
double threshold = DBL_MAX :LBP特征向量相似度的阈值,只有两张图片的相似度小于阈值才可认为识别有效,大于阈值则返回-1
构造好LBPH人脸识别的对象,下面分别来看看训练和识别的函数:
LBPHRecog->train(trainPic, labels); //LBP人脸识别训练函数
训练函数参数中的trainPic是一个vector,所有需要训练的图片都被包含在内,labels也是vector,存储与trainPic中对应训练图片的名字,这样从trainPic中得到的与识别的图片最相似的图片的名字即可在labels中查找到。
result = LBPHRecog->predict(recogPic);//进行识别,并返回识别结果
返回的识别结果即是对应的labels中的名字。
二、代码实现
下面直接来看代码,程序会打开笔记本的摄像头,实现实时人脸识别,并将识别结果显示在画面上。//头文件 #include<opencv2/highgui/highgui.hpp> #include<opencv2/contrib/contrib.hpp> #include<opencv2/imgproc/imgproc.hpp> #include<opencv2/objdetect/objdetect.hpp> #include<iostream> #include<io.h> //命名空间 using namespace std; using namespace cv; CascadeClassifier faceDetect; //人脸检测对象 //函数声明 vector<Rect> FaceDetector(Mat img);//检测人脸,并返回人脸区域 void DrawFace(Mat img, vector<Rect> faces);//将人脸标注出来 void GetFilesName(string path, vector<string>& filesName);//获取文件夹里的所有文件名称 int main() { //变量 Mat frame; Mat src; Mat facePic; Mat recogPic; vector<Rect> faces; vector<string> filesName; string path = "..\\TrainPic"; string pic; vector<Mat> trainPic;//训练图片 vector<int> labels;//与训练图片一一对应的标签 int result; map<int, string> labelsInfo; faceDetect.load("../models/haarcascade_frontalface_alt2.xml"); Ptr<FaceRecognizer> LBPHRecog = createLBPHFaceRecognizer(1, 8 ,3, 3, 50);//构造LBPH人脸识别类的对象并初始化 //加载人脸库 GetFilesName(path, filesName); for(int i = 0; i<filesName.size(); i++) { pic = filesName[i]; src = imread(pic); cvtColor(src, src, CV_RGB2GRAY); trainPic.push_back(src); labelsInfo.insert(make_pair(i, filesName[i])); labels.push_back(i); } //LBPHRecog->setLabelsInfo(labelsInfo); LBPHRecog->train(trainPic, labels); //LBP人脸识别训练函数 VideoCapture cap(0);//打开摄像头 int c=0; if(!cap.isOpened()) { cerr<<"摄像头无法打开"<<endl; } while(c!= 27) { cap>>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<<t<<endl; DrawFace(frame, faces); for(size_t i = 0; i<faces.size(); i++) { facePic = frame(Rect(faces[i])); resize(facePic, recogPic, recogPic.size()); cvtColor(recogPic, recogPic, CV_RGB2GRAY); //equalizeHist(recogPic, recogPic); result = LBPHRecog->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<Rect> FaceDetector(Mat img) { Mat src = Mat::zeros(240, 320, img.type()); vector<Rect> 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.size(); i++) { faces[i].x=faces[i].x*2; faces[i].y=faces[i].y*2; faces[i].width=faces[i].width*2; faces[i].height=faces[i].height*2; } return faces; } void DrawFace(Mat img, vector<Rect> faces) { for(size_t num = 0; num<faces.size(); num++) { rectangle(img, Point(faces[num].x, faces[num].y), Point(faces[num].x + faces[num].width, faces[num].y + faces[num].height), Scalar(0, 255, 0), 1, 8); } } void GetFilesName(string path, vector<string>& 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); } }
注意:上述代码中人脸图片的训练部分并不具有通用性,需要根据实际运用进行修改,这部分就由读者自己来完成吧 :)
代码运行的结果图就不贴上去了,见谅~
相关文章推荐
- Linux下查看文件和文件夹大小(转)
- 常浏览的技术网站
- linux socket手册
- Linux下安装Mysql
- 第24讲 项目2:油量监控
- 在CentOS上安装rabbitmq-server
- linux开发环境基本配置
- linux高级权限(ACL与sudo)
- Mac OS CentOS下 dd命令行创建系统USB安装盘
- Linux-Centos7----安装Python的psutil模块插件
- linux文件权限
- 监控FTP服务状态,并自动重启servU
- Hadoop概述
- 鸟哥的Linux私房菜读书笔记-第11章-认识与学习bash
- opencv笔记 1.利用摄像头进行视频文件写入
- HBase基本概念和hbase shell常用命令用法
- P2V后LINUX系统开机处理方法
- 服务器端tomcat,debug调试
- Linux性能调优
- linux命令后台运行