C++开发人脸性别识别教程(4)——OpenCv的人脸检测函数

  这个项目主要包含三部分:人脸检测、特征提取、性别分类:

  这篇博客中我们重点介绍OpenCv的人脸检测函数。这篇博客我们先不提MFC,而是在win32控制台下编写一段人脸检测的程序。

  一、开启摄像头

  我们先讲解如何通过摄像头来采集图像,这听起来更有实际意义。

  1、新建工程并配置OpenCv(注意工程类型选择win32控制台应用程序):

  2、包含头文件

  OpenCv2.x版本包含头文件非常方便,一句话搞定:

#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;

  谈到包含头文件,这里有一个地方需要详细说一下,就是OpenCv2.x之所以操作简洁,是因为其将各个模块的头文件全部置于“opencv.hpp”这个文件中了,右键打开opencv.hpp文档,你会发现如下内容:

  3、初始化一个摄像头捕捉器

  首先,需要建立一个摄像头捕捉器,并将其与当前设备中的摄像头相关联:

    /***********初始化一个摄像头捕捉器***********/
    CvCapture* capture = cvCreateCameraCapture(0);
    cvNamedWindow("Camera");

  注意以"cv"开头的结构体和函数名都是隶属于OpenCv1.x版本中的内容,不过OpenCv2.x是完全兼容1.x版本的,而且貌似在2.x版本并未对摄像头相关函数进行重写,因此这里暂且延用1.x中的代码。

  4、调用摄像头步骤画面并显示

  首先,给出代码,稍后解释:

    IplImage* cameraImage = NULL;
    while ((cameraImage = cvQueryFrame(capture)) != NULL)
    {
        cvShowImage("Camera",cameraImage);
        cvWaitKey(1);
    }

  显然cvQueryFrame()函数的作用是在当前的时间点从摄像头抓取的视频流中截出一帧,这里将其赋值给变量camearImage(IplImage*类型,因为这是1.0的代码),若其非空,则显示在屏幕上。注意这里必须添加延时函数cvWaitKey(单位是毫秒),哪怕只延时一毫秒否则将无法正常显示摄像头输出。

  按下Ctrl+F5,程序正常运行:

  二、人脸检测

  OpenCv2.x版本中封装的人脸检测函数基于AdaBoost(级联分类器)人脸检测算法,当然这里我们无需深入了解算法相关的知识,因为Intel已经将需要用到的、训练好的人脸检测器(分类器)放在了安装文件里:

  1、准备工作

  调用人脸检测函数前需要做一些准备工作,分别是初始化所需内存、初始化检测器指针、设置检测器路径:

static CvMemStorage* storage            = NULL;
static CvHaarClassifierCascade* cascade = NULL;
const char* cascadePath                 = "D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt_tree.xml";

  这里有两个问题需要强调:

  (1)从路径中可以看出,检测器位于安装目录下的source文件夹下的data文件夹下的haarcascades文件夹中。

  (2)在C++表示路径是要用双斜杠,因为第一个斜杠会默认为是转义字符,对第二个斜杠进行转义。

  (3)这三个变量均为全局变量。

  2、图像灰度化

  由于这里用到的人脸检测函数主要针对于灰度图像,因此需要将摄像头采集的彩色图像灰度化:

        /**********灰度化***********/
        IplImage* grayImage = cvCreateImage(cvSize(cameraImage->width,cameraImage->height),8,1);
        cvCvtColor(cameraImage,grayImage,CV_BGR2GRAY);

  这里涉及到如何通过cvCreatImage创建一个空的8位无符号整型单通道图,即需要通过一个cvSize结构体来指定图像初始的尺寸,这点在opencv2.x得到了很大改良(Mat类的加入)。

  3、调用人脸检测函数

  首先,创建一块内存区域,并加载相应的检测器(这个在主循环外完成即可):

    storage = cvCreateMemStorage(0);
    cascade = (CvHaarClassifierCascade*)cvLoad(cascadePath);

  然后,清空指定位置内存块,调用人脸检测函数:

        /**********人脸检测***********/
        cvClearMemStorage(storage);
        CvSeq* objects = cvHaarDetectObjects(grayImage,cascade,storage,1.1,2,0,cvSize(30,30));

  cvhaardetectobjects函数的参数较为复杂,具体参数设置参见:cvhaardetectobjects参数设置。我们这里需要了解的就是这个函数的返回参数是一系列检测结果序列,每个检测结果实际上就是一个矩形结构体对象。

  4、绘制人脸区域矩形框

  接下来一一绘制检测到的矩形结果:

        /**********绘制检测结果***********/
        for (int i = 0; i < (objects ? objects->total : 0); i++)
        {
            CvRect* rect = (CvRect*)cvGetSeqElem(objects,i);
            cvRectangle(cameraImage,cvPoint(rect->x,rect->y),cvPoint(rect->x + rect->width,rect->y + rect->height),cvScalar(0.0,255));
        }
        cvShowImage("Camera",cameraImage);

  注意这里需要把之前测试摄像头程序中的图片显示语句注释掉,否则前后在显示图像时会发生覆盖,不能正常看到图像的检测结果:

  5、总程序

  这里给出摄像头人脸检测的总程序:

