opencv Haar+AdaBoost分类器+Cascade

写的很乱,仅供自己做笔记使用吧。。。。。。。。


1-以Haar为始,Haar各种特征示例:

                                  这里写图片描述

      看着上面这一大堆黑白块,我想应该不难理解矩形特征这个词——黑白两部分嘛。规则不是特征,但按某个规则可以找到特征的话,当我们有了很多很多很多规则之后……这就是Haar特征的思想,每一个小黑白块就是一种规则,也是一种特征,也是一个分类器。不过单独一个这样的分类器当真不敢恭维,所以,他们都是弱分类器,他们能做得不多,就像战场上的士兵不计其数,组合在一起却会有意想不到的变化。

2 - 以AdaBoost成形

      Boost就是把一堆准确率跟随机数差不多的弱分类器集合在一起变成一个强大的强分类,只是他宁可放过不可错杀还是宁可错杀不可放过的阈值选择问题让人们备受困扰。想要提高正确率就要降低阈值,错误率也会变高,想要降低错误率就要提高阈值,正确率也会降低。这是一个无比头疼却又无可奈何的问题。

既然如此,就让Cascade出场吧。这种问题,决策树最喜欢了。

3 - 以Cascade扭转乾坤

Cascade即为级联,AdaBoost解决了士兵的众说纷纭,成为了一方名将。而级联的出现,就是要集百家名说成一方之言——一次决断,多方铭鉴。如果我能找到99.9%的目标分类,那错误的分类中哪怕有50%误入结果,20轮之后也将不足为惧:20级的级联足够在99.9%变成99%的过程中,把50%变成0.0001%。
  这就是级联,或者说表现成的决策树。让每一个AdaBoost出身的强分类器依次进行决策,被认为是正确的就将向下传递,错误的则被直接抛弃。再配合权重改变样本的分布,训练,上场,一锤定音。

   链接:https://www.jianshu.com/p/bfa54561960e


      众所周知,OpenCV中的Adaboost级联分类是树状结构,如图1,其中每一个stage都代表一级强分类器。当检测窗口通过所有的强分类器时才被认为是目标,否则拒绝。实际上,不仅强分类器是树状结构,强分类器中的每一个弱分类器也是树状结构。

                       

弱分类器结构

Haar特征和弱分类器之间的关系:

一个完整的弱分类器包括: 

1.若干个Haar特征 + 和Haar特征数量相等的弱分类器阈值

2. 若干个leftValue

3. 若干个rightValue

这些元素共同构成了弱分类器,缺一不可。haarcascade_frontalface_alt2.xml的弱分类器Depth=2,包含了2种形式,下图为Depth=2的树状弱分类器示意图。图中的左边形式包含2个Haar特征、1个leftValue、2个rightValue和2个弱分类器阈值(t1和t2);右边形式包括2个Haar特征、2个leftValue、1个rightValue和2个弱分类器阈值。

                         

接下来我们了解树状弱分类器是如何工作的。还是以图3左边的形式为例:

  1. 计算第一个Haar特征的特征值haar1,与第一个弱分类器阈值t1对比,当haar1<t1时,进入步骤2;当haar1>t1时,该弱分类器输出rightValue2并结束。
  2. 计算第二个Haar特征值haar2,与第二个弱分类器阈值t2对比,当haar2<t2时输出leftValue;当haar2>t2时输出rightValue1。

     通过上述步骤计算弱分类器输出值,即通过计算出的Haar特征值与弱分类器阈值对比,从而选择最终输出leftValue和rightValue值中的哪一个。

强分类器结构

     在OpenCV中,强分类器是由多个弱分类器“并列”构成,即强分类器中的弱分类器是两两相互独立的。在检测目标时,每个弱分类器独立运行并输出cascadeLeaves[leafOfs - idx]值,然后把当前强分类器中每一个弱分类器的输出值相加,即:


级联分类器

     在OpenCV中:由弱分类器“并联”组成强分类器,而由强分类器“串联”组成级联分类器。那么还剩最后一个内容,那就是检测窗口大小固定(例如alt2是20*20像素)的级联分类器如何遍历图像,以便找到在图像中大小不同、位置不同的目标。

1. 为了找到图像中不同位置的目标,需要逐次移动检测窗口(窗口中的Haar特征相应也随着移动),这样就可以遍历到图像中的每一个位置;

2. 而为了检测到不同大小的目标,一般有两种做法:逐步缩小图像or逐步放大检测窗口,这样即可遍历到图像中不同大小的目标

