opencv学习笔记三十八:级联分类器人脸检测

Haar分类器算法的要点如下:

① 使用Haar-like特征做检测。

② 使用积分图(Integral Image)对Haar-like特征值进行加速求解。

③ 使用AdaBoost算法训练区分人脸和非人脸的强分类器。

④ 使用筛选式级联把强分类器级联到一起,提高准确率。

Haar特征:  

什么是特征,我把它放在下面的情景中来描述,假设在人脸检测时我们需要有这么一个子窗口在待检测的图片窗口中不断的移位滑动,子窗口每到一个位置,就会计算出该区域的特征,然后用我们训练好的级联分类器对该特征进行筛选,一旦该特征通过了所有强分类器的筛选,则判定该区域为人脸。

那么这个特征如何表示呢?好了,这就是大牛们干的好事了。后人称这他们搞出来的这些东西叫Haar-Like特征。

下面是Viola牛们提出的Haar-like特征。

      这些所谓的特征不就是一堆堆带条纹的矩形么,到底是干什么用的?我这样给出解释,将上面的任意一个矩形放到人脸区域上,然后,将白色区域的像素和减去黑色区域的像素和,得到的值我们暂且称之为人脸特征值,如果你把这个矩形放到一个非人脸区域,那么计算出的特征值应该和人脸特征值是不一样的,而且越不一样越好,所以这些方块的目的就是把人脸特征量化,以区分人脸和非人脸。

决策树用途很广可以分析因素对事件结果的影响,同时也是很常用的分类方法,我举个最简单的决策树例子,假设我们使用三个Haar-like特征f1,f2,f3来判断输入数据是否为人脸,可以建立如下决策树:

 

        可以看出,在分类的应用中,每个非叶子节点都表示一种判断,每个路径代表一种判断的输出,每个叶子节点代表一种类别,并作为最终判断的结果。 一个弱分类器就是一个基本和上图类似的决策树,最基本的弱分类器只包含一个Haar-like特征,也就是它的决策树只有一层,被称为树桩(stump)。

        最重要的就是如何决定每个结点判断的输出,要比较输入图片的特征值和弱分类器中特征,一定需要一个阈值,当输入图片的特征值大于该阈值时才判定其为人脸。训练最优弱分类器的过程实际上就是在寻找合适的分类器阈值,使该分类器对所有样本的判读误差最低。

我们看到了通过AdaBoost算法辛苦的训练出了强分类器,然而在现实的人脸检测中,只靠一个强分类器还是难以保证检测的正确率,这个时候,需要一个豪华的阵容,训练出多个强分类器将它们强强联手,最终形成正确率很高的级联分类器这就是我们最终的目标Haar分类器。

         那么训练级联分类器的目的就是为了检测的时候,更加准确,这涉及到Haar分类器的另一个体系,检测体系,检测体系是以现实中的一幅大图片作为输入,然后对图片中进行多区域,多尺度的检测,所谓多区域,是要对图片划分多块,对每个块进行检测,由于训练的时候用的照片一般都是20*20左右的小图片,所以对于大的人脸,还需要进行多尺度的检测,多尺度检测机制一般有两种策略,一种是不改变搜索窗口的大小,而不断缩放图片,这种方法显然需要对每个缩放后的图片进行区域特征值的运算,效率不高,而另一种方法,是不断初始化搜索窗口size为训练时的图片大小,不断扩大搜索窗口,进行搜索,解决了第一种方法的弱势。

         无论哪一种搜索方法,都会为输入图片输出大量的子窗口图像,这些子窗口图像经过筛选式级联分类器会不断地被每一个节点筛选,抛弃或通过。

它的结构如图所示。

 

 adaboost工作原理:

#include<opencv2\opencv.hpp>
using namespace cv;
using namespace std;
int main(int arc, char** argv) { 
	Mat src = imread("2.jpg");
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);
	Mat gray_img;
	cvtColor(src, gray_img, CV_BGR2GRAY);
	equalizeHist(gray_img, gray_img);
	//【1】定义级联分类器
	CascadeClassifier face_cascade;
	String cascadeFilePath = "E:/anzhuang/opencv3.4.1/opencv/build/etc/haarcascades/haarcascade_frontalface_alt.xml"	
        //【2】加载opencv训练好的数据模型
	face_cascade.load(cascadeFilePath);
	vector<Rect>faces;
        //【3】检测人脸
	face_cascade.detectMultiScale(gray_img, faces, 1.1, 2, 0, Size(30, 30));

	for (int i = 0; i < faces.size(); i++)
	{
		rectangle(src, faces[i], Scalar(0, 255,0 ),2);
	}
	imshow("output", src);
	waitKey(0);
	return 0;
}

 

摄像头实时人脸检测:

#include<opencv2\opencv.hpp>
using namespace cv;
using namespace std;
int main(int arc, char** argv) { 
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	VideoCapture capture(0);
	Mat frame;
	vector<Rect>objects;
	CascadeClassifier cascade;
	cascade.load("E:/anzhuang/opencv3.4.1/opencv/build/etc/haarcascades/haarcascade_frontalface_default.xml");
	while (capture.read(frame)){
		imshow("input", frame);	
		cascade.detectMultiScale(frame, objects, 1.1,3,0,Size(30,30));
		for (int i = 0; i < objects.size(); i++) {
			rectangle(frame, objects[i], Scalar(0, 255, 0), 2, 8);
		}
		char c = waitKey(10);
		if (c == 27) { break; }
		imshow("output", frame);
	}
	waitKey(0);
	return 0;
}

 参考文献:https://blog.csdn.net/zouxy09/article/details/7922923

猜你喜欢

转载自blog.csdn.net/qq_24946843/article/details/82710907