// Camera.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2\opencv.hpp>

using namespace cv;
using namespace std;

static CvMemStorage* storage            = NULL;
static CvHaarClassifierCascade* cascade = NULL;
const char* cascadePath                 = "D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt_tree.xml";

int _tmain(int argc, _TCHAR* argv[])
{
    /***********初始化一个摄像头捕捉器***********/
    CvCapture* capture = cvCreateCameraCapture(0);
    cvNamedWindow("Camera");

    /***********初始化人脸检测相关变量***********/
    IplImage* cameraImage = NULL;
    storage = cvCreateMemStorage(0);
    cascade = (CvHaarClassifierCascade*)cvLoad(cascadePath);

    while ((cameraImage = cvQueryFrame(capture)) != NULL)
    {
        //cvShowImage("Camera",cameraImage);
        cvWaitKey(1);

        /**********灰度化***********/
        IplImage* grayImage = cvCreateImage(cvSize(cameraImage->width,cameraImage->height),8,1);
        cvCvtColor(cameraImage,grayImage,CV_BGR2GRAY);

        /**********人脸检测***********/
        cvClearMemStorage(storage);
        CvSeq* objects = cvHaarDetectObjects(grayImage,cascade,storage,1.1,2,0,cvSize(30,30));

        /**********绘制检测结果***********/
        for (int i = 0; i < (objects ? objects->total : 0); i++)
        {
            CvRect* rect = (CvRect*)cvGetSeqElem(objects,i);
            cvRectangle(cameraImage,cvPoint(rect->x,rect->y),cvPoint(rect->x + rect->width,rect->y + rect->height),cvScalar(0.0,255));
        }
        cvShowImage("Camera",cameraImage);
    }
    return 0;
}
时间: 2024-08-08 05:36:23

C++开发人脸性别识别教程(4)——OpenCv的人脸检测函数的相关文章

C++开发人脸性别识别教程(18)——辅助功能之文件名批量修改、方法验证

时光推移了30多天,这个人脸性别识别的小项目也接近尾声了,预计再通过三篇博文的篇幅来完成这个项目的收尾工作.在这篇博文中我们再为程序添加另外两个小的辅助功能:文件名批量修改.方法验证. 一 文件名批量修改 批量修改文件名是一件很基础也很常用的小操作,核心操作就是图像文件的批量读取.批量改名.批量保存.基本思想就是把文件读出来,然后在保存回去(注意不要和别的文件发生覆盖),从这个角度来讲文件名批量修改与上一篇博客C++开发人脸性别识别教程(17)——辅助功能之人脸批量分割中的人脸批量分割简直如出一

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

经过之前几篇博客的讲解,我们已经成功搭建了MFC应用框架,并实现了基本的图像显示和人脸检测程序,在这篇博文中我们要向其中添加性别识别代码. 关于性别识别,之前已经专门拿出两篇博客的篇幅来进行讲解,这里不再赘述,具体参见:C++开发人脸性别识别教程(5)——通过FaceRecognizer类实现性别识别和C++开发人脸性别识别教程(6)——通过SVM实现性别识别. 一.分类器训练 在进行人脸性别识别之前需要训练性别识别的分类器,而分类器的训练过程是相对耗时的(大约五分钟),因此这里我们采用离线训练