from:https://blog.csdn.net/beizhengren/article/details/77095841 



利用haar特征,结合级联分类器进行人脸检测:

Haar分类器 = Haar-like特征 + 积分图方法 + AdaBoost +级联;

Haar分类器算法的整体思路如下:

  1. 计算积分图,使用积分图(Integral Image)对Haar-like进行特征求值
  2. 挑选最优分类器;
  3. 使用AdaBoost算法把这些分类器训练成一个强分类器,用于区分人脸和非人脸
  4. 级联,也就是强分类器的强强联手。把强分类器级联到一起,提高准确率。

       在开始前,一定要记住,以24*24窗口为例,就有16万+的特征数量,所以首先要从中筛选有用的特征(即最优弱分类器,第3步),然后利用AdaBoost将这些最优弱分类器训练成一个强分类器,最后将强分类器进行级联。

 

 

1、计算特征值和积分图

2、挑选最优分类器

之前一直以为计算到haar特征值后,然后直接用AdaBoost进行训练强分类器,大错特错!以24*24为例,16万+个特征值,如果直接利AdaBoost训练,那么工作量是极其极其巨大的。所以必须有个筛选的过程,筛选出T个优秀的特征值(即最优弱分类器),然后把这个T个最优弱分类器传给AdaBoost进行训练。

如何挑选?

    最初的弱分类器可能只是一个最基本的Haar-like特征,计算输入图像的Haar-like特征值,和最初的弱分类器的特征值比较,以此来判断输入图像是不是人脸,然而这个弱分类器太简陋了,可能并不比随机判断的效果好,对弱分类器的孵化就是训练弱分类器成为最优弱分类器,注意这里的最优不是指强分类器,只是一个误差相对稍低的弱分类器,训练弱分类器实际上是为分类器进行设置的过程。至于如何设置分类器,设置什么,我们首先分别看下弱分类器的数学结构。

                                        

 其中 f为特征,θ为阈值,p指示不等号的方向,x表示一个检测子窗口。对每个特征 f,训练一个弱分类器 h(x,f,p,θ),就是确定f的最优阈值,使得这个弱分类器 h(x,f,p,θ)对所有训练样本的分类误差最小。

弱分类器的孵化: 

对于每个特征 f,计算所有训练样本的特征值,并将其排序,对排好序的表中的每个元素,计算下面四个值:

  • 全部人脸样本的权重的和T+;
  • 全部非人脸样本的权重的和T−;
  • 该元素前的人脸样本的权重的和S+;
  • 该元素前的非人脸样本的权重的和S−;

      选取当前元素的特征值和它前面的一个特征值之间的数作为阈值,所得到的弱分类器就在当前元素处把样本分开为2类—— 这个阈值对应的弱分类器将当前元素前的所有元素分为人脸(或非人脸),而把当前元素后(含)的所有元素分为非人脸(或人脸)。该阈值的分类误差为:

                                         

    通过把这个排序表从头到尾扫描一遍就可以为弱分类器选择使分类误差最小的阈值(最优阈值),有了该阈值,我们的第一个最优弱分类器就诞生了。也就是选取了一个最佳弱分类器。当输入图片的特征值大于该阈值时才判定其为人脸。训练最优弱分类器的过程实际上就是在寻找合适的分类器阈值,使该分类器对所有样本的判读误差最低。一个弱分类器就是一个基本和上图类似的决策树,最基本的弱分类器只包含一个Haar-like特征,也就是它的决策树只有一层,被称为树桩(stump)。

                        这里写图片描述

3、利用AdaBoost训练一个强分类器

此时,我们手中有T个最优弱分类器(在第3步中得到),现在就要利用AdaBoost算法了:

强分类器的诞生需要T轮的迭代,具体操作如下:

1. 给定训练样本集S,共N个样本,其中X和Y分别对应于正样本和负样本; T为训练的最大循环次数;

2. 初始化样本权重为1/N,即为训练样本的初始概率分布;

3. 第一次迭代训练N个样本,得到第一个最优弱分类器,步骤见上文的弱分类器的孵化;

4. 提高上一轮中被误判的样本的权重;

5. 将新的样本和上次本分错的样本放在一起进行新一轮的训练。

6. 循环执行4-5步骤,T轮后得到T个最优弱分类器。

7.组合T个最优弱分类器得到强分类器,如上图所示。

    相当于让所有弱分类器投票,再对投票结果按照弱分类器的错误率加权求和,将投票加权求和的结果与平均投票结果比较得出最终的结果。强分类器的脱颖而出更像是民主的投票制度。但从宏观的局外的角度看,整个AdaBoost算法就是一个弱分类器从孵化到化蝶的过程。

