Opencv2.4.9源码分析——Cascade Classification(一)

我把级联分类器分为三部分内容介绍,第一部分内容是原理。

物体识别,尤其是人脸识别,是近二、三十年里计算机视觉领域一个热门的课题。它的应用范围极广,目前成熟的算法也较多。OpenCV也集成了一个物体识别的算法,它主要是基于Viola和Jones这两个人于2001年提出的震惊业界的Viola & Jones算法,该算法最初是用于人脸识别,但在对其它刚性物体的识别上效果也极佳。

Viola & Jones算法创新之处在于,它把下面三种方法首次集成用于人脸识别中:

(1)、应用HAAR状特征,并采用积分图像的方法计算该特征值;

(2)、应用AdaBoost算法选择适用于人脸的HAAR状特征;

(3)、把各类由AdaBoost算法得到的强分类器级联起来得到最终的级联分类器。

这三种方法整合在一起,大大提高了最终的级联分类器的准确率和速度。下面我们就来详细讲解Viola & Jones算法。

Viola & Jones算法采用大量的正样本图像和负样本图像来训练级联分类器,正样本图像是各种人脸图像,负样本图像是任意非人脸图像。我们要从正、负样本中找到区别于其他物体的人脸特征。Viola & Jones算法不是采用基于像素的特征,而是采用HAAR状特征。图1呈现了一些常用于人脸识别的HAAR状特征。

《Opencv2.4.9源码分析——Cascade Classification(一)》

图1 HAAR状特征

从图1可以看出,每个HAAR状特征就是一个模板,模板内包括黑色区域和白色区域。例如,如果想检测图像中的边缘,则用代表边缘的HAAR状特征模板对图像进行扫描,分别计算模板所覆蓋的白色区域内和黑色区域内的所有像素灰度值之和,然后两者相减,这个差值就是该模板在该位置上的特征值。只要把该特征值与事先设置好的阈值相比较,就可以判断出该位置是否为边缘像素。特征值判断的一般公式为:

《Opencv2.4.9源码分析——Cascade Classification(一)》(1)

式中,x表示图像,f(x)表示该图像的特征值,θ为阈值,h(x)表示该图像最终的分类结果。一般情况下,我们很难得到这个阈值θ,或者说根本不存在这样一个能准确分类图像的值。因此我们只要把使分类错误程度最小的那个值作为阈值即可。

《Opencv2.4.9源码分析——Cascade Classification(一)》

图2 人脸检测所用到的HAAR状特征的示例

很显然,HAAR状特征不仅有类别的差异,还有大小的不同,即模板的大小尺寸也是可以变化的。图2表现了一些HAAR状特征对人脸检测的示例。

因此对于图像的特征,不仅涉及到模板的类型,还涉及到模板的大小,以及模板的位置。这样一来,图像的特征会有成千上万。例如对于一个24×24大小的人脸图像来说,它共有大约180,000多个特征,这要远远大于该尺寸大小的像素的数量(24×24=576)。但如果我们采用积分图像的方法,则计算HAAR状特征的特征值的效率会显著提高,以至于比计算特征是像素的方法还要快。这是因为积分图像非常适用于对矩形区域内所有像素灰度值之和的计算,而HAAR状特征的特征值正是这类计算。

积分图像很早就被应用在计算机图形学中,但直到Viola & Jones算法的提出,才把它应用到计算机视觉领域中。积分图像IΣ(x, y)的大小尺寸与原图像I(x, y)的大小尺寸相等,而积分图像在(x, y)处的值等于原图像中横座标小于等于x并且纵座标也小于等于y的所有像素灰度值之和,也就是在原图像中,从其左上角到(x, y)处所构成的矩形区域内所有像素灰度值之和,即

《Opencv2.4.9源码分析——Cascade Classification(一)》(2)

事实上,积分图像的计算十分简单,只需要对原图像进行一次扫描,就可以得到一幅完整的积分图像,它的计算公式有几种,下列公式是其中的一种:

