本系列文章总共有七篇,目录索引如下:
AdaBoost 人脸检测介绍(1) : AdaBoost身世之谜
AdaBoost 人脸检测介绍(2) : 矩形特征和积分图
AdaBoost 人脸检测介绍(3) : AdaBoost算法流程
AdaBoost 人脸检测介绍(4) : AdaBoost算法举例
AdaBoost 人脸检测介绍(5) : AdaBoost算法的误差界限
AdaBoost 人脸检测介绍(6) : 使用OpenCV自带的 AdaBoost程序训练并检测目标
AdaBoost 人脸检测介绍(7) : Haar特征CvHaarClassifierCascade等结构分析
2. 矩形特征和积分图
AdaBoost,是英文”Adaptive Boosting”(自适应增强)的缩写,由Yoav Freund和Robert Schapire在1995年提出。它的自适应在于:前一个基本分类器分错的样本会得到加强,加权后的全体样本再次被用来训练下一个基本分类器。同时,在每一轮中加入一个新的弱分类器,直到达到某个预定的足够小的错误率或达到预先指定的最大迭代次数。
AdaBoost算法到目前为止仍然是人脸检测的热门算法。本节主要介绍AdaBoost算法的原理,包括级联策略、积分图思想、矩形特征。
2.1 级联策略
AdaBoost 是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器,即弱分类器,然后把这些弱分类器集合起来,构造一个更强的最终分类器。因此AdaBoost是一种基于级联分类模型的分类器。级联分类模型可以用下图表示:
级联分类器就是将多个强分类器连接在一起进行操作。每一个强分类器都由若干个弱分类器加权组成,例如,有些强分类器可能包含10个弱分类器,有些则包含20个弱分类器,一般情况下一个级联用的强分类器包含20个左右的弱分类器,然后在将10个强分类器级联起来,就构成了一个级联强分类器,这个级联强分类器中总共包括200个弱分类器。因为每一个强分类器对负样本的判别准确度非常高,所以一旦发现检测到的目标位负样本,就不再继续调用下面的强分类器,减少了很多的检测时间。因为一幅图像中待检测的区域很多都是负样本,这样由级联分类器在分类器的初期就抛弃了很多负样本的复杂检测,所以级联分类器的速度是非常快的;只有正样本才会送到下一个强分类器进行再次检验,这样就保证了最后输出的正样本的伪正(false positive)的可能性非常低。
2.2 矩形特征
P.Viola等在2001年提出一种基于Boosting方法的实时人脸检测系统,该系统的检测速度可以达到每秒15帧,实时检测速度及准确率表现优异,这是人脸检测从研究走向实用的一次质的飞跃。他们对人脸应用积分图方法计算矩形特征,用其得到的结果训练分类器。
2.2.1 Harr-like特征
Harr-like特征是Viola等提出的一种简单矩形特征,因其类似于Harr小波而得名。它反映了图像局部的灰度化。影响AdaBoost检测训练算法速度很重要的两方面是特征的选取和特征值的计算。脸部的一些特征可以由矩形特征简单地描绘。如下图示范:
上图中两个矩形特征,表示出人脸的某些特征。比如中间一幅表示眼睛区域的颜色比脸颊区域的颜色深,右边一幅表示鼻梁两侧比鼻梁的颜色要深。同样,其他目标,如眼睛等,也可以用一些矩形特征来表示。在给定有限的数据情况下,基于特征的检测能够编码特定区域的状态,而且基于特征的系统比基于像素的系统要快得多。
矩形特征对一些简单的图形结构,比如边缘、线段,比较敏感,但是其只能描述特定走向(水平、垂直、对角)的结构,因此比较粗略。如上图,脸部一些特征能够由矩形特征简单地描绘,例如,通常眼睛要比脸颊颜色更深;鼻梁两侧要比鼻梁颜色要深;嘴巴要比周围颜色更深。
对于一个 24×24 检测器,其内的矩形特征数量超过160,000个,必须通过特定算法甄选合适的矩形特征,并将其组合成强分类器才能检测人脸。
常用的矩形特征有三种:两矩形特征、三矩形特征、四矩形特征,如图:
由图表可以看出,两矩形特征反映的是边缘特征,三矩形特征反映的是线性特征、四矩形特征反映的是特定方向特征。
Lienhart R.等对Haar-like矩形特征库作了进一步扩展,加入了旋转〖45〗^o角的矩形特征。扩展后的特征大致分为4种类型:边缘特征、线特征环、中心环绕特征和对角线特征:
这些所谓的特征不就是一堆带条纹的矩形么,到底是干什么用的?我这样给出解释,将上面的任意一个矩形放到人脸区域上,然后,将白色区域的像素和减去黑色区域的像素和,得到的值我们暂且称之为人脸特征值,如果你把这个矩形放到一个非人脸区域,那么计算出的特征值应该和人脸特征值是不一样的,而且越不一样越好,所以这些方块的目的就是把人脸特征量化,以区分人脸和非人脸。为了增加区分度,可以对多个矩形特征计算得到一个区分度更大的特征值,那么什么样的矩形特征怎么样的组合到一块可以更好的区分出人脸和非人脸呢,这就是AdaBoost算法要做的事了。OpenCV的Haar分类器就是基于扩展后的特征库实现的。
特征模板都是由两个或多个全等的矩形相邻组合而成,特征模板内有白色和黑色两种矩形。特征模板的特征值定义为:白色矩形像素和减去黑色矩形像素和。接下来,要解决两个问题:1)求出每个待检测子窗口中的特征个数;2)求出每个特征的特征值。
子窗口中的特征个数即为特征矩形的个数。训练时,将每一个特征在训练图像子窗口中进行滑动计算,获取各个位置的各类矩形特征。在子窗口中位于不同位置的同一类型矩形特征,属于不同的特征。可以证明,在确定了特征的形式之后,矩形特征的数量只与子窗口的大小有关。在24×24的检测窗口中,矩形特征的数量约为160,000个。
2.2.2 特征模板个数
特征模板可以在子窗口内以“任意”尺寸“任意”放置,每一种形态称为一个特征。找出子窗口所有特征,是进行弱分类训练的基础。
2.2.2.1 子窗口内的条件矩形
如图所示一个 m<script type="math/tex" id="MathJax-Element-727">m</script> x m<script type="math/tex" id="MathJax-Element-728">m</script>大小的子窗口,可以计算在这么大的子窗口内存在多少个矩形特征。
以 m<script type="math/tex" id="MathJax-Element-729">m</script>×m<script type="math/tex" id="MathJax-Element-730">m</script> 像素分辨率的检测器为例,其内部存在的满足特定条件的所有矩形的总数可以这样计算:
对于 m<script type="math/tex" id="MathJax-Element-731">m</script>×m<script type="math/tex" id="MathJax-Element-732">m</script> 子窗口,我们只需要确定了矩形左上顶点 A(x1,y1)<script type="math/tex" id="MathJax-Element-733">A(x_1,y_1)</script> 和右下顶点 B(x2,y2)<script type="math/tex" id="MathJax-Element-734">B(x_2,y_2)</script>,即可以确定一个矩形;如果这个矩形还必须满足下面两个条件(称为 (s,t)<script type="math/tex" id="MathJax-Element-735">(s,t)</script> 条件,满足 (s,t)<script type="math/tex" id="MathJax-Element-736">(s,t)</script> 条件的矩形称为条件矩形):
1)x<script type="math/tex" id="MathJax-Element-737">x</script> 方向边长必须能被自然数 s<script type="math/tex" id="MathJax-Element-738">s</script> 整除(能均等分成 s<script type="math/tex" id="MathJax-Element-739">s</script> 段);
2)y<script type="math/tex" id="MathJax-Element-740">y</script> 方向边长必须能被自然数 t<script type="math/tex" id="MathJax-Element-741">t</script> 整除(能均等分成 t<script type="math/tex" id="MathJax-Element-742">t</script> 段);
则这个矩形的最小尺寸为 s×t<script type="math/tex" id="MathJax-Element-743">s×t</script> 或 t×s<script type="math/tex" id="MathJax-Element-744">t×s</script>,最大尺寸为 [m/s]<script type="math/tex" id="MathJax-Element-745">[m/s]</script>*s×[m/t]<script type="math/tex" id="MathJax-Element-746">[m/t]</script>*t 或 [m/t]<script type="math/tex" id="MathJax-Element-747">[m/t]</script>*t×[m/s]<script type="math/tex" id="MathJax-Element-748">[m/s]</script>*s;其中[ ]为取整运算符。
2.2.2.2 条件矩形的数量
我们通过下面两步就可以定位一个满足条件的矩形:
1)确定 A(x1,y1):x1∈1,2,?,m?s,m?s+1,y1∈1,2,?,m?t,m?t+1<script type="math/tex" id="MathJax-Element-1201">A(x_1,y_1 ) :x_1∈{1,2,?,m-s,m-s+1}, y_1∈{1,2,?,m-t,m-t+1}</script> ;
2)确定 A<script type="math/tex" id="MathJax-Element-1202">A</script> 点后,B<script type="math/tex" id="MathJax-Element-1203">B</script> 点只能在图中阴影内(包括边缘)取值,因此有:
x2∈X=x1+s?1,x1+2s?1,?,x1+ps?1,
<script type="math/tex; mode=display" id="MathJax-Element-1204">x_2∈X={x_1+s-1, x_1+2s-1,?, x_1+ps-1},</script>
y2∈Y=y1+t?1,〖y〗1+2t?1,?,y1+qt?1,
<script type="math/tex; mode=display" id="MathJax-Element-1229">y_2∈Y={y_1+t-1,〖 y〗_1+2t-1,?,y_1+qt-1},</script>
其中 p=[(m?x1+1)/s],q=[(m?y1+1)/t]<script type="math/tex" id="MathJax-Element-1230">p=[(m-x_1+1)/s],q=[(m-y_1+1)/t]</script> ,并且|X|=p,|Y|=q<script type="math/tex" id="MathJax-Element-1231"> |X|=p,|Y|=q</script>。
由上分析可知,在m<script type="math/tex" id="MathJax-Element-1232">m</script>×m<script type="math/tex" id="MathJax-Element-1233">m</script> 子窗口中,满足 (s,t)<script type="math/tex" id="MathJax-Element-1234">(s,t)</script> 条件的所有矩形的数量为:
实际上,(s,t)<script type="math/tex" id="MathJax-Element-1235">(s,t)</script> 条件描述了矩形的特征,下面列出了不同矩形特征对应的 (s,t)<script type="math/tex" id="MathJax-Element-1236">(s,t)</script> 条件:
所以 m<script type="math/tex" id="MathJax-Element-1237">m</script>×m<script type="math/tex" id="MathJax-Element-1238">m</script> 子窗口中所有5种特征模板的特征总数量 Ωm<script type="math/tex" id="MathJax-Element-1239">?^m</script> ,就是分别满足5个(s,t)<script type="math/tex" id="MathJax-Element-1240">(s,t)</script>条件的矩形特征的数量的总和,即:
Ωm=Ωm(1,2)+Ωm(2,1)+Ωm(1,3)+Ωm(3,1)+Ωm(2,2)
<script type="math/tex; mode=display" id="MathJax-Element-977">?^m= ?_{(1,2)}^m+?_{(2,1)}^m+?_{(1,3)}^m+?_{(3,1)}^m+?_{(2,2)}^m</script>
特别地,由于特征模板 1 和 2、3 和 4 具有旋转对称性,则可以进一步简化为:
Ωm=2Ωm(1,2)+2Ωm(1,3)+Ωm(2,2)
<script type="math/tex; mode=display" id="MathJax-Element-978">?^m= 2?_{(1,2)}^m+2?_{(1,3)}^m+?_{(2,2)}^m</script>
下面以24×24子窗口为例,具体计算其特征总数量:
下面列出了,在不同子窗口大小内,特征的总数量:
2.2.2.3 再次讨论Harr特征个数
最早的Haar特征由Papageorgiou C.等提出(《A general framework for object detection》),后来Paul Viola和Michal Jones提出利用积分图像法快速计算Haar特征的方法(《Rapid object detection using a boosted cascade of simple features》)。之后,Rainer Lienhart 和 Jochen Maydt用对角特征对Haar特征库进行了扩展(《An extended set of Haar-like features for rapid object detection》)。OpenCV的Haar分类器就是基于扩展后的特征库实现的。在该论文中,作者提出了Harr特征个数的公式:
XY(W+1?w(X+1)/2)(H+1?h(Y+1)/2)
<script type="math/tex; mode=display" id="MathJax-Element-1144">XY(W+1-w (X+1)/2)(H+1-h (Y+1)/2)</script>
其中, W<script type="math/tex" id="MathJax-Element-1145">W</script>×H<script type="math/tex" id="MathJax-Element-1146">H</script>为窗口大小,w<script type="math/tex" id="MathJax-Element-1147">w</script>×h<script type="math/tex" id="MathJax-Element-1148">h</script>为矩形特征大小,X=?W/w?,Y=?H/h?<script type="math/tex" id="MathJax-Element-1149">X=?W/w?,Y=?H/h? </script>表示矩阵特征在水平和垂直方向能放大的最大比例系数。
对于旋转45°的矩形特征(如1c和1d),w、h<script type="math/tex" id="MathJax-Element-1150">w、h</script> 表示如下图所示:
其计算公式为:
XY(W+1?z(X+1)/2)(H+1?z(Y+1)/2), z=w+h.
<script type="math/tex; mode=display" id="MathJax-Element-1151">XY(W+1-z (X+1)/2)(H+1-z (Y+1)/2),\ \ \ \ \ \ \ z=w+h. </script>
Remark: 我觉得对于旋转45°的矩形个数计算公式中,除了z<script type="math/tex" id="MathJax-Element-1152">z</script>值变化外,X<script type="math/tex" id="MathJax-Element-1153">X</script> 和Y<script type="math/tex" id="MathJax-Element-1154">Y</script>的值也应该变为:X=?W/z?,Y=?H/z?<script type="math/tex" id="MathJax-Element-1155">X=?W/z?,Y=?H/z?</script>。
下面是我理解的计算过程,跟前一节条件矩形数量的计算类似:
1)对于某固定大小的特征矩形,在窗口内计算其可滑动的次数。
2)对于某一特征,特征本身可在水平和垂直两个方向分别缩放。
清楚这两点,我们就可以很容易的写出计算特征个数的代码:
由以上的代码,我们很容易推导出论文中提到的Harr特征个数公式,证明如下:
对于45°特征,由于Rainer Lienhart定义的w、h<script type="math/tex" id="MathJax-Element-1156">w、h</script>与原矩阵含义不同,即实际滑动的矩阵框为(w+h)<script type="math/tex" id="MathJax-Element-1157">(w+h)</script>×(w+h)<script type="math/tex" id="MathJax-Element-1158">(w+h)</script>。所以只要用如下方式调用原函数即可:GetHarrLikeCount(W, H, w+h, w+h)。
运行结果如下:
将此结果跟论文比较,结果基本一致。论文中的结果如下:
2.3 积分图
2.3.1定义
一个简单的微积分类比:如果我们要经常计算 ∫baf(x)dx<script type="math/tex" id="MathJax-Element-1159"> \int_a^b f(x) {\rm d}x </script> ,那我们会先计算F(x)=∫f(x)dx<script type="math/tex" id="MathJax-Element-1160"> F(x) = \int f(x) {\rm d}x </script>,那么∫baf(x)dx=F(b)?F(a)<script type="math/tex" id="MathJax-Element-1161"> \int_a^b f(x) {\rm d}x = F(b) - F(a)</script>,见下图:
积分图的含义与此类似。2001年,Viola等提出积分图(Integral Image)概念,其目的是为了快速的计算分类器所需的矩形特征。定义一副图像的像素灰度为 I(x,y)<script type="math/tex" id="MathJax-Element-1162">I(x,y)</script>,则对于图像内一点 A(x,y)<script type="math/tex" id="MathJax-Element-1163">A(x,y)</script>,定义其积分图SAT(x,y)<script type="math/tex" id="MathJax-Element-1164">SAT(x,y)</script>为:
SAT(x,y)=∑x′≤x,y′≤yI(x′,y′) ,
<script type="math/tex; mode=display" id="MathJax-Element-1165"> SAT(x,y)=\sum_{x‘≤x, y‘≤y} I(x‘,y‘) \ , </script>
其中 I(x′,y′)<script type="math/tex" id="MathJax-Element-1166">I(x‘,y‘)</script> 为点 (x′,y′)<script type="math/tex" id="MathJax-Element-1167">(x‘,y‘)</script> 处原始图在此点的颜色值;对于灰度图,其值为 0 ~ 255。对于彩色图像,是此点的颜色值。
要得到一幅输入图像的积分图像,只需逐点扫描原图像一次,就可计算出来。即:
s(x,y)=s(x,y?1)+I(x,y)
<script type="math/tex; mode=display" id="MathJax-Element-1168">s(x,y)=s(x,y-1)+ I(x,y)</script>
SAT(x,y)=SAT(x?1,y)+s(x,y)
<script type="math/tex; mode=display" id="MathJax-Element-66">SAT(x,y)=SAT(x-1,y)+s(x,y)</script>
其中 s(x,y)<script type="math/tex" id="MathJax-Element-67">s(x,y)</script> 表示点 (x,y)<script type="math/tex" id="MathJax-Element-68">(x,y)</script> 在 y<script type="math/tex" id="MathJax-Element-69">y</script> 方向的所有原始图像之和,称为“列积分和”,可以定义为:
s(x,y)=∑y′≤yI(x,y′)
<script type="math/tex; mode=display" id="MathJax-Element-70">s(x,y)= \sum_{y‘≤y}I(x,y‘) </script>
并定义 s(x,0)=0, SAT(0,y)=0<script type="math/tex" id="MathJax-Element-71">s(x,0)=0, \ SAT(0,y)=0</script>。
2.3.2利用积分图计算矩形特征值
一个区域的像素值,可以利用该区域端点的积分图来计算,如下图所示:
区域 D 的像素值,可以利用 1、2、3、4 点的积分图来计算。在上图中,我们用 SAT1<script type="math/tex" id="MathJax-Element-1241">SAT_1</script> 表示区域A<script type="math/tex" id="MathJax-Element-1242">A</script>的像素值,SAT2<script type="math/tex" id="MathJax-Element-1243">SAT_2</script> 表示区域 A+B<script type="math/tex" id="MathJax-Element-1244">A+B</script> 的像素值,SAT3<script type="math/tex" id="MathJax-Element-1245">SAT_3</script> 表示区域 A+C<script type="math/tex" id="MathJax-Element-1246">A+C</script> 的像素值,SAT4<script type="math/tex" id="MathJax-Element-1247">SAT_4</script> 表示区域A+B+C+D<script type="math/tex" id="MathJax-Element-1248">A+B+C+D</script> 的像素值,由此可得:
区域D的像素值=SAT4+SAT1?SAT2?SAT3.
<script type="math/tex; mode=display" id="MathJax-Element-80">区域 D 的像素值 = SAT_4+SAT_1-SAT_2-SAT_3.</script>
因此,由积分图可以快速得到一个区域的像素值。
2.3.3计算特征模板的特征值
由上一节已经知道,一个区域的像素值,可以由该区域端点的积分图来计算。由前面特征模板的特征值的定义可以推出,矩形特征的特征值可以由特征端点的积分图计算出来。以“两矩形特征”中的第二个特征为例,如下图,使用积分图计算其特征值:
![这里写图片描述](http://img.blog.csdn.net/20160920103450957)
该特征模板的特征值,由定义知,为区域 A<script type="math/tex" id="MathJax-Element-81">A</script> 的像素值减去区域 B<script type="math/tex" id="MathJax-Element-82">B</script> 的像素值。由上节知:
区域A的像素值=SAT5+SAT1?SAT2?SAT4,
<script type="math/tex; mode=display" id="MathJax-Element-83">区域 A 的像素值 = SAT_5+SAT_1-SAT_2-SAT_4,</script>
区域B的像素值=SAT6+SAT2?SAT5?SAT3.
<script type="math/tex; mode=display" id="MathJax-Element-84">区域 B 的像素值 = SAT_6+SAT_2-SAT_5-SAT_3.</script>
因此该特征模板的特征值为:
SAT5+SAT1?SAT2?SAT4–(SAT6+SAT2?SAT5?SAT3)=
<script type="math/tex; mode=display" id="MathJax-Element-85"> SAT_5+SAT_1-SAT_2-SAT_4 –(SAT_6+SAT_2-SAT_5-SAT_3 )= </script>
(SAT5?SAT4)+(SAT3?SAT2)?(SAT2?SAT1)?(SAT6?SAT5).
<script type="math/tex; mode=display" id="MathJax-Element-86"> (SAT_5-SAT_4 )+(SAT_3-SAT_2 )-(SAT_2-SAT_1 )-(SAT_6-SAT_5). </script>
所以特征模板的特征值,只与特征矩形端点的积分图有关,而与图像的坐标无关。通过计算特征矩形端点的积分图,再进行简单的加减运算,就可以得到特征值。正因为如此,特征的计算速度大大提高,也提高了目标的检测速度。
2.3.4计算旋转45°的矩形特征
在旋转积分图中,每个点存储的是其左上方〖45〗^o区域范围内所有像素之和:
RSAT(x,y)=∑y′≤y,y′≤y?|x?x′|I(x′,y′)
<script type="math/tex; mode=display" id="MathJax-Element-1251">RSAT(x,y)=\sum_{y‘≤y,y‘≤y-|x-x‘ |} I(x‘,y‘)</script>
RSAT(x,y)<script type="math/tex" id="MathJax-Element-1252">RSAT(x,y)</script> 也可以采用增量方式计算得到:
RSAT(x,y)=RSAT(x?1,y?1)+RSAT(x+1,y?1)?RSAT(x,y?2)+I(x,y)+I(x,y?1).
<script type="math/tex; mode=display" id="MathJax-Element-89">RSAT(x,y)=RSAT(x-1,y-1)+RSAT(x+1,y-1)-RSAT(x,y-2)+I(x,y)+I(x,y-1) .</script>
初始边界:
RSAT(?1,y)=RSAT(x,?1)=RSAT(x,?2)=RSAT(?1,?1)=RSAT(?1,?2)=0.
<script type="math/tex; mode=display" id="MathJax-Element-90">RSAT(-1,y)= RSAT(x,-1)=RSAT(x,-2)=RSAT(-1,-1)=RSAT(-1,-2)=0.</script>
【同步本人网易博客文章】AdaBoost 人脸检测介绍(2) : 矩形特征和积分图
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