opencv人脸检测_Haar特征分类器实现人脸检测_cascade.detectMultiScale参数详解

原帖地址:

1. 概述

CascadeClassifier为OpenCV中cv namespace下用来做目标检测的级联分类器的一个类。该类中封装的目标检测机制,简而言之是滑动窗口机制+级联分类器的方式

2. 支持的特征

对于Haar、LBP和HOG,CascadeClassifier都有自己想对他们说的话:

1) Haar:因为之前从OpenCV1.0以来,一直都是只有用haar特征的级联分类器训练和检测(当时的检测函数称为cvHaarDetectObjects,训练得到的也是特征和node放在一起的xml),所以在之后当CascadeClassifier出现并统一三种特征到同一种机制和数据结构下时,没有放弃原来的C代码编写的haar检测,仍保留了原来的检测部分。另外,Haar在检测中无论是特征计算环节还是判断环节都是三种特征中最简洁的,但是笔者的经验中他的训练环节却往往是耗时最长的。

2) LBP:LBP在2.2中作为人脸检测的一种方法和Haar并列出现,他的单个点的检测方法(将在下面看到具体讨论)是三者中较为复杂的一个,所以当检测的点数相同时,如果不考虑特征计算时间,仅计算判断环节,他的时间是最长的

3) HOG:在2.4.0中才开始出现在该类中的HOG检测,其实并不是OpenCV的新生力量,因为在较早的版本中HOG特征已经开始作为单独的行人检测模块出现。比较起来,虽然HOG在行人检测和这里的检测中同样是滑窗机制,但是一个是级联adaboost,另一个是SVM;而且HOG特征为了加入CascadeClassifier支持的特征行列改变了自身的特征计算方式:不再有相邻cell之间的影响,并且采用在Haar和LBP上都可行的积分图计算,放弃了曾经的HOGCache方式,虽然后者的加速性能远高于前者,而简单的HOG特征也使得他的分类效果有所下降(如果用SVM分类器对相同样本产生的两种HOG特征做分类,没有了相邻cell影响的计算方式下的HOG特征不那么容易完成分类)。这些是HOG为了加入CascadeClassifier而做出的牺牲,不过你肯定也想得到OpenCV保留了原有的HOG计算和检测机制。另外,HOG在特征计算环节是最耗时的,但他的判断环节和Haar一样的简洁。

3.CascadeClassifier检测的基本原理:

xml中存放的是训练后的特征池,特征size大小根据训练时的参数而定,检测的时候可以简单理解为就是将每个固定size特征(检测窗口)与输入图像的同样大小区域比较,如果匹配那么就记录这个矩形区域的位置,然后滑动窗口,检测图像的另一个区域,重复操作。由于输入的图像中特征大小不定,比如在输入图像中眼睛是50x50的区域,而训练时的是25x25,那么只有当输入图像缩小到一半的时候,才能匹配上,所以这里还有一个逐步缩小图像,也就是制作图像金字塔的流程.

void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& objects,
                                          double scaleFactor, int minNeighbors,
                                          int flags, Size minObjectSize, Size maxObjectSize)
{
    vector<int> fakeLevels;
    vector<double> fakeWeights;
    detectMultiScale( image, objects, fakeLevels, fakeWeights, scaleFactor,
        minNeighbors, flags, minObjectSize, maxObjectSize, false );
}

参数意思:
1. const Mat& image:输入图像
2. vector& objects:输出的矩形向量组
3. double scaleFactor=1.1:这个是每次缩小图像的比例,默认是1.1
4. minNeighbors=3:表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大小都可以检测到人脸)。
5. flags=0:可以取如下这些值:
CASCADE_DO_CANNY_PRUNING=1, 利用canny边缘检测来排除一些边缘很少或者很多的图像区域
CASCADE_SCALE_IMAGE=2, 正常比例检测
CASCADE_FIND_BIGGEST_OBJECT=4, 只检测最大的物体
CASCADE_DO_ROUGH_SEARCH=8 初略的检测
6. minObjectSize maxObjectSize:匹配物体的大小范围

由于人脸可能出现在图像的任何位置,在检测时用固定大小的窗口对图像从上到下、从左到右扫描,判断窗口里的子图像是否为人脸,这称为滑动窗口技术(sliding window)。为了检测不同大小的人脸,还需要对图像进行放大或者缩小构造图像金字塔,对每张缩放后的图像都用上面的方法进行扫描。由于采用了滑动窗口扫描技术,并且要对图像进行反复缩放然后扫描,因此整个检测过程会非常耗时。