《Opencv2.4.9源码分析——Cascade Classification(一)》(3)

其中,IΣ(x-1, y)、IΣ(x, y-1)和IΣ(x-1, y-1)都是在计算IΣ(x, y)之前得到的值。

《Opencv2.4.9源码分析——Cascade Classification(一)》

图3 积分图像求矩阵内灰度值之和

利用积分图像可以计算原图像中任意矩形内像素灰度值之和。如图3所示,某图像I(x, y)中有四个点,它们的座标分别为A=(x0, y0),B=(x1, y0),C=(x0, y1)和D=(x1, y1)。由这4个点组成了矩阵W,该W内的像素灰度之和为:

《Opencv2.4.9源码分析——Cascade Classification(一)》(4)

其中,IΣI的积分图像。Lienhart等人又在此基础上,提出了旋转积分图像的计算方法,这样就可以更方便的计算图1所示的那些倾斜45度角的HAAR状特征的特征值。

由式4可知,一旦图像的积分图像确定下来,图像中任意矩阵区域内的灰度值之和就可以很容易的得到。更重要的是,无论矩阵面积多大,所需要的运算量都是相同的。因此当算法中需要大量重复的计算不同矩阵区域内的灰度值之和时,应用积分图像就可以大大地提高效率。

如前所述,如果我们用HAAR状特征,则表征图像的就不再是常用的图像像素,而是每个HAAR状特征的特征值。但特征值太多,并不是每个特征都是人脸所固有的特征,我们怎样从大量的特征中选取那些待识别物体与其他物体不同的特征呢?Viola & Jones算法采用了改进的AdaBoost算法。

AdaBoost算法可以通过一系列弱分类器的线性组合得到一个强分类器。尽管弱分类器的分类效果可能仅仅比猜想的要好一点点,但最终的强分类器却可以得到令人吃惊的分类效果。

之所以会出现这种现象,是因为在每次循环迭代生成弱分类器后,都会对样本权值重新赋值,即把分类正确的样本的权值变小,而把分类错误的样本权值增大,这样就能保证在下一个迭代生成弱分类器时,会把更多的关注分配给前一个弱分类器分类错误的样本上,以至于出现了最终的强分类器会随着弱分类器数量的增加而性能提高这一特点。

常规的AdaBoost算法共有四种:Discrete Adaboost,Real AdaBoost,LogitBoost和Gentle AdaBoost,这几种算法的主要区别就是样本权值的计算,以及弱分类器的线性组合上。Viola & Jones算法应用的是不同于以上4种算法的另一种改进的AdaBoost算法,它的执行步骤为:

■给出样本(x1, y1),(x2, y2), …, (xn,yn),其中正样本的数量为l,负样本为m,定义正样本的响应值为1,负样本为0;

■ 为样本初始化权值,第i个样本的权值w1,i为:

《Opencv2.4.9源码分析——Cascade Classification(一)》

■迭代循环t=1,…,T

    1) 归一化权值:    

《Opencv2.4.9源码分析——Cascade Classification(一)》

    2) 为每一个特征j,训练一个分类器hj,即hj只能用于特征j,而该特征j的基于权值的误差εj为:

《Opencv2.4.9源码分析——Cascade Classification(一)》

    3) 在所有误差中最小的那个误差εt所对应的分类器作为此次迭代得到的弱分类器ht

    4) 更新权值:

《Opencv2.4.9源码分析——Cascade Classification(一)》

■最终的强分类器为:

《Opencv2.4.9源码分析——Cascade Classification(一)》

弱分类器ht是基于单个特征的,它的形式如式1所示。简单的说,训练弱分类器的过程就是得到最佳特征以及它所对应的阈值的过程。这种弱分类器可以看成是仅仅有一个节点的决策树,即树墩形(stump)的决策树。由于每次迭代,样本的权值不同,分类错误的程度会发生变化,所以每次迭代的阈值是不同。图2中呈现的特征就是迭代初期所选取得到的主要HAAR状特征。

