【转载】OpenCV中的Haar+Adaboost(一):Haar特征详细介绍

http://lib.csdn.net/article/opencv/29324(原文地址)

OpenCV中的Adaboost级联分类器,阅读了所有相关得代码(包括检测和训练部分),发现目前opencv中的Adaboost级联分类器代码有以下特点。可能正是由于这些问题,导致代码极其复杂,可能没有几个人愿意花费时间去阅读。

1. 代码与V&J论文原始算法差异很大,支持不同特征,不同Adaboost,还有很多小tricks。

2. 由于历史遗留,代码中C结构(CvMat)和C++结构(cv::Mat)共用。


图1 opencv_traincascade.exe训练程序usage界面

缩进图1显示了opencv_traincascade.exe的usage界面,仅仅一个traincascade训练程序就有如此之多的命令。翻遍目前网上介绍Adaboost级联分类器的文章,没有一篇文章能够完整的介绍上面所有命令的原理,甚至有些文章还存在错误,实在让人头疼。基于知识共享的原则,我把这几个月分析代码的结果写成一个系列分享出来,希望大家不再“摸着石头过河”。

缩进本系列文章不追求高深的原理(其实是我水平低),力求简单粗暴、看完就能懂。目前OpenCV中的Adaboost级联分类器支持多种特征,考虑到篇幅问题,我选择用最基础的Haar特征进行分析。下面是本系列文章的基本写作思路:

1. 首先,由Haar为引子,分析XML分类器中各个结点数值的含义,介绍Adaboost级联分类器的树状结构。

2. 然后,以DAB(Discrete Adaboost)为基础,介绍默认的GAB(Gentle Adaboost)原理。

3. 最后,分析训练分类器的实际过程,包括其中一些小tricks。

当然由于作者水平有限,难免出现遗漏和错误,真诚的欢迎各位大侠批评指正!


1 Haar特征的生成

缩进既然是结合Haar特征分析Adaboost级联分类器,那么有必要先对Haar特征进行细致的分析。

缩进Haar特征最先由Paul Viola等人提出,后经过Rainer Lienhart等扩展引入45°倾斜特征,成为现在OpenCV所使用的的样子。图2展示了目前OpenCV(2.4.11版本)所使用的共计14种Haar特征,包括5种Basic特征、3种Core特征和6种Titled(即45°旋转)特征。

图2 OpenCV中使用的的Haar特征

缩进而图1中haarFeatureParams参数中的mode参数正对应了训练过程中所使用的特征集合:

图3 mode参数

1. 如果mode为BASIC,则只使用BASIC的5种Haar特征进行训练,训练出的分类器也只包含这5种特征。

2. 如果mode为CORE,则使用BASIC的5种+CORE的3种Haar特征进行训练。

3. 如果mode为ALL,则使用BASICA的5种+CORE的3种+ALL的6种Titled共14种特征进行训练。

缩进需要说明,训练程序opencv_trancascade.exe一般默认使用BASIC模式,实际中训练和检测效果已经足够好。不建议使用ALL参数,引入Titled倾斜特征需要多计算一张倾斜积分图,会极大的降低训练和检测速度,而且效果也没有论文中说的那么好。

缩进在实际中,Haar特征可以在检测窗口中由放大+平移产生一系列子特征,但是白:黑区域面积比始终保持不变

缩进如图4,以x3特征为例,在放大+平移过程中白:黑:白面积比始终是1:1:1。首先在红框所示的检测窗口中生成大小为3个像素的最小x3特征;之后分别沿着x和y平移产生了在检测窗口中不同位置的大量最小3像素x3特征;然后把最小x3特征分别沿着x和y放大,再平移,又产生了一系列大一点x3特征;然后继续放大+平移,重复此过程,直到放大后的x3和检测窗口一样大。这样x3就产生了完整的x3系列特征。

图4 x3特征平移+放大产生一系列子特征示意图

缩进那么这些通过放大+平移的获得的子特征到底总共有多少个?Rainer Lienhart在他的论文中给出了完美的解释:假设检测窗口大小为W*H,矩形特征大小为w*h,X和Y为表示矩形特征在水平和垂直方向的能放大的最大比例系数:

图5 特征数量计算示意图

则如图5,在检测窗口Window中,一般矩形特征(upright rectangle)的数量为:


缩进简单解释一下,上述公式可以理解为:

1. 特征框竖直放大1倍,即无放大,竖直方向有(H-h+1)个特征

2. 特征框竖直放大2倍,竖直方向有(H-2h+1)个特征

3. 特征框竖直放大3倍,竖直方向有(H-3h+1)个特征

4.如此到竖直放大Y=floor(H/h)倍,竖直方向有1个特征,即(H-Y*h+1)

那么竖直方向总共有(H-h+1)+(H-2h+1)+(H-3h+1)+……+(H-Y*h+1)=Y[H+1-h(1+Y)/2]个特征。考虑到水平和竖直方向缩放是独立的,所以能得到上述公式。

缩进对应于之前的x3特征,当x3特征在24*24大小的检测窗口中时(此时W=H=24,w=3,h=1,X=8,Y=24),一共能产生27600个子特征,除x3外其他一般矩形特征数量计算方法类似。另外,我为认为title特征(即图5中的45° rotated reactangle)并无实用性,所以不作解释,请自行分析了解。


2 计算Haar特征值

缩进看到这里,您应该明白了大量的Haar特征是如何产生的。当有了大量的Haar特征用于训练和检测时,接下来的问题是如何计算Haar特征值。按照OpenCV代码,Haar特征值=整个Haar区域内像素和×权重 + 黑色区域内像素和×权重:

1. 对于图2中的x3和y3特征,weightall = 1,weightblack = -3;

2. 对于point特征,weightall = 1,weightblack = -9;

3. 其余11种特征均为weightall =1, weightblack = -2。

缩进这也就是其他文章中提到的所谓“白色区域像素和减去黑色区域像素和”,只不过是加权相加而已。例如以x2特征为例,(黑 + 白) * 1 + 黑 * (-2) = 白 - 黑;对于Point特征,(黑 + 白) * 1 + 黑 * (-9) = 白 - 8 * 黑。

缩进为什么要设置这种加权相减,而不是直接相减?请仔细观察图2中的特征,不难发现x3、y3、point特征黑白面积不相等,而其他特征黑白面积相等。设置权值就是为了抵消面积不等带来的影响,保证所有Haar特征的特征值在灰度分布绝对均匀的图中为0。

————————————————–

缩进对应的,在保存分类器的OpenCV XML文件中,每一个Haar特征都被保存在2~3个形如<x y width height weight>的标签中,其中x和y代表Haar矩形左上角坐标(以检测窗口左上角为原点),width和height代表矩形的宽和高,而weight则对应了上面说的权重值,例如图6中的左边x2类型的Haar特征应该为<4 2 12 8 1.0>(整个Haar,权重1)和<4 2 12 4 -2.0>(黑色区域,权重-2)。

————————————————–

缩进了解了特征值如何计算之后,再来看看不同的特征值的含义是什么。我选取了MIT人脸库中2706个大小为20*20的人脸正样本图像,计算如图6位置的Haar特征值,结果如图7。

