现在我们的MFC框架已经初具规模,能够读取并显示目录下的图片。在这篇博文中我们将向当中加入人脸检測的程序。

  一、人脸检測算法

  这里我们使用OpenCv封装的Adaboost方法来进行人脸检測,參见:C++开发人脸性别识别教程(4)——OpenCv的人脸检測函数

  二、初始化

  1、加入初始化button

  在进行人脸检測之前须要初始化一些相关变量。比如开辟内存,载入检測器等等。首先,我们为MFC框架加入一个初始化button。并将ID更改为IDC_BUTTON_INITIAL:

  双击这个button。加入事件响应函数:

  2、初始化变量

  从之前的博客中可知。OpenCv在进行人脸检測时须要用到两个静态变量:static CvMemStorage* storage和static CvHaarClassifierCascade* cascade。这里我们将其作为成员变量加入到CGenderRecognitionMFCDlg类中。这里因为static CvMemStorage*和static CvHaarClassifierCascade*这两个类型名在MFC类向导中是无法被识别的,因此须要手动加入至CGenderRecognitionMFCDlg类的构造函数中:

  接下里对这两个惊天变量进行初始化。

C++明白规定静态成员变量要在类外进行初始化,而不能在类内声明时或者构造函数内进行初始化,原因就是静态变量时属于类本身的,而非类对象的属性,和全局变量相似,因此我们将这两个静态变量的初始化操作放在GenderRecognitionMFCDlg.cpp文件(从解决方式资源管理器窗体中查找cpp文件)的开头位置:

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
CvMemStorage* CGenderRecognitionMFCDlg::storage = NULL;
CvHaarClassifierCascade* CGenderRecognitionMFCDlg::cascade = NULL;

  然后在“初始化”button的响应函数OnBnClickedButtonInitial()中载入相应的人脸检測器:

void CGenderRecognitionMFCDlg::OnBnClickedButtonInitial()
{
cascade = cvLoadHaarClassifierCascade("D:\\opencv\\sources\\data\\haarcascades
\\haarcascade_frontalface_alt_tree.xml",cvSize(30,30));
storage = cvCreateMemStorage(0);
// TODO: 在此加入控件通知处理程序代码
}

  初始化完毕。

  三、编写人脸检測函数  

  这里将人脸检測的操作封装成一个函数detect_and_draw(),作为成员函数加入到CGenderRecognitionMFCDlg类中:

  在类视图中找到detect_and_draw()函数。完好其人脸检測代码,因为之前已经具体介绍过人脸检測的相关操作。这里直接给出代码:

void CGenderRecognitionMFCDlg::detect_and_draw(IplImage* img)
{
/**********初始化**********/
double scale = 1.2;
IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1); /**********灰度化**********/
if (img->nChannels = 3)
{
cvCvtColor(img,gray, CV_BGR2GRAY);//将图像灰度化存放在gray中
}
else
{
gray = img;
} /**********直方图均衡**********/
cvEqualizeHist(gray,gray); /**********人脸检測**********/
cvClearMemStorage(storage);
CvSeq* objects = cvHaarDetectObjects(gray,//待检測图像
cascade, //分类器标识
storage, //存储检測到的候选矩形
1.3, //相邻两次检測中窗体扩大的比例
3, //觉得是人脸的最小矩形数(阈值)
0, //CV_HAAR_DO_CANNY_PRUNING
cvSize(30,30)); //初始检測窗体大小 /**********绘制检測结果**********/
if(objects->total > 0) //假设人脸检測成功
{
for (int i = 0; i < (objects ? objects->total : 0); i++)
{
CvRect* rect = (CvRect*)cvGetSeqElem(objects,i);
cvRectangle(img,cvPoint(rect->x,rect->y),
cvPoint(rect->x + rect->width,rect->y + rect->height),cvScalar(0.0,255));
}
} /**********在图像控件上显示图像**********/
CvvImage cvvImage;
cvvImage.CopyOf(img);
cvvImage.DrawToHDC(m_pPicCtlHdc,m_PicCtlRect); cvReleaseImage(&gray);
}

  注意这里相对于之前的程序,加入了一项直方图均衡化的操作。以提高人脸检測的成功率:

  四、调用人脸检測函数

  理论上在显示图像之前应该自己主动调用人脸检測操作,因此在GetNextBigImg()函数中调用人脸检測函数:

  因为在detect_and_draw()函数中已经封装了picture显示的程序。所以能够将GetNextBigImg()函数中原有的picture控件显示程序去掉。

  大功告成。顺利完毕人脸检測:

  三、总结

  这里我们初步完毕了MFC中的人脸检測功能。但这里存在两个严重的BUG,一是假设用户未单击“初始化”button,直接打开图片,程序会因缺少必要的初始化步骤而直接崩溃;二是如上图所见,OpenCv在进行人脸检測时可能会错误检測出多个矩形。当中仅仅有一个矩形包括人脸,其余的都是干扰,须要进行处理,我们将在下一篇博客中介绍怎样解决这两个BUG。

  同一时候在此须要强调一下两个问题:

  1、静态成员变量的初始化:c++中能够对类中私有成员中的静态变量初始化吗?

  2、字符串的连接:C++字符换行 .

