【从零学习openCV】IOS7下的人脸检测
前言:
人脸检测与识别一直是计算机视觉领域一大热门研究方向,而且也从安全监控等工业级的应用扩展到了手机移动端的app,总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,目前在学习openCV,自然不能放过这个领域,于是稍微了解了下openCV下人脸检测的一些原理,为之后的人脸识别等研究做个小小的铺垫。
原理:
人脸检测属于目标检测(object detection) 的一部分,主要涉及两个方面
- 先对要检测的目标对象进行概率统计,从而知道待检测对象的一些特征,建立起目标检测模型。
- 用得到的模型来匹配输入的图像,如果有匹配则输出匹配的区域
好吧,这样说有点抽象,接下来我们来看看openCV常用的haar人脸检测是怎么回事吧
Haar特征
首先,什么是Haar呢?说白了,haar就是一种基于“块”的特征,它最早是由Papageorigiou等人用于人脸描述。目前常用的Haar-like特征可以分为三类:线性特征、边缘特征、点特征(中心特征)、对角线特征。如下图所示:
显然,边缘特征有4种:x方向,y方向,x倾斜方向,y倾斜方向;线特征有8种,点特征有2种,对角线特征有1种。每一种特征的计算都是由黑色填充区域的像素值之和与白色填充区域的像素值之和的差值。而计算出来的这个差值就是所谓的Haar-like特征的特征值。
Haar特征是基于"块"的特征,能够降低计算成本。但是对于一张24*24的图片能够提取的haar特征量非常巨大,大概有16万之多。如何从这么多的特征中提取出对人脸识别真正有用的特征是一个非常重要的问题,于是就要使用到Adaboosting算法。
Adaboosting算法
AdaBoost算法是一种迭代的算法,对于一组训练集,通过改变其中每个样本的分布概率,而得到不同的训练集Si,对于每一个Si进行训练从而得到一个弱分类器Hi,再将这些若分类器根据不同的权值组合起来,就得到了强分类器。
第一次的时候,每个样本都是均匀分布,通过训练得到分类器H0,在该训练集中,分类正确的,就降低其分布概率;分类错误的,就提高其分布概率,这样得到的新的训练集S1就主要是针对不太好分类的样本了。再使用S1进行训练,得到分类器H1,依次迭代下去……,设迭代此外为T,则得到T个分类器。对于每个分类器的权值,其分类准确性越高,权值越高。
前面说到,一张24*24的图片,能提取到16W多的haar特征,一个弱分类器,实际上就是在这16W多的特征中选取一个特征,用这个特征能够区分出人脸or非人脸,且错误率最低。
比如现在有人脸样本2000张,非人脸样本4000张,这些样本都经过了归一化,大小都是24X24的图像。那么,对于16W中的任一特征fi,我们计算该特征在这2000人脸样本、4000非人脸样本上的值,这样就得到6000个特征值。将这些特征值排序,然后选取一个最佳的特征值,在该特征值下,对于特征fi来说,样本的加权错误率最低。选择所有特征中,错误率最低的特征,用来判断人脸,这就是一个弱分类器,同时用此分类器对样本进行分类,并更新样本的权重。
具体实施过程如下,内容均摘自DylanTsou的博客
窗口扫描检测
得到了分类器后就可以对图像进行人脸检测了,由于输入的图像往往与分类器训练的图像大小不一致(一般更大),于是我们需要一个能够滑动的窗口在输入图像上不断移动进行扫描,如果我们训练的图像就是24*24的,滑动窗口就是一个24*24 window,使用这个window扫描一张大图上所有位置,在每个位置上都使用训练好的分类器回答是不是人脸的问题。扫描结束之后需要一些重叠的窗口合并(在同一张人脸附近可能有很多个临近窗口都被判断为包含人脸)。
为了能够提高扫描速度可以使用了逐级删选的方案,就是先开始使用计算成本低的分类器海选(这样的分类器包含较少的特征),海选过程中标准较低,尽可能将所有的人脸都删选进来,低标准导致很多非人脸也被选进来。然后逐渐提高分类器的标准(也就是说使用包含更多特征的分类器,同时增加了计算成本)这样的逐级删选能够降低计算成本。
最后还有一个问题: 在一张照片中人脸的大小各有差别不一定就和训练图片大小相同。解决这个问题的方法是使用不同大小的窗口来检测人脸, 这时候若分类器中的阈值需要随着窗口面积做等比例的变化。
使用openCV进行人脸检测
好了,经过前面的介绍,对人脸检测的原理应该有了大体的了解,其实用openCV实现人脸检测十分简单。
首先OpenCV自带了人脸的Haar特征分类器。OpenCV安装目录中的\data\ haarcascades目录下的haarcascade_frontalface_alt.xml与haarcascade_frontalface_alt2.xml都是用来检测人脸的Haar分类器。这个haarcascades目录下还有人的全身,眼睛,嘴唇的Haar分类器。
使用人脸的Haar特征分类器非常之简单,直接使用cvHaarDetectObjects。下面来看看这个函数的介绍:
函数功能:检测图像中的目录
函数原型:
CVAPI(CvSeq*) cvHaarDetectObjects(
const CvArr* image,
CvHaarClassifierCascade* cascade,
CvMemStorage* storage,
double scale_factor CV_DEFAULT(1.1),
int min_neighbors CV_DEFAULT(3),
int flags CV_DEFAULT(0),
CvSize min_size CV_DEFAULT(cvSize(0,0)),
CvSize max_size CV_DEFAULT(cvSize(0,0))
);
参数说明:
const CvArr* image:表示输入图像,使用灰度图可以去除一些噪声,并且加快检测速度。
CvHaarClassifierCascade* cascade:表示Haar特征分类器,可以用cvLoad()函数来从磁盘中加载xml文件作为Haar特征分类器。
CvMemStorage* storage:表示内存存储器,用来统一管理各种动态对象的内存。
double scale_factor:表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%
int min_neighbors:表示构成检测目标的相邻矩形的最小个数(默认为3个)。如果组成检测目标的小矩形的个数和小于 min_neighbors - 1 都会被排除。如果min_neighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框,这种设定值一般用在用户自定义对检测结果的组合程序上。
int flags:要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域,因此这些区域通常不会是人脸所在区域。
CvSize min_size、max_size:表示检测窗口的最小值和最大值,一般设置为默认即可。
函数返回值:
函数将返回CvSeq对象,该对象包含一系列CvRect表示检测到的人脸矩形。
案例实战——IOS7人脸检测应用
终于进入正题了,这次的案例是在上篇的基础上稍加修改的,关于如何在Xcode下配置openCV以及UIImage与cv:Mat和IplImage之间的转化我就不赘述了,具体请参看【从零学习openCV】IOS7下的openCV开发起步(Xcode5.1.1&openCV2.49)
首先我们先将haarcascade_frontalface_alt2.xml导入工程目录
将main.storyboard下的布局改成如下形式:
好了,废话不多说,直接上代码:
- (void) opencvFaceDetect {NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];UIImage* img = [image copy];if(img) {[self.view bringSubviewToFront:self.indicator];[self.indicator startAnimating]; //由于人脸检测比较耗时,于是使用加载指示器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, currentvalue, CV_HAAR_DO_CANNY_PRUNING, cvSize(0,0), cvSize(0, 0));NSLog(@"faces:%d",faces->total);cvReleaseImage(&small_image);cvReleaseImage(&image);cvReleaseImage(&grayImg);//创建画布将人脸部分标记出CGImageRef imageRef = img.CGImage;CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();CGContextRef contextRef = CGBitmapContextCreate(NULL, img.size.width, img.size.height,8, img.size.width * 4,colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrderDefault);CGContextDrawImage(contextRef, CGRectMake(0, 0, img.size.width, img.size.height), imageRef);CGContextSetLineWidth(contextRef, 4);CGContextSetRGBStrokeColor(contextRef, 1.0, 0.0, 0.0, 1);//对人脸进行标记,如果isDoge为Yes则在人脸上贴图for(int i = 0; i < faces->total; i++) {NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];// Calc the rect of facesCvRect cvrect = *(CvRect*)cvGetSeqElem(faces, i);CGRect face_rect = CGContextConvertRectToDeviceSpace(contextRef, CGRectMake(cvrect.x*scale, cvrect.y*scale , cvrect.width*scale, cvrect.height*scale));if(isDoge) {CGContextDrawImage(contextRef, face_rect, [UIImage imageNamed:@"doge.png"].CGImage);} else {CGContextStrokeRect(contextRef, face_rect);}[pool release];}self.imageView.image = [UIImage imageWithCGImage:CGBitmapContextCreateImage(contextRef)];CGContextRelease(contextRef);CGColorSpaceRelease(colorSpace);cvReleaseMemStorage(&storage);cvReleaseHaarClassifierCascade(&cascade);}[pool release];[self.indicator stopAnimating];
}
上面这个函数就是整个人脸检测的核心了,思路很简单,先将原图像转为灰度图,并且缩小4倍,这样处理的速度能够大大加快,然后就是加载haar分类器,调用cvHaarDetectObjects函数进行检测得到一系列的人脸框(cvRect),最后就是在原图像上把cvRect的地方画出来。
由于整个检测过程相对比较耗时,尤其是图像像素特别大的时候,甚至需要好几秒的时间,所以应该单开线程来调用opencvFaceDetect方法,并且最后用指示器来表示图像正在处理中。
- (IBAction)FaceDetectClicked:(id)sender {[self.view bringSubviewToFront:self.indicator];[self.indicator startAnimating];[NSThread detachNewThreadSelector:@selector(opencvFaceDetect) toTarget:self withObject:nil];
}
最终效果如下:
最近迷上了doge啊,女神不要怪我。。
老规矩,整个案例的工程代码附上:IOS7下openCV人脸检测demo
(转载请注明作者和出处:Shawn-HT http://blog.csdn.net/shawn_ht 未经允许请勿用于商业用途)
参考文章:
http://www.iteye.com/topic/463668
http://www.douban.com/note/61620214/
http://www.cnblogs.com/dylantsou/archive/2012/08/11/2633483.html
http://blog.csdn.net/morewindows/article/details/8239678
【从零学习openCV】IOS7下的人脸检测相关推荐
- 【从零学习openCV】IOS7下的人脸检測
前言: 人脸检測与识别一直是计算机视觉领域一大热门研究方向,并且也从安全监控等工业级的应用扩展到了手机移动端的app,总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,眼下在学习ope ...
- 【从零学习openCV】IOS7根据人脸检测
前言: 人脸检測与识别一直是计算机视觉领域一大热门研究方向,并且也从安全监控等工业级的应用扩展到了手机移动端的app.总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,眼下在学习ope ...
- 【从零学习OpenCV 4】4种读取Mat类元素的的方法
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
- 【从零学习OpenCV 4】Mat类构造与赋值
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
- 【从零学习OpenCV 4】Mat类介绍
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
- 【从零学习OpenCV 4】安装过程中问题解决方案
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
- 【从零学习OpenCV 4】了解OpenCV的模块架构
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
- 【从零学习OpenCV 4】Image Watch插件的使用
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
- 【从零学习OpenCV 4】opencv_contrib扩展模块的安装
本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门 ...
最新文章
- 五行塔怎么吃第五个_红毛丹怎么吃 吃红毛丹的五个好处
- 通过踩坑带你读透虚拟机的“锁粗化”
- C#期末考试题,图书系统
- 线程故事:Web应用程序中的ThreadLocal
- Flume架构以及应用介绍[转]
- Excel的裁剪(trimming)(トリミング)功能使用介绍
- 转载:PostgreSQL 读懂执行计划
- win7 与xp 互联步骤
- 深圳计算机免考申请在哪,深圳自考申请免考要什么条件
- 电子专业的学生必看的文章
- java jsp实现网站访问量的统计
- 【软件工程】课程管理系统需求分析规格说明
- crc16-ccitt算法c语言,CRC-CCITT 标准CRC16(1021) 算法校验类
- Li feifei How we're teaching computers to understand pictures
- Node.js + Web Socket 打造即时聊天程序嗨聊(上)
- 【蓝桥杯真题】成绩统计
- 知行合一(科学实践理论)
- WebRTC[53] - WebRTC回声问题定位的一般方法
- 后渗透篇:劫持技术(lpk.dll劫持游戏注入【Win7 实例】)
- esp32之wifi状态机
热门文章
- Excel中IF函数的使用
- python学习——HTMLParser
- 全国计算机二级下次报名时间,全国计算机二级考试报名时间
- java的“看门狗”锁续期可以用php redis这样实现【php锁续期、分布式锁、无锁请求队列超卖】解决【商家超卖(商品库存控制)、用户超买(秒杀订单控制)】问题。非demo 线上一直在用
- java导出word表格 行列合并
- pyopenpose文档
- 真的有这么丝滑:3D头发建模新方法NeuralHDHair,浙大、ETH Zurich、CityU联合出品...
- Excel表格 |两列数据(多列)合并一列且自动换行
- 可兼容CS4344的国产音频数模转换电路,目前已广泛应用于数字通信、DVD音频、汽车音响系统
- ICIAR2018数据集下载