以512x512大小的图像为例,假设分类器窗口为24x24,滑动窗口的步长为1,则总共需要扫描的窗口数为:以512x512大小的图像为例,假设分类器窗口为24x24,滑动窗口的步长为1,则总共需要扫描的窗口数为:

以512x512大小的图像为例,假设分类器窗口为24x24,滑动窗口的步长为1,则总共需要扫描的窗口数为:

即要检测一张图片需要扫描大于120万个窗口!!!计算量惊人,因此有必要采取某种措施提高效率,具体解决方案本文会给出。

其实这种方法不好。。。。

4.实践:利用Opencv自带的Haar特征分类器进行人脸检测。

(1)Haar特征分类器

Haar特征分类器就是一个XML文件,该文件中会描述人体各个部位的Haar特征值。包括人脸、眼睛、嘴唇等等。

Haar特征分类器存放目录:OpenCV安装目录中的\data\ haarcascades目录下,例如:

例如此次程序进行人脸识别,需要将分类器haarcascade_frontalface_alt2.xml复制到所建项目的可运行文件夹内。

(2)对CascadeClassifier做初始化

cv::CascadeClassifier classifier;

classifier.load(“cascade.xml”); //这里的xml是训练得到的分类器

CascadeClassifier类中既有load也有read函数,二者是相同的,load将引用read函数

#include <opencv2/core/core.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/opencv.hpp>

#include <vector>  
#include <cstdio>  

using namespace cv;
using namespace std;
int main() 
{
   //1.加载分类器
	CascadeClassifier cascade;
	//如果要识别人体的其它部位,只需将上面的haarcascade_frontalface_alt2.xml分类器替换即可。
	cascade.load("haarcascade_frontalface_alt2.xml"); 
	Mat srcImg, dstImg, grayImg;

	//2.读图片
	srcImg = imread("1.jpg");
	//尺寸调整  
	resize(srcImg, srcImg, Size(srcImg.cols / 4, srcImg.rows / 4), 0, 0, INTER_LINEAR); //用线性插值
	dstImg = srcImg.clone();
	imshow("原图",srcImg);
	//waitKey(0);
	grayImg.create(srcImg.size(), srcImg.type());
	cvtColor(srcImg, grayImg, CV_BGR2GRAY);//生成灰度图,提高检测效率

	//定义7种颜色,用于标记人脸
	Scalar colors[] =
	{
		// 红橙黄绿青蓝紫
	   CV_RGB(255,0,0),
	   CV_RGB(255, 97, 0),
	   CV_RGB(255, 255, 0),
	   CV_RGB(0, 255, 0),
	   CV_RGB(255, 97, 0),
	   CV_RGB(0, 0, 255),
	   CV_RGB(160, 32, 240),
	};
	// 3.检测
	vector<Rect> rect;
	cascade.detectMultiScale(grayImg, rect, 1.1, 3, 0);//分类器对象调用

	printf("检测到人脸个数:%d\n", rect.size());

	//4.标记--在脸部画圆
	for (int i = 0; i < rect.size(); i++)
	{
		Point center;
		int radius;
		center.x = cvRound((rect[i].x + rect[i].width * 0.5));
		center.y = cvRound((rect[i].y + rect[i].height * 0.5));

		radius = cvRound((rect[i].width + rect[i].height) *0.25);
		circle(dstImg, center, radius, colors[i % 7], 2);
	}

	//5.显示
	imshow("识别结果",dstImg);
	waitKey(0);
}

识别结果:

仅仅是用了一个函数而已,还有很长路要走。。。

我还希望通过深度学习+opencv实现人脸检测,请期待。

等会。。。大家分得清楚,人脸检测和人脸识别吗?其实人脸检测,就是本文中的,就是对一副图片进行检测,检测是否包含人脸,而人脸识别则是人脸检测的基础上,不仅要检测出是否含有人脸,而且要进一步检测出的人脸图像与已有人脸库中的人脸进行对比,识别出该人脸图像中对应库中的哪一个。

猜你喜欢

转载自blog.csdn.net/zhuyong006/article/details/89178139