4、级联,也就是强分类器的强强联手

     我们看到了通过AdaBoost算法辛苦的训练出了强分类器,然而在现实的人脸检测中,只靠一个强分类器还是难以保证检测的正确率,这个时候,需要一个豪华的阵容,训练出多个强分类器将它们强强联手,最终形成正确率很高的级联分类器这就是我们最终的目标Haar分类器。

      级联强分类器的策略是,将若干个强分类器由简单到复杂排列,希望经过训练使每个强分类器都有较高检测率,而误识率可以放低,比如几乎99%的人脸可以通过,但50%的非人脸也可以通过,这样如果有20个强分类器级联,那么他们的总识别率为0.99^20约等于98%,错误接受率也仅为0.5^20约等于0.0001%。这样的效果就可以满足现实的需要了,但是如何使每个强分类器都具有较高检测率呢?

下面我们讲讲级联分类器的训练。

      设K是一个级联检测器的层数,D是该级联分类器的检测率,F是该级联分类器的误识率,di是第i层强分类器的检测率,fi是第i层强分类器的误识率。如果要训练一个级联分类器达到给定的F值和D值,只需要训练出每层的d值和f值,这样:d^{K}=D,f^{K}=F级联分类器的要点就是如何训练每层强分类器的d值和f值达到指定要求。

检测   

      Haar分类器的另一个体系,检测体系是以现实中的一幅大图片作为输入,然后对图片中进行多区域,多尺度的检测,所谓多区域,是要对图片划分多块,对每个块进行检测,由于训练的时候用的照片一般都是20*20左右的小图片,所以对于大的人脸,还需要进行多尺度的检测,多尺度检测机制一般有两种策略,一种是不改变搜索窗口的大小,而不断缩放图片,这种方法显然需要对每个缩放后的图片进行区域特征值的运算,效率不高,而另一种方法,是不断初始化搜索窗口size为训练时的图片大小,不断扩大搜索窗口,进行搜索,解决了第一种方法的弱势。在区域放大的过程中会出现同一个人脸被多次检测,这需要进行区域的合并,这里不作探讨。

     无论哪一种搜索方法,都会为输入图片输出大量的子窗口图像,这些子窗口图像经过筛选式级联分类器会不断地被每一个节点筛选,抛弃或通过。级联分类器如下所示:
                                 cascade.jpg

       首先将所有待检测的子窗口输入到第一个分类器中,如果某个子窗口判决通过,则进入下一个分类器继续检测识别,否则该子窗口直接退出检测流程,也就是说后续分类器不需要处理该子窗口。通过这样一种级联的方式可以去除一些误识为目标的子窗口,降低误识率。例如,单个强分类器,99%的目标窗口可以通过,同时50%的非目标窗口也能通过,假设有20个强分类器级联,那么最终的正确检测率为0.9920=98%0.9920=98%,而错误识别率为0.5020≈0.0001%0.5020≈0.0001%,在不影响检测准确率的同时,大大降低了误识率。当然前提是单个强分类器的准确率非常高,这样级联多个分类器才能不影响最终的准确率或者影响很小。

  在一幅图像中,为了能够检测到不同位置的目标区域,需要以一定步长遍历整幅图像;而对于不同大小的目标,则需要改变检测窗口的尺寸,或者固定窗口而缩放图像。这样,最后检测到的子窗口必然存在相互重叠的情况,因此需要进一步对这些重叠的子窗口进行合并,也就是非极大值抑制(NMS,non-maximum suppression),同时剔除零散分布的错误检测窗口。

from:https://blog.csdn.net/Zachary_Co/article/details/78811605

from:https://blog.csdn.net/u010807846/article/details/54798935

from:https://blog.csdn.net/nk_wavelet/article/details/52601567


Haar特征原理:

1、简述:

     openCV的的Haar分类器是一个监督分类器,首先对图像进行直方图均衡化并归一化到同样大小(例如,20x20),然后标记里面是否包含要监测的物体。为了检测整副图像,可以在图像中移动搜索窗口,检测每一个位置来确定可能的目标。 为了搜索不同大小的目标物体,分类器被设计为可以进行尺寸改变,这样比改变待检图像的尺寸大小更为有效。所以,为了在图像中检测未知大小的目标物体,扫描程序通常需要用不同比例大小的搜索窗口对图片进行几次扫描。

         分类器中的“级联”是指最终的分类器是由几个简单分类器级联组成。在图像检测中,被检窗口依次通过每一级分类器,这样在前面几层的检测中大部分的候选区域就被排除了,全部通过每一级分类器检测的区域即为目标区域。该分类器在级联的每个节点中使用AdaBoost来学习一个高检测率低拒绝率的多层树分类器。它使用了以下一些新的特征