C++开发人脸性别识别教程(13)——针对单张图片的性别识别

在之前的博文中我们的性别识别程序已经初步成型,能够识别某个文件夹下的图片文件.不过这里有一个问题,假设这个文件夹下有着大量的图片,而我们希望识别这些图片中的某一张,此时需要我们不停的单击“下一张”按钮才会轮询到对应的图片,这是相当麻烦的,因此在这篇博客中我们向程序中添加一个功能——单张图片的性别识别. 一.基本思想 最基本的办法就是在主界面再添加一个按钮控件,命名为“图片文件”(之前的按钮为“图片文件夹”),不过这样会使得界面上的按钮控件过于繁多,给人一种“作者只会用button控件”的感觉.这

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

原文地址:http://blog.csdn.net/u013088062/article/details/50435079 OpenCv是C++图像处理的重要工具,这个人脸性别识别的项目就是借助OpenCv进行开发的.虽然网上已经有了很多关于OpenCv的配置教程,但出于教程完整性考虑,这里还是用专门的一篇博客来介绍OpenCv的具体配置方法,同时也介绍一下OpenCv中的一个强有力的图像处理插件——ImageWatch. 由于这个程序是一年前写的,当时的OpenCv的最新版本为2.4.9(现在

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

OpenCv是C++图像处理的重要工具.这个人脸性别识别的项目就是借助OpenCv进行开发的. 尽管网上已经有了非常多关于OpenCv的配置教程,但出于教程完整性考虑.这里还是用专门的一篇博客来介绍OpenCv的详细配置方法,同一时候也介绍一下OpenCv中的一个强有力的图像处理插件--ImageWatch. 因为这个程序是一年前写的.当时的OpenCv的最新版本号为2.4.9(如今已经更新到了3.0),而且2.4.9版本号和3.0版本号在配置方法上稍有不同,这里我仍以2.4.9版本号为例来介绍

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

在之前的博文中我们已经能够顺利驱动摄像头来采集源图像,在这篇博文中将正式为其加入性别识别的代码,实现摄像头视频的人脸性别识别. 一.人脸检测 在得到摄像头采集的源图像之后,首先要做的就是对其进行人脸检测,将人脸区域分割出来.这步相对来说比较简单,只需在定时器时间触发函数中加入人脸检测的代码即可,这里给出OnTimer()函数的整体代码: void CGenderRecognitionMFCDlg::OnTimer(UINT_PTR nIDEvent) { /***********人脸检测并识别*

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

上一篇教程中我们介绍了怎样使用OpenCv封装的FaceRecognizer类实现简单的人脸性别识别,这里我们为大家提供第二种主要的性别识别手段--支持向量机(SVM). 支持向量机在解决二分类问题方面有着强大的威力(当然也能够解决多分类问题).性别识别是典型的二分类模式识别问题,因此非常适合用SVM进行处理,同一时候OpenCv又对SVM进行了非常好的封装,调用非常方便,因此我们在这个性别识别程序中考虑增加SVM方法. 在这里我们採用了HOG+SVM的模式来进行,即先提取图像的HOG特征.然后

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

原文地址:http://blog.csdn.net/u013088062/article/details/50480518 上一篇教程中我们介绍了如何使用OpenCv封装的FaceRecognizer类实现简单的人脸性别识别,这里我们为大家提供另外一种基本的性别识别手段——支持向量机(SVM). 支持向量机在解决二分类问题方面有着强大的威力(当然也可以解决多分类问题),性别识别是典型的二分类模式识别问题,因此很适合用SVM进行处理,同时OpenCv又对SVM进行了很好的封装,调用非常方便,因此我

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

在之前的博客中已经解决了人脸检测的问题,我们计划在这篇博客中介绍人脸识别.性别识别方面的相关实现方法. 其实性别识别和人脸识别本质上是相似的,因为这里只是一个简单的MFC开发,主要工作并不在算法研究上,因此我们直接将性别识别视为一种特殊的人脸识别模式.人脸识别可能需要分为几十甚至上百个类(因为有几十甚至上百个人),而性别识别则是一种特殊的人脸识别——只有两个类. 一.基本工具 通过OpenCv进行性别识别的基本工具是FaceRecognizer.这是OpenCv2.x版本中的一个基本的人脸识别类