您的位置:首页 > 移动开发 > IOS开发

【从零学习openCV】IOS7人脸识别实战

2014-06-01 11:44 330 查看
前言

接着上篇《IOS7下的人脸检测》,我们顺藤摸瓜的学习如何在IOS7下用openCV的进行人脸识别,实际上很简单,由于人脸检测部分已经完成,剩下的无非调用openCV的方法对采集到的人脸样本进行训练,最终得到一个可以预测人脸的模型。但是其中的原理可谓是博大精深,由于快临近期末考试了,没时间去琢磨其中具体的细节,这次就先写个大概的demo,下次更新文章就得到6月20号之后了。

原理:

从OpenCV2.4之后,openCV加入了新的类FaceRecognizer,我们可以使用它便捷地进行人脸识别。

目前FaceRecognizer类支持的人脸识别有三种,特征脸EigenFace、Fisher脸FisherFace、局部二元模式直方图LBPHFace。分别调用函数createEigenFaceRecognizer、createFisherFaceRecognizer、createLBPHFaceRecognizer建立模型,下面分别对三种方法做介绍。

EigenFace

顾明思议其实就是特征脸的方法,也称为基于主成分分析(principal component analysis,简称PCA)的人脸识别方法,至于什么是PCA及其原理可以看看这篇:特征脸(Eigenface)理论基础-PCA(主成分分析法)。特征子脸技术的基本思想是:从统计的观点,寻找人脸图像分布的基本元素,即人脸图像样本集协方差矩阵的特征向量,以此近似地表征人脸图像。这些特征向量称为特征脸(Eigenface)。

实际上,特征脸反映了隐含在人脸样本集合内部的信息和人脸的结构关系。将眼睛、面颊、下颌的样本集协方差矩阵的特征向量称为特征眼、特征颌和特征唇,统称特征子脸。特征子脸在相应的图像空间中生成子空间,称为子脸空间。计算出测试图像窗口在子脸空间的投影距离,若窗口图像满足阈值比较条件,则判断其为人脸。

基于特征分析的方法,也就是将人脸基准点的相对比率和其它描述人脸脸部特征的形状参数或类别参数等一起构成识别特征向量,这种基于整体脸的识别不仅保留了人脸部件之间的拓扑关系,而且也保留了各部件本身的信息,而基于部件的识别则是通过提取出局部轮廓信息及灰度信息来设计具体识别算法。现在Eigenface(PCA)算法已经与经典的模板匹配算法一起成为测试人脸识别系统性能的基准算法;而自1991年特征脸技术诞生以来,研究者对其进行了各种各样的实验和理论分析,FERET'96测试结果也表明,改进的特征脸算法是主流的人脸识别技术,也是具有最好性能的识别方法之一。

FisherFace

主成分分析是一种基于特征脸的方法,找到使数据中最大方差的特征线性组合。这是一个表现数据的强大方法,但它没有考虑类别信息,并且在扔掉主元时,同时许多有鉴别的信息都被扔掉。假设你数据库中的变化主要是光照变化,那么PCA此时几乎失效了。

线性鉴别分析在降维的同时考虑类别信息,由统计学家 Sir R. A. Fisher发明。其诉求是为了找到一种特征组合方式,达到最大的类间离散度和最小的类内离散度。这个想法很简单:在低维表示下,相同的类应该紧紧的聚在一起,而不同的类别尽量距离越远。 这也被Belhumeur, HespanhaKriegman所认同,所以他们把鉴别分析引入到人脸识别问题中。

LBPH

LBP的基本思想是对图像的像素和它局部周围像素进行对比后的结果进行求和。把这个像素作为中心,对相邻像素进行阈值比较。如果中心像素的亮度大于等于他的相邻像素,把他标记为1,否则标记为0。你会用二进制数字来表示每个像素,比如11001111。因此,由于周围相邻8个像素,你最终可能获取2^8个可能组合,被称为局部二值模式,有时被称为LBP码。

以上内容部分摘自于http://m.blog.csdn.net/blog/ningningxl/10903581,如果更深入地了解这三种算法,可以看看这篇文章。

案例实战

好了,直接进入正题,这里我采用openCV的createEigenFaceRecognizer方法,其他的两种方法大同小异。程序还是在上篇的基础上进行改动,请参看:【从零学习openCV】IOS7下的人脸检测

界面设计如下,应该很容易看出各个功能控件是干啥的吧 :-)



下面对每一个功能进行说明:

选择照片:这个请参考我之前的文章。

检测裁剪

代码如下,具体原理请看我上篇文章。