由AdaBoost算法得到的强分类器用于人脸识别还远远不够,因为这里还会涉及到两个问题。第一问题是在实际识别过程中,人脸图像的数量会远远小于非人脸图像的数量,我们应该首先剔除掉那些明显不是人脸的图像,即我们不应该把过多的精力花费到对非人脸图像的识别上。第二个问题是我们在提高识别率的同时,错误率也会显著提高,即识别率和错误率具有相同的变化趋势和程度。这里的识别率指的是能够正确识别物体的程度,而错误率指的是把非待识别物体当成识别物体的程度。例如一共有200个样本,正、负样本各100个,我们能够把正样本全部识别出来,此时的识别率为100%,但同时有50个负样本也被当成了正样本,则此时的错误率为50%。

为了解决上述两个问题,Viola & Jones算法使用了级联分类器这一概念。

《Opencv2.4.9源码分析——Cascade Classification(一)》

图4 级联分类器

级联分类器的每级都是一个强分类器,它只把它认为是正样本的图像传递给下一级,而把负样本直接抛弃,因此如果每级强分类器具有相同的识别率和错误率的话,那么后一级的强分类器一定会比前一级的强分类器具有更复杂的结构,即后一级的强分类器具有更多的弱分类器,由于弱分类器就是对单一特征的判断,所以级联分类器的每一级强分类器所需要的特征是递增的。另外,级联分类器的识别率和错误率分别是每一级强分类器的识别率和错误率的乘积,因此只要保证每级强分类器具有接近100%的识别率,最终级联分类器的识别率也会很高,而级联分类器的错误率却可以达到极低的水平。例如,每级强分类器的识别率和错误率分别都是99%和50%,那么由10级强分类器构成的级联分类器的识别率和错误率分别为90.4%和0.098%。

下面是训练级联分类器的过程:

■定义每级强分类器的最小识别率和最大错误率分别为df,定义最终所要得到的级联分类器的错误率为Ftarget

■设DiFi分别表示级联分类器的识别率和错误率,下标i表示该级联分类器的级数,PN分别表示全体正样本集和负样本集,ni表示第i个强分类器的弱分类器的数量,即该强分类器利用ni个特征来识别物体

■初始化Di=1.0,Fi=1.0,i=0

■在FiFtarget条件下循环

    ♦ ii+1

    ♦ ni=0;Fi=Fi-1

    ♦ 在Fif×Fi-1条件下循环

          ● nini+1

          ● 在PN下,利用AdaBoost算法训练得到具有ni个弱分类器的一个强分类器

          ● 评估当前级联分类器,在验证集合中的得到DiFi

          ● 降低第i个强分类器的阈值,直至Di至少等于d×Di-1为止,降低阈值也一定会影响到Fi

    ♦ 设N为空集

    ♦ 如果FiFtarget,则用当前级联分类器评估负样本集,把识别得到的所有错误率下的样本放入N

在级联分类器的训练过程中,需要注意一点的是,每训练一个AdaBoost强分类器,都需要重新更新训练样本集,也就是一定要满足后一个强分类器训练的样本必须为前一个强分类器识别分类为正样本的那些样本。具体的做法是,用当前得到的级联分类器对正、负样本进行识别,选取满足一定数量要求的仍然被分类为正样本的那些正样本作为此次AdaBoost强分类器的正训练样本集,以及被错误分类为正样本的那些负样本作为负训练样本集。由于我们设定的d都较高,因此可以对正训练样本集无需更新,仅仅把正样本集作为正训练样本集即可。

当级联分类器训练好后,我们就可以对目标进行识别。但往往待识别图像比训练样本图像要大,这时就需要用级联分类器对待识别图像进行扫描,并不断改变级联分类器的尺寸大小,因为Viola & Jones算法认为改变HAAR状特征的尺寸要比改变待识别图像的尺寸容易。