图6 Haar特征位置示意图(左边对应人眼区域,右边无具体意义

图7 图6的2个Haar特征在MIT人脸样本中特征值分布图

左边特征结果为红色右边蓝色

缩进可以看到,图6中2个不同Haar特征在同一组样本中具有不同的特征值分布,左边特征计算出的特征值基本都大于0,而右边特征的特征值基本均匀分布于0两侧(分布越均匀对样本的区分度越小)。所以,正是由于样本中Haar特征值分布不同,导致了不同Haar特征分类效果不同。显而易见,对样本区分度越大的特征分类效果越好,即红色曲线对应图6中的的左边Haar特征分类效果好于右边Haar特征。那么看到这里,应该理解了下面2个问题:

1. 在检测窗口通过平移+放大可以产生一系列Haar特征,这些特征由于位置和大小不同,分类效果也各异;

2. 通过计算Haar特征的特征值,可以有将图像矩阵映射为1维特征值,有效实现了降维。


3 Haar特征值标准化

缩进细心的朋友可能已经从图7中发现,仅仅一个12*18大小的Haar特征计算出的特征值变化范围从-2000~+6000,跨度非常大。这种跨度大的特性不利于量化评定特征值,所以需要进行“标准化”,压缩特征值范围。假设当前检测窗口中的图像为i(x,y),当前检测窗口为w*h大小(例如图6中为20*20大小),OpenCV采用如下方式“标准化”:

1. 计算检测窗口中间部分(w-2)*(h-2)的图像的灰度值和灰度值平方和:

2. 计算平均值:

3. 计算标准化因子:

4. 标准化特征值:

缩进具体代码在cascadedetect.cpp中的HaarEvaluator::setImage()函数中可以看到,关键部分如下:

[cpp]  view plain  copy
  1. normrect = Rect(1, 1, origWinSize.width-2, origWinSize.height-2);  
  2. CV_SUM_PTRS( p[0], p[1], p[2], p[3], sdata, normrect, sumStep );  
  3. CV_SUM_PTRS( pq[0], pq[1], pq[2], pq[3], sqdata, normrect, sqsumStep );  

与代码对应的,如图中蓝色为检测窗口,红色为标准化过程中使用到的像素。

缩进为什么一定要在norm的时候缩进去一个边呢?作者猜测这可能是为了避免边缘像素不稳定,干扰标准化因子的计算。其实如何标准化并不重要,重要的是检测和训练时的方法一定要一致!否则可能会由于标准化不同带来的误差导致模型无法工作!

缩进之后按照上述公式求出varNormFactor后,使用标准化后的特征值normValue与阈值对比(见下节)。

——————————————-

参考文献:

[1] Paul Viola and Michael J. Jones. Rapid Object Detection using a Boosted Cascade of Simple Features. IEEE CVPR, 2001.

[2] Rainer Lienhart and Jochen Maydt. An Extended Set ofHaar-like Features for Rapid Object Detection. IEEE ICIP 2002, Vol. 1, pp. 900-903, Sep. 2002.

——————————————-

Haar特征的分析就结束了,下一篇,我会介绍积分图和旋转积分图。


http://lib.csdn.net/article/opencv/29324(原文地址)

OpenCV中的Adaboost级联分类器,阅读了所有相关得代码(包括检测和训练部分),发现目前opencv中的Adaboost级联分类器代码有以下特点。可能正是由于这些问题,导致代码极其复杂,可能没有几个人愿意花费时间去阅读。

1. 代码与V&J论文原始算法差异很大,支持不同特征,不同Adaboost,还有很多小tricks。

2. 由于历史遗留,代码中C结构(CvMat)和C++结构(cv::Mat)共用。


图1 opencv_traincascade.exe训练程序usage界面

缩进图1显示了opencv_traincascade.exe的usage界面,仅仅一个traincascade训练程序就有如此之多的命令。翻遍目前网上介绍Adaboost级联分类器的文章,没有一篇文章能够完整的介绍上面所有命令的原理,甚至有些文章还存在错误,实在让人头疼。基于知识共享的原则,我把这几个月分析代码的结果写成一个系列分享出来,希望大家不再“摸着石头过河”。

缩进本系列文章不追求高深的原理(其实是我水平低),力求简单粗暴、看完就能懂。目前OpenCV中的Adaboost级联分类器支持多种特征,考虑到篇幅问题,我选择用最基础的Haar特征进行分析。下面是本系列文章的基本写作思路:

1. 首先,由Haar为引子,分析XML分类器中各个结点数值的含义,介绍Adaboost级联分类器的树状结构。

2. 然后,以DAB(Discrete Adaboost)为基础,介绍默认的GAB(Gentle Adaboost)原理。

3. 最后,分析训练分类器的实际过程,包括其中一些小tricks。

当然由于作者水平有限,难免出现遗漏和错误,真诚的欢迎各位大侠批评指正!


1 Haar特征的生成

缩进既然是结合Haar特征分析Adaboost级联分类器,那么有必要先对Haar特征进行细致的分析。

缩进Haar特征最先由Paul Viola等人提出,后经过Rainer Lienhart等扩展引入45°倾斜特征,成为现在OpenCV所使用的的样子。图2展示了目前OpenCV(2.4.11版本)所使用的共计14种Haar特征,包括5种Basic特征、3种Core特征和6种Titled(即45°旋转)特征。

图2 OpenCV中使用的的Haar特征

缩进而图1中haarFeatureParams参数中的mode参数正对应了训练过程中所使用的特征集合:

图3 mode参数

1. 如果mode为BASIC,则只使用BASIC的5种Haar特征进行训练,训练出的分类器也只包含这5种特征。

2. 如果mode为CORE,则使用BASIC的5种+CORE的3种Haar特征进行训练。

3. 如果mode为ALL,则使用BASICA的5种+CORE的3种+ALL的6种Titled共14种特征进行训练。

缩进需要说明,训练程序opencv_trancascade.exe一般默认使用BASIC模式,实际中训练和检测效果已经足够好。不建议使用ALL参数,引入Titled倾斜特征需要多计算一张倾斜积分图,会极大的降低训练和检测速度,而且效果也没有论文中说的那么好。

缩进在实际中,Haar特征可以在检测窗口中由放大+平移产生一系列子特征,但是白:黑区域面积比始终保持不变

缩进如图4,以x3特征为例,在放大+平移过程中白:黑:白面积比始终是1:1:1。首先在红框所示的检测窗口中生成大小为3个像素的最小x3特征;之后分别沿着x和y平移产生了在检测窗口中不同位置的大量最小3像素x3特征;然后把最小x3特征分别沿着x和y放大,再平移,又产生了一系列大一点x3特征;然后继续放大+平移,重复此过程,直到放大后的x3和检测窗口一样大。这样x3就产生了完整的x3系列特征。

图4 x3特征平移+放大产生一系列子特征示意图

缩进那么这些通过放大+平移的获得的子特征到底总共有多少个?Rainer Lienhart在他的论文中给出了完美的解释:假设检测窗口大小为W*H,矩形特征大小为w*h,X和Y为表示矩形特征在水平和垂直方向的能放大的最大比例系数:

图5 特征数量计算示意图

则如图5,在检测窗口Window中,一般矩形特征(upright rectangle)的数量为:


缩进简单解释一下,上述公式可以理解为:

1. 特征框竖直放大1倍,即无放大,竖直方向有(H-h+1)个特征

2. 特征框竖直放大2倍,竖直方向有(H-2h+1)个特征

3. 特征框竖直放大3倍,竖直方向有(H-3h+1)个特征

4.如此到竖直放大Y=floor(H/h)倍,竖直方向有1个特征,即(H-Y*h+1)

那么竖直方向总共有(H-h+1)+(H-2h+1)+(H-3h+1)+……+(H-Y*h+1)=Y[H+1-h(1+Y)/2]个特征。考虑到水平和竖直方向缩放是独立的,所以能得到上述公式。

缩进对应于之前的x3特征,当x3特征在24*24大小的检测窗口中时(此时W=H=24,w=3,h=1,X=8,Y=24),一共能产生27600个子特征,除x3外其他一般矩形特征数量计算方法类似。另外,我为认为title特征(即图5中的45° rotated reactangle)并无实用性,所以不作解释,请自行分析了解。


2 计算Haar特征值

缩进看到这里,您应该明白了大量的Haar特征是如何产生的。当有了大量的Haar特征用于训练和检测时,接下来的问题是如何计算Haar特征值。按照OpenCV代码,Haar特征值=整个Haar区域内像素和×权重 + 黑色区域内像素和×权重:

1. 对于图2中的x3和y3特征,weightall = 1,weightblack = -3;

2. 对于point特征,weightall = 1,weightblack = -9;

3. 其余11种特征均为weightall =1, weightblack = -2。

缩进这也就是其他文章中提到的所谓“白色区域像素和减去黑色区域像素和”,只不过是加权相加而已。例如以x2特征为例,(黑 + 白) * 1 + 黑 * (-2) = 白 - 黑;对于Point特征,(黑 + 白) * 1 + 黑 * (-9) = 白 - 8 * 黑。

缩进为什么要设置这种加权相减,而不是直接相减?请仔细观察图2中的特征,不难发现x3、y3、point特征黑白面积不相等,而其他特征黑白面积相等。设置权值就是为了抵消面积不等带来的影响,保证所有Haar特征的特征值在灰度分布绝对均匀的图中为0。

————————————————–

缩进对应的,在保存分类器的OpenCV XML文件中,每一个Haar特征都被保存在2~3个形如<x y width height weight>的标签中,其中x和y代表Haar矩形左上角坐标(以检测窗口左上角为原点),width和height代表矩形的宽和高,而weight则对应了上面说的权重值,例如图6中的左边x2类型的Haar特征应该为<4 2 12 8 1.0>(整个Haar,权重1)和<4 2 12 4 -2.0>(黑色区域,权重-2)。

————————————————–

缩进了解了特征值如何计算之后,再来看看不同的特征值的含义是什么。我选取了MIT人脸库中2706个大小为20*20的人脸正样本图像,计算如图6位置的Haar特征值,结果如图7。

图6 Haar特征位置示意图(左边对应人眼区域,右边无具体意义

图7 图6的2个Haar特征在MIT人脸样本中特征值分布图

左边特征结果为红色右边蓝色

缩进可以看到,图6中2个不同Haar特征在同一组样本中具有不同的特征值分布,左边特征计算出的特征值基本都大于0,而右边特征的特征值基本均匀分布于0两侧(分布越均匀对样本的区分度越小)。所以,正是由于样本中Haar特征值分布不同,导致了不同Haar特征分类效果不同。显而易见,对样本区分度越大的特征分类效果越好,即红色曲线对应图6中的的左边Haar特征分类效果好于右边Haar特征。那么看到这里,应该理解了下面2个问题:

1. 在检测窗口通过平移+放大可以产生一系列Haar特征,这些特征由于位置和大小不同,分类效果也各异;

2. 通过计算Haar特征的特征值,可以有将图像矩阵映射为1维特征值,有效实现了降维。


3 Haar特征值标准化

缩进细心的朋友可能已经从图7中发现,仅仅一个12*18大小的Haar特征计算出的特征值变化范围从-2000~+6000,跨度非常大。这种跨度大的特性不利于量化评定特征值,所以需要进行“标准化”,压缩特征值范围。假设当前检测窗口中的图像为i(x,y),当前检测窗口为w*h大小(例如图6中为20*20大小),OpenCV采用如下方式“标准化”:

1. 计算检测窗口中间部分(w-2)*(h-2)的图像的灰度值和灰度值平方和:

2. 计算平均值:

3. 计算标准化因子:

4. 标准化特征值:

缩进具体代码在cascadedetect.cpp中的HaarEvaluator::setImage()函数中可以看到,关键部分如下:

[cpp]  view plain  copy
  1. normrect = Rect(1, 1, origWinSize.width-2, origWinSize.height-2);  
  2. CV_SUM_PTRS( p[0], p[1], p[2], p[3], sdata, normrect, sumStep );  
  3. CV_SUM_PTRS( pq[0], pq[1], pq[2], pq[3], sqdata, normrect, sqsumStep );  

与代码对应的,如图中蓝色为检测窗口,红色为标准化过程中使用到的像素。

缩进为什么一定要在norm的时候缩进去一个边呢?作者猜测这可能是为了避免边缘像素不稳定,干扰标准化因子的计算。其实如何标准化并不重要,重要的是检测和训练时的方法一定要一致!否则可能会由于标准化不同带来的误差导致模型无法工作!

缩进之后按照上述公式求出varNormFactor后,使用标准化后的特征值normValue与阈值对比(见下节)。

——————————————-

参考文献:

[1] Paul Viola and Michael J. Jones. Rapid Object Detection using a Boosted Cascade of Simple Features. IEEE CVPR, 2001.

[2] Rainer Lienhart and Jochen Maydt. An Extended Set ofHaar-like Features for Rapid Object Detection. IEEE ICIP 2002, Vol. 1, pp. 900-903, Sep. 2002.

——————————————-

Haar特征的分析就结束了,下一篇,我会介绍积分图和旋转积分图。


猜你喜欢

转载自blog.csdn.net/mnydxk/article/details/81034302