人脸检测:人脸检测是指给定一张图片,判断图片中是否存在人脸,如果存在人脸,将人脸所在区域框出来。
opencv和dlib都自带了人脸检测模块,这一篇文章中,我们先来学习一下opencv自带的人脸检测器,基于adaboost算法的通过haar特征训练的人脸检测模型。
第一部分:Haar特征和积分图
1.1 Haar特征
Haar特征也叫矩形特征,主要有边缘特征、线性特征和中心环绕特征,从不同角度反映图像的灰度信息,能够完备的反映人脸图像的灰度特征
1.2 特征图
矩形特征对应的特征值的计算方法:该矩形特征中白色区域所有像素的灰度和减去黑色区域内所有像素的灰度和。如果直接计算的话,会有大量的重复计算,浪费大量的时间,所以引入积分图的概念。
对于图像上的某一个像素点p(x,y),该像素点对应的积分图像值为以图像左上角到该点的直线为对角线的矩形区域内的所有像素的灰度和,对图像从左到右、从上到下扫描一次即可计算出所有像素点的积分值。矩形特征对应的特征值就可以通过矩形的6个顶点的积分值求得。
第二部分:adaboost算法
人脸检测分类器的训练需要两类样本:正样本即人脸图像,负样本即非人脸图像。
adaboost算法是将多个弱分类器组合在一起形成一个强分类器的算法。弱分类器的训练过程相当于特征选择的过程,强分类器的训练过程相当于由分类能力一般的弱分类器向分类能力良好的强分类器提升的过程。对于此问题,弱分类是这样训练出来的:对于每一个矩形特征,调整阈值训练出一个对此特征的最优弱分类器,再取所有矩形特征的最优弱分类器为最后的弱分类器。然后将弱分类器级联在一起形成一个强分类器。
Haar分类器算法的要点如下:
(1)使用haar-like特征做检测
(2)使用积分图对haar-like特征求值进行加速
(3)使用adaboost算法训练区分人脸和非人脸的强分类器
(4)使用筛选式级联把强分类器级联在一起,提高准确率
第三部分:代码详解
上面的原理讲的不是很清楚,还望读者见谅,下面我们看一下实例代码
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
string xmlPath = "D:\\Program Files\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt2.xml";
CascadeClassifier ccf; //创建分类器对象
if (!ccf.load(xmlPath)) //加载训练文件
{
cout << "不能加载指定的xml文件" << endl;
return 0;
}
namedWindow("人脸检测");
Mat img = imread("1.jpg");
vector<Rect> faces; //创建一个容器保存检测出来的脸
Mat gray;
cvtColor(img, gray, CV_BGR2GRAY); //转换成灰度图,因为harr特征从灰度图中提取
equalizeHist(gray, gray); //直方图均衡行
ccf.detectMultiScale(gray, faces, 1.15, 3, 0, Size(30, 30)); //检测人脸
for (vector<Rect>::const_iterator iter = faces.begin(); iter != faces.end(); iter++)
{
rectangle(img, *iter, Scalar(0, 0, 255), 2, 8); //画出脸部矩形
}
imshow("人脸检测", img);
waitKey();
return 0;
}
上面的代码很简单,只需要调用opencv里面的几个函数就可以检测出人脸,但里面的原理还是很复杂的,希望大家可以尽可能多的理解了原理之后再理解代码。
下面简单的介绍一下上面的代码:
一:读取opencv自带的检测器
opencv在自己的安装目录下已经自带了好多检测器,我们可以在安装目录下的sources/data目录下看到许多xml格式的已经训练好的模型,我们可以根据自己的需要选择,我们这里使用haarcascade_frontalface_alt2.xml模型。
二:图像预处理
模型读取完成后,我们就需要读取图片,首先我们使用imread函数读取一张图片,注意这里的参数需要改成你自己的图片名;然后将读取的彩色图通过cvtColor函数转化为灰度图;最后通过函数equalizeHist函数进行直方图均衡,功能是实现图像对比度的增强。
三:人脸检测
通过调用detectMultiScale函数实现人脸的检测,该函数将检测到的人脸区域矩形信息存放在第二个参数里。
四:在原图上画出矩形区域
最后一步通过opencv中的rectangle函数在原图上将人脸的矩形框画出来并通过imshow函数显示
最后看一张人脸检测的效果图