上一篇我们初步分析了下示例代码facedetector的程序参数解析部分。其中参数解析的过程如下:
其中第4步黄色标注的部分cascadeName,是我们人脸识别分类器的主要参数。
在openCV中,实现了著名的haar特征检测算法,而依托该算法分类器,我们可以实现人脸识别、定位。
该算法基于特征模板的滑动计算图像特征,从而区分物体的显著轮廓。
这些特征模板形似以下图像:
试想用这些黑白二值图像”蒙”在你的图像或部分图像上,然后你原来的图像被分成“黑”“白”两类区域,最后用黑色区域和白色区域的像素进行简单的加减运算,便能得到图像的基本特征。
例如,我们将模板窗口(3)“蒙”在鼻子部位,便能得到相契合的特征,将模板窗口(4)放在双眼部位,同样能得到与双眼部位契合的特征。
但是如何根据不同图像来确定特征模板窗口的大小,和它们应该放置的位置呢。比如上图,我们怎么知道将特定大小的“上黑下白”特征模板固定在图像的高度3/4上?
答案就是,我们让不知劳累的计算机,测试各种位置和大小。
这是一个巨大的工作量,首先我们如果确定具体特征模板窗口大小为24,24。那么我们就得将待检测图像分为若干个24,24大小区域,试图分别用不同特征模板检测*区域图像是否“匹配”某特征,那么单单一个窗口匹配次数是大于160000,这依然将是一个巨大的工作量。
但如果引入级联分类器——Cascade Classifiers,那么工作量就会极大的缩减。
拿人脸检测来讲,先用一些特征,确定该区域图像“有脸”以及“无脸“,丢掉”无脸“部分,然后再用其他特征检测,来进一步确定特征的是否存在,以及确定其特征位置。
这个过程使得我们匹配特征的过程产生一个“级联“的工作模式,每往下走一层,就会”丢掉“一些无关的区域,这样特征就越来越精确。
从上述过程当中我们可以看到,单独一个特征不能确定最终结果,而是多个特征的级联联合使得最终我们能够做出一个精确的判断。
我们把单个特征的检测叫做弱分类器(因为它不能单独确定最终结果),而把这些弱分类器级联成的最终分类器成为强分类器。可见最终的强分类器是在集成算法的基础上构建的。
好吧,言归正传,openCV实现了这个强分类器,用CascadeClassifier类封装该分类器。你可以实例化该类对象,并设计一个训练计划,来训练想要的特征检测器。
对与人脸检测来说,openCV已经帮我们训练好了分类器,该分类器的参数数据保存在一个xml文件中。
在实际使用过程中,这个文件的路径将作为重要的参数和被检测图像一起传给CascadeClassifier对象,接着对被检测图像中人脸进行定位。
而上一篇中,解析出的参数cascadeName,正是这个文件路径
我们接着上一篇,继续往下做,得到cascadeName后,构造CascadeClassifier对象”cascade”。
然后利用classifier对被检测图像进行人脸预测。
同样,我们简化源代码,此次只对单张图像进行检测。
//根据分类器模板路径cascadeName构造级联分类器(CascadeClassifier)对象"cascade"
cv::CascadeClassifier cascade(cascadeName);//读入被检测图像
Mat image =imread("D:/试验/test/baby.png");//定义灰度图像,用于暂存原图像对应的灰度图。
Mat gray;//将原被检测图像从真彩色图像转换为灰度图cvtColor(image, gray, cv::COLOR_BGR2GRAY);//定义一个向量(数组),用于存放所检测出的人脸位置(注意:可能并不只有一个人脸)
vector<Rect> faces;//启动检测
cascade.detectMultiScale(gray,faces);//用红色矩形绘制人脸位置结果for(int i =0; i < faces.size(); i++){
cv::rectangle(image, faces[i],Scalar(255,0,0));}//显示最终被“标记”的图像imshow("检测人脸", image);//等待用户输入任意键结束程序waitKey();
运行结果:
最后发下关于类CasadeClassifier的官方文档解释,本篇博文多是对该文档的总结https://docs.opencv.org/3.4/db/d28/tutorial_cascade_classifier.html
版权归原作者 LayeZhao 所有, 如有侵权,请联系我们删除。