- (void) opencvFaceDetect  {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
UIImage* img = [image copy];
if(img) {
cvSetErrMode(CV_ErrModeParent);
IplImage *image = [self CreateIplImageFromUIImage:img];

IplImage *grayImg = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1); //先转为灰度图
cvCvtColor(image, grayImg, CV_BGR2GRAY);

//将输入图像缩小4倍以加快处理速度
int scale = 4;
IplImage *small_image = cvCreateImage(cvSize(image->width/scale,image->height/scale), IPL_DEPTH_8U, 1);
cvResize(grayImg, small_image);

//加载分类器
NSString *path = [[NSBundle mainBundle] pathForResource:@"haarcascade_frontalface_alt2" ofType:@"xml"];
CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad([path cStringUsingEncoding:NSASCIIStringEncoding], NULL, NULL, NULL);
CvMemStorage* storage = cvCreateMemStorage(0);
cvClearMemStorage(storage);

//关键部分,使用cvHaarDetectObjects进行检测,得到一系列方框
CvSeq* faces = cvHaarDetectObjects(small_image, cascade, storage ,1.1, (int)self.slider.value, CV_HAAR_DO_CANNY_PRUNING, cvSize(0,0), cvSize(0, 0));

NSLog(@"faces:%d",faces->total);
cvReleaseImage(&small_image);
cvReleaseImage(&grayImg);

if(faces->total>0)
{
CvRect cvrect = *(CvRect*)cvGetSeqElem(faces, 0);  //默认取第一张人脸
cvSetImageROI(image, cvRect(cvrect.x*scale, cvrect.y*scale , cvrect.width*scale, cvrect.height*scale));     //设置ROI,实现区域裁剪
RoIImg = cvCreateImage(cvSize(cvrect.width*scale,cvrect.height*scale), IPL_DEPTH_8U, 3);
cvCvtColor(image, RoIImg, CV_BGR2RGB);
cvResetImageROI(image);
self.imageView.image = [self UIImageFromIplImage:RoIImg];
}
cvReleaseImage(&image);
}

[pool release];
}


加入训练

得到了裁剪后的图片还需要对训练图片进行预处理,先转为灰度图,并且调整为同一大小(我设成了50*50),这些都是EigenFaceRecognizer的要求,最后进行归一化,防止光照带来的影响。

- (IBAction)addTrainClicked:(id)sender {
IplImage *grayImg = cvCreateImage(cvGetSize(RoIImg), IPL_DEPTH_8U, 1); //先转为灰度图
cvCvtColor(RoIImg, grayImg, CV_BGR2GRAY);
IplImage *small_image = cvCreateImage(cvSize(50,50), IPL_DEPTH_8U, 1); //统一大小
cvResize(grayImg, small_image);
cv::Mat cur_mat = cv::cvarrToMat(small_image,true),des_mat;
cv::normalize(cur_mat,des_mat,0, 255, cv::NORM_MINMAX, CV_8UC1);   //归一化
images.push_back(des_mat);
int labelnum = [self.labelEdit.text intValue];   //得到编辑框的数字,作为此图像的label
labels.push_back(labelnum);
self.addTrainBtn.enabled = NO;
}
生成模型

直接调用createEigenFaceRecognizer即可,选取PCA主成分维度为10

- (IBAction)GetModelClicked:(id)sender {
model = cv::createEigenFaceRecognizer(10);//PCA主成分的维数为10
model->train(images,labels);
NSLog(@"生成模型!");
}


人脸识别

点击预测按钮就可以用得到的模型对人脸图片进行预测了,注意打开一张照片后得先进行检测裁剪后才能预测。

- (IBAction)PredictClicked:(id)sender {
IplImage *grayImg = cvCreateImage(cvGetSize(RoIImg), IPL_DEPTH_8U, 1); //先转为灰度图
cvCvtColor(RoIImg, grayImg, CV_BGR2GRAY);
IplImage *small_image = cvCreateImage(cvSize(50,50), IPL_DEPTH_8U, 1); //统一大小
cvResize(grayImg, small_image);
cv::Mat cur_mat = cv::cvarrToMat(small_image,true),des_mat;
cv::normalize(cur_mat,des_mat,0, 255, cv::NORM_MINMAX, CV_8UC1);   //归一化
int pred = model->predict(des_mat);
NSString* tip = [NSString stringWithFormat:@"label:%d",pred];
UIAlertView *alter = [[UIAlertView alloc] initWithTitle:@"识别结果" message:tip delegate:nil cancelButtonTitle:@"我知道了" otherButtonTitles:nil];
[alter show];
NSLog(@"%d",pred);
}


最终效果:

步骤1:先对杨幂女神的三张写真进行检测裁剪,改训练label为1,点击加入训练按钮。






步骤2:再对诗诗女神的三张写真进行检测裁剪,改训练label为2,点击加入训练按钮。



步骤3:点击生成模型按钮。

步骤4:打开杨幂女神的另外一张照片,进行检测裁剪后,点击预测,识别结果为1,匹配正确。



步骤5:打开诗诗女神的另外一张照片,进行检测裁剪后,点击预测,识别结果为2,匹配正确。



可见openCV的特征脸算法能识别出美女之间的差异O(∩_∩)O

最后整个案例代码奉上,为期末考攒人品吧:IOS7下用openCV实现人脸检测加识别demo

(转载请注明作者和出处:Shawn-HT
http://blog.csdn.net/shawn_ht 未经允许请勿用于商业用途)

参考文章:

http://blog.csdn.net/liulina603/article/details/7925170

http://m.blog.csdn.net/blog/ningningxl/10903581

http://www.muxiaofei.com/class-facerecognizer-on-the-opencv-face-recognition-face-recognition/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息