以上我们给出了完整的Viola & Jones人脸识别算法。Opencv的级联分类器是基于该算法的,但也做了一些改进。首先弱分类器不再是树墩形的决策树,而是更广义的决策树,也就是说一个弱分类器可以同时判断多个特征,我们可以通过设定决策树的深度来控制它的特征判断的数量,但此时级联分类器的错误率不再仅仅是所有强分类的错误率的乘积,而需要再除以这个决策树的深度。而当决策树的深度为1时,它就是树墩形的决策树。

第二个重要的改进是特征不再仅仅是HAAR状特征,还包括了LBP特征和HOG特征。下面我们就来介绍后两种特征。

《Opencv2.4.9源码分析——Cascade Classification(一)》

图5 LBP编码

LBP(Local BinaryPatterns,局部二值模式)是在计算机视觉领域中用于分类的一种可视描述符,它是一种用于图像纹理分类的特征。LBP的最初定义是,在一个3×3的窗体内,以中心像素的灰度值为阈值,比较其8邻域内的其他像素的灰度值,大于阈值则重新赋值为1,否则为0,然后从左上角开始按逆时针排序,组成的二进制数(即编码)就是中心像素的LBP特征的特征值,如图5所示,它的特征值为01111100,它所对应的十进制数为124。

《Opencv2.4.9源码分析——Cascade Classification(一)》

图6 LBP特征

通过这种二进制LBP编码,我们可以看出中心像素的一些特征。8邻域像素经比较后如果是1则表示为黑,是0则为白。如图6所示,我们可以直观的看出LBP能够很好的表现点、线、边缘和角等的特征。

广义上,我们可以把像素扩展为一个大小相同的由多个像素组成的矩形区域,区域的值为该区域内所有像素灰度值之和,而阈值比较和二进制编码与图5所示的方法相同。这样我们就得到了尺寸大小不同的LBP特征。

《Opencv2.4.9源码分析——Cascade Classification(一)》

图7 广义LBP编码

如图7所示,中心区域4的8个邻域分别为区域0~区域3和区域5~区域8,这9个区域可以是面积相同的任意矩形。由p0,p1,p4和p5这四个像素所组成的区域0的值可以由前面介绍的积分图像的方法求得,其他区域的值的计算方法相同。

HOG(Histogram ofOriented Gradient,方向梯度直方图)也是一种用于物体识别的特征描述符。该方法的本质是图像中局部目标或形状可以用强度梯度或边缘方向的分布加以描述。我们可以把图像分割为若干个称为cell的小区域,对于cell内的像素,可以得到它们的梯度方向的直方图。而为了降低图像局部的阴影和光照变化的影响,我们可以得到被称为block的大区域,对block内的所有cell进行归一化处理。

下面就来详细介绍HOG算法。首先计算像素的梯度,它可以应用下列算子分别得到水平梯度Gx和垂直梯度Gy

[-1,0, 1] 和 [-1, 0, 1]T      (5)

则该像素的梯度幅值G和角度θ为(我们可以把θ限制在0~π之间):

《Opencv2.4.9源码分析——Cascade Classification(一)》(6)

《Opencv2.4.9源码分析——Cascade Classification(一)》(7)

然后计算cell的直方图。我们把π分隔成9份,每一份称为bin,即0~π之间共有9个bin。我们统计cell内所有像素梯度角度是属于这9个bin中的哪一个,并把属于该bin的所有像素的梯度幅值累加作为该bin的值,这样就得到了该cell的梯度方向直方图。

最后在block内进行归一化处理,简单的方法是把block内的所有cell的所有bin值都除以该block内所有像素梯度幅值之和。

在这里,每一block就是一个HOG特征。block可以是矩形,也可以是圆形。当是矩形时,每个block一般包括4个cell,因此一个HOG特征包含36(4×9)个bin值,这个bin值我们又称为特征成分(component)。cell的大小可以为
t×
t,2
t×
t
t×2
t
t为8的整数倍,即8,16,24……。随着
t的变化,block的大小也在变化,HOG特征的尺寸也随之变化,以适应不同大小的目标识别。而在同一尺度下,不同的block可以重叠交错,即同一个cell可以属于不同的block。

点赞