1. 使用类Haar输入特征:对矩形图像区域的和或者差进行阈值化。

2.积分图像技术加速了矩形区域的45°旋转的值的计算,用来加速类Haar输入特征的计算。

3.使用统计boosting来创建两类问题(人脸和非人脸)的分类器节点(高通过率,低拒绝率)

4.把弱分类器节点组成筛选式级联。即,第一组分类器最优,能通过包含物体的图像区域,同时允许一些不包含物体通过的图像通过;第二组分 类器次优分类器,也是有较低的拒绝率;以此类推。也就是说,对于每个boosting分类器,只要有人脸都能检测到,同时拒绝一小部分非人脸, 并将其传给下一个分类器,是为低拒绝率。以此类推,最后一个分类器将几乎所有的非人脸都拒绝掉,只剩下人脸区域。只要图像区域通过了整 个级联,则认为里面有物体。

2、Haar 特征获取

       基于Haar特征的cascade分类器(classifiers) 是Paul Viola和 Michael Jone在2001年,论文”Rapid Object Detection using a Boosted Cascade of Simple Features”中提出的一种有效的物品检测(object detect)方法。它是一种机器学习方法,通过许多正负样例中训练得到cascade方程,然后将其应用于其他图片。 
      现在让我们来看以下人脸检测是如何工作的。首先,算法需要许多正样例(包含人脸的图片)和负样例(不包含人脸的图片)来训练分类器。然后我们要从这些图片中获取特征(extract features)。如下所示为Haar特征获取的方式。和卷积核(conventional kernel)类似,每个特征由白方块下的像素和减去黑方块的像素和来得到。 

      在Haar-like特征提出之前,传统的人脸检测算法一般是基于图像像素值进行的,计算量较大且实时性较差。Papageorgiou等人最早将Harr小波用于人脸特征表示,Viola和Jones则在此基础上,提出了多种形式的Haar特征。Lienhart等人对Haar矩形特征做了进一步的扩展,加入了旋转45度的矩形特征,因此现有的Haar特征模板主要如下图所示:

                             haar.jpg 

        这些所谓的特征不就是一堆带条纹的矩形么,到底是干什么用的?

       将上面的任意一个矩形放到人脸区域上,然后,将白色区域的像素和减去黑色区域的像素和,得到的值我们暂且称之为人脸特征值,如果你把这个矩形放到一个非人脸区域,那么计算出的特征值应该和人脸特征值是不一样的,而且越不一样越好,所以这些方块的目的就是把人脸特征量化,以区分人脸和非人脸。为了增加区分度,可以对多个矩形特征计算得到一个区分度更大的特征值,那么什么样的矩形特征怎么样的组合到一块可以更好的区分出人脸和非人脸呢,这就是AdaBoost算法要做的事了。OpenCV的Haar分类器就是基于扩展后的特征库实现的。

  特征模板都是由两个或多个全等的矩形相邻组合而成,特征模板内有白色和黑色两种矩形。特征模板的特征值定义为:白色矩形像素和减去黑色矩形像素和。也就是说白色区域的权值为正值,黑色区域的权值为负值,而且权值与矩形区域的面积成反比,抵消两种矩形区域面积不等造成的影响,保证Haar特征值在灰度分布均匀的区域特征值趋近于0。Haar特征在一定程度上反应了图像灰度的局部变化,在人脸检测中,脸部的一些特征可由矩形特征简单刻画,例如,眼睛比周围区域的颜色要深,鼻梁比两侧颜色要浅等。

      接下来,要解决两个问题:1)求出每个待检测子窗口中的特征个数;2)求出每个特征的特征值。

  子窗口中的特征个数即为特征矩形的个数。训练时,将每一个特征在训练图像子窗口中进行滑动计算,获取各个位置的各类矩形特征。在子窗口中位于不同位置的同一类型矩形特征,属于不同的特征。
  Haar-like矩形特征分为多类,特征模板可用于图像中的任一位置,而且大小也可任意变化,因此Haar特征的取值受到特征模板的类别、位置以及大小这三种因素的影响,使得在一固定大小的图像窗口内,可以提取出大量的Haar特征。例如,在一个24×24的检测窗口内,矩形特征的数量可以达到16万个(参考:https://blog.csdn.net/nk_wavelet/article/details/52592844

     这样就需要解决两个重要问题,快速计算Haar矩形特征值——积分图;筛选有效的矩形特征用于分类识别——AdaBoost分类器。

      为了解决大量计算的问题引入了积分图像(intergal images)的概念。它大大简化了像素和的计算,大约只需要像素数目数量级的运算,每次运算只涉及到4个像素。这让一切都变得超级快。 
       在我们计算的所有特征中,大部分特征是无关紧要的。比如下图这个例子。 顶上一行表示两个不错的特征,第一个特征似乎是根据眼睛所在位置通常比脸颊和鼻子更黑来选择,而第二个特征选择的依据则是眼睛比鼻梁要黑。因此,相同的窗口用于脸颊或者其他部位时就没有意义了。那么我们如何从超过16万个的特征中选择最好的特征呢?我们可以使用Adaboost来实现。 

                                             这里写图片描述 

AdaBoost分类器+Cascade 分类器

      由输入图像得到积分图,通过取不同种类、大小的Haar特征模板,并在不同位置处,利用积分图提取Haar矩形特征,可快速得到大量Haar特征值,AdaBoost分类器可用于对提取的Haar特征(通常需要做归一化处理)进行训练分类,并应用于人脸检测中。AdaBoost是一种集成分类器,由若干个弱分类器(例如决策树)组合训练得到。

      在训练多个弱分类器得到强分类器的过程中,采用了两次加权的处理方法,一是对样本图片进行加权,在迭代过程中,提高错分样本的权重;二是对筛选出的弱分类器h_{t}进行加权,弱分类器准确率越高,权重越大。


       我们将每个特征都应用于所有训练集图片中,对于每个特征,找出人脸图片分类效果最好的阈值。显然,分类会有误分类,我们选择分类错误率最小的那些特征,也就是说这些特征可以最好的将人脸图片和非人脸图片区分开。(实际上没有那么简单,每个图片初始时给定相同的权重。每次分类后,提升被分类错误图片的权重。然后再根据新的权重分类,计算出新的错误率和新的权重,直到错误率或迭代次数达到要求即停止(实际上就是Adaboost的流程))。 
        最终的分类器是这些弱分类器的加权和。之所以称之为弱分类器是因为每个分类器不能单独分类图片,但是将他们聚集起来就形成了强分类器。论文表明,只需要200个特征的分类器在检测中的精确度达到了95%。最终的分类器大约有6000个特征。(将超过160000个特征减小到6000个,这是非常大的进步了) 
        假设现在你有一张图片,使用24x24的滑动窗口,将6000个特征应用于图片来检测图片是否为人脸。嗯….这是不是有点效率低下,浪费时间?确实是的,不过作者自有妙计。

       事实上,一张图片中大部分的区域都不是人脸。如果能找到一个简单的方法能够检测某个窗口是不是人脸区域,如果该窗口不是人脸区域,那么就只看一眼便直接跳过,也就不用进行后续处理了,这样就能集中精力判别那些可能是人脸的区域。为此引入了Cascade 分类器。它不是将6000个特征都用在一个窗口,而是将特征分为不同的阶段,然后一个阶段一个阶段的应用这些特征(通常情况下,前几个阶段只有很少量的特征)。如果窗口在第一个阶段就检测失败了,那么就直接舍弃它,无需考虑剩下的特征。如果检测通过,则考虑第二阶段的特征并继续处理。如果所有阶段的都通过了,那么这个窗口就是人脸区域。                  

      作者的检测器将6000+的特征分为了38个阶段,前五个阶段分别有1,10,25,25,50个特征(前文图中提到的两个特征实际上是Adaboost中得到的最好的两个特征)。根据作者所述,平均每个子窗口只需要使用6000+个特征中的10个左右

       以上就是Viola-Jones 人脸识别的工作原理,简述此技术不限于人脸检测,还可用于其他物体的检测,如汽车、飞机等的正面、侧面、后面检测。在检测时,先导入训练好的参数文件,其中haarcascade_frontalface_alt2.xml对正面脸的识别效果较好,haarcascade_profileface.xml对侧脸的检测效果较好。当然,如果要达到更高的分类精度,可以收集更多的数据进行训练。

猜你喜欢

转载自blog.csdn.net/qq_30815237/article/details/89524701