C++开发人脸性别识别教程(10)——加入图片的人脸检測程序的更多相关文章

  1. C++开发人脸性别识别教程(16)——视频人脸性别识别

    在之前的博文中我们已经可以顺利驱动摄像头来採集源图像.在这篇博文中将正式为其加入性别识别的代码,实现摄像头视频的人脸性别识别. 一.人脸检測 在得到摄像头採集的源图像之后,首先要做的就是对其进行人脸检 ...

  2. C++开发人脸性别识别教程(19)——界面美化

    在这篇博文中将完毕<C++开发人脸性别识别>的收尾工作.主要内容分为两部分:加入视频暂定功能.界面规范化. 一 视频暂停功能 严格来说这个视频暂定功能算是视频人脸性别识别的一个遗留问题,本 ...

  3. C++开发人脸性别识别教程(12)——加入性别识别功能

    经过之前几篇博客的解说,我们已经成功搭建了MFC应用框架,并实现了主要的图像显示和人脸检測程序,在这篇博文中我们要向当中加入性别识别代码. 关于性别识别,之前已经专门拿出两篇博客的篇幅来进行解说.这里 ...

  4. C++开发人脸性别识别教程(3)——OpenCv配置和ImageWatch插件介绍

    OpenCv是C++图像处理的重要工具.这个人脸性别识别的项目就是借助OpenCv进行开发的. 尽管网上已经有了非常多关于OpenCv的配置教程,但出于教程完整性考虑.这里还是用专门的一篇博客来介绍O ...

  5. C++开发人脸性别识别教程(5)——通过FaceRecognizer类实现性别识别

    在之前的博客中已经攻克了人脸检測的问题,我们计划在这篇博客中介绍人脸识别.性别识别方面的相关实现方法. 事实上性别识别和人脸识别本质上是相似的,由于这里仅仅是一个简单的MFC开发,主要工作并不在算法研 ...

  6. C++开发人脸性别识别教程(7)——搭建MFC框架之界面绘制

    在之前的博客中我们已经将项目中用到的算法表述完成,包含人脸检測算法以及四种性别识别算法,在这篇博客中我们将着手搭建主要的MFC框架. 一.框架概况 在这篇博文中我们将搭建最主要的MFC框架.绘制MFC ...

  7. C++开发人脸性别识别教程(9)——搭建MFC框架之显示图片

    在之前的博客中我们已经实现读取用户选定的目录.并将其路径保存在对应的变量中.在这篇博文中我们将介绍怎样借助CvvImage类将图片显示在picture控件中,并自己主动读取目录下的其它图片. 一.加入 ...

  8. C++开发人脸性别识别教程(6)——通过SVM实现性别识别

    http://blog.csdn.net/u013088062/article/details/50480518

  9. C++开发人脸性别识别教程(8)——搭建MFC框架之读取目录信息

    在上一篇博客中我们已经绘制了MFC界面,在这篇博客中我们将加入响应代码,为MFC框架加入一个最主要的功能:打开一个目录. 一.加入相关头文件 这里头文件主要包括三类:opencv头文件.批量读取文件相 ...

随机推荐

  1. 微信小程序从零开始开发步骤(六)4种页面跳转的方法

    用法:用于页面跳转,相当于html里面的<a></a>标签. API教程:https://mp.weixin.qq.com/debug/wxadoc/dev/component ...

  2. 【习题 8-3 UVA - 12545】Bits Equalizer

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 如果1的个数第一个串比第2个串多. 那么就无解. 否则. 找几个位置去凑1 优先找'?'然后才是0的位置 剩余的全都用swap操作就 ...

  3. 联合体union用在何处?

    程序设计刚開始学习的人在学习时,总想问:"这个东东有什么用?"于是,在建设有关的教学资源时,也便总从这个角度,试图给出一些案例,这是一个将刚開始学习的人作为教学目标人群的人该干的事 ...

  4. 存储控制器和SDRAM 实验

    S3C2440 存储控制器(memory controller)提供了訪问外部设备所需的信号,这是一种通过总线形式来訪问扩展的外设. S3C2440  的存储器控制器有下面的特性: 支持小字节序.大字 ...

  5. Atcoder AtCoder Regular Contest 079 E - Decrease (Judge ver.)

    E - Decrease (Judge ver.) Time limit : 2sec / Memory limit : 256MB Score : 600 points Problem Statem ...

  6. silverlight依据json字符串动态创建实体类

    1.接收json字符串: //用JsonValue转换json字符串是为了之后获得json字符串的每行数据和每一列的列名 JsonValue jv = JsonValue.Parse(json);   ...

  7. System.out.println 的多线程并发问题

    假设println函数的參数为常量则不会出现线程并发问题,可是假设參数为表达式形式.则JVM在运行println函数的时候会分为几步来运行,从而造成并发问题. 例如以下样例所看到的: package ...

  8. solr/lucence和关系数据库的混合使用

    我们知道solr提供了一个DIHandler,提供将关系数据库中的数据导成索引,然后使用solr查询. 对于一个大表中关联数个小表的查询,这非常耗费时间. 我的思路是: 1. 将一个大表做成索引,使用 ...

  9. jsonp跨域实例丨利用百度数据制作搜索页面

    <!DOCTYPE html><html>    <head>        <meta charset="UTF-8">      ...

  10. 1.1selenium 介绍

    1.1selenium 介绍selenium 是一个 web 的自动化测试工具,不少学习功能自动化的同学开始首选 selenium , 相因为它相比 QTP 有诸多有点:* 免费,也不用再为破解 QT ...