zoukankan      html  css  js  c++  java
  • 基于Haar特征的Adaboost级联人脸检测分类器

            基于Haar特征的Adaboost级联人脸检测分类器
    基于Haar特征的Adaboost级联人脸检测分类器,简称haar分类器。通过这个算法的名字,我们可以看到这个算法其实包含了几个关键点:Haar特征、Adaboost、级联。理解了这三个词对该算法基本就掌握了。
    1        算法要点
    Haar分类器 = Haar-like特征 + 积分图方法 + AdaBoost +级联;
    Haar分类器算法的要点如下:
    a)        使用Haar-like特征做检测。
    b)       使用积分图(IntegralImage)对Haar-like特征求值进行加速。
    c)        使用AdaBoost算法训练区分人脸和非人脸的强分类器。
    d)       使用筛选式级联把分类器级联到一起,提高准确率。
    2        历史
      在2001年,Viola和Jones两位大牛发表了经典的《Rapid Object Detectionusing a Boosted Cascade of Simple Features》和《Robust Real-Time Face Detection》,在AdaBoost算法的基础上,使用Haar-like小波特征和积分图方法进行人脸检测,他俩不是最早使用提出小波特征的,但是他们设计了针对人脸检测更有效的特征,并对AdaBoost训练出的强分类器进行级联。这可以说是人脸检测史上里程碑式的一笔了,也因此当时提出的这个算法被称为Viola-Jones检测器。又过了一段时间,RainerLienhart和Jochen
    Maydt两位大牛将这个检测器进行了扩展,最终形成了OpenCV现在的Haar分类器。
    AdaBoost是Freund和Schapire在1995年提出的算法,是对传统Boosting算法的一大提升。Boosting算法的核心思想,是将弱学习方法提升成强学习算法,也就是“三个臭皮匠顶一个诸葛亮”
    3        Haar特征
      什么是特征,特征就是分类器的输入。把它放在下面的情景中来描述,假设在人脸检测时我们需要有这么一个子窗口在待检测的图片窗口中不断的移位滑动,子窗口每到一个位置,就会计算出该区域的特征,然后用我们训练好的级联分类器对该特征进行筛选,一旦该特征通过了所有强分类器的筛选,则判定该区域为人脸。
      1 clc;
      2 clear; 
      3 close all;
      4 
      5 % Haar-like特征矩形计算
      6 
      7 board = 24                                              % 检测窗口宽度
      8 num = 24                                                % 检测窗口分划数
      9 
     10 show = 1;                                               % 1为作图
     11 time = 0.001;                                           % 作图间隔
     12 
     13 %%
     14 
     15 if mod(board,num)~=0
     16     error('检测窗口宽度必须是分划数的整数倍')
     17 else
     18     delta = board/num                                   % 滑动步进值 
     19 end
     20 
     21 % Haar特征1:左白,右黑,(s,t)=(1,2)
     22 
     23 s = 1;
     24 t = 2;
     25 R = s:s:floor(num/s)*s;                                 % Haar窗口高
     26 C = t:t:floor(num/t)*t;                                 % Haar窗口宽
     27 NUM = 0;                                                % Haar特征总数
     28 
     29 % '---- Haar特征1:左白,右黑,(s,t)=(1,2) ---'
     30 for I = 1:length(R)
     31     for J = 1:length(C)
     32        
     33         r = R(I)*delta;                                   % Haar窗口高
     34         c = C(J)*delta;                                  % Haar窗口宽
     35         nr = num-R(I)+1;                                 % 行方向移动个数
     36         nc = num-C(J)+1;                                 % 列方向移动个数
     37        
     38         Px0 = [0 r];                                     % 矩形坐标初始化
     39         Py0 = [0 c/2 c];
     40         for i = 1:nr
     41             for j = 1:nc
     42                 Px = Px0+(i-1)*delta;                    % 滑动取点
     43                 Py = Py0+(j-1)*delta;
     44                 NUM = NUM+1;
     45                
     46                 if show
     47                     plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on;
     48                     plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square;
     49                     title('Haar矩形遍历演示');xlabel('x');ylabel('y');
     50                    
     51                     plot(Px,repmat(Py',1,2),'r','LineWidth',5)
     52                     plot(repmat(Px,2,1),repmat([Py(1) Py(end)]',1,2),'r','LineWidth',5); hold off
     53                     pause(time)
     54                 end
     55                
     56             end
     57         end
     58        
     59     end
     60 end
     61 NUM
     62 %% Haar特征2:上白,下黑,(s,t)=(2,1)
     63 s = 2;
     64 t = 1;
     65 R = s:s:floor(num/s)*s;                                 % Haar窗口高
     66 C = t:t:floor(num/t)*t;                                 % Haar窗口宽
     67 NUM = 0;                                                % Haar特征总数
     68 '---- Haar特征2:上白,下黑,(s,t)=(2,1) ---'
     69 for I = 1:length(R)
     70     for J = 1:length(C)
     71        
     72         r = R(I)*delta;                                  % Haar窗口高
     73         c = C(J)*delta;                                  % Haar窗口宽
     74         nr = num-R(I)+1;                                 % 行方向移动个数
     75         nc = num-C(J)+1;                                 % 列方向移动个数
     76        
     77         Px0 = [0 r/2 r];                                 % 矩形坐标初始化
     78         Py0 = [0 c];
     79         for i = 1:nr
     80             for j = 1:nc
     81                 Px = Px0+(i-1)*delta;                    % 滑动取点
     82                 Py = Py0+(j-1)*delta;
     83                 NUM = NUM+1;
     84                 if show
     85                     plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on;
     86                     plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square;
     87                     title('Haar矩形遍历演示');xlabel('x');ylabel('y');
     88                    
     89                     plot(repmat(Px,2,1),repmat(Py',1,length(Px)),'r','LineWidth',3);
     90                     plot(repmat([Px(1) Px(end)]',1,2),repmat(Py,2,1),'r','LineWidth',3); hold off
     91                     pause(time)
     92                 end
     93                
     94             end
     95         end
     96        
     97     end
     98 end
     99 NUM
    100 %% Haar特征3:左右白,中间黑,(s,t)=(1,3)
    101 s = 1;
    102 t = 3;
    103 R = s:s:floor(num/s)*s;                                 % Haar窗口高
    104 C = t:t:floor(num/t)*t;                                 % Haar窗口宽
    105 NUM = 0;                                                % Haar特征总数
    106 '---- Haar特征3:左右白,中间黑,(s,t)=(1,3) ---'
    107 for I = 1:length(R)
    108     for J = 1:length(C)
    109        
    110         r = R(I)*delta;                                  % Haar窗口高
    111         c = C(J)*delta;                                  % Haar窗口宽
    112         nr = num-R(I)+1;                                 % 行方向移动个数
    113         nc = num-C(J)+1;                                 % 列方向移动个数
    114        
    115         Px0 = [0 r];                                     % 矩形坐标初始化
    116         Py0 = [0 c/3 c*2/3 c];
    117         for i = 1:nr
    118             for j = 1:nc
    119                 Px = Px0+(i-1)*delta;                    % 滑动取点
    120                 Py = Py0+(j-1)*delta;
    121                 NUM = NUM+1;
    122                
    123                 if show
    124                     plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on;
    125                     plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square;
    126                     title('Haar矩形遍历演示');xlabel('x');ylabel('y');
    127                    
    128                     plot(Px,repmat(Py',1,2),'r','LineWidth',5)
    129                     plot(repmat(Px,2,1),repmat([Py(1) Py(end)]',1,2),'r','LineWidth',5); hold off
    130                     pause(time)
    131                 end
    132             end
    133         end
    134        
    135     end
    136 end
    137 NUM
    138 %% Haar特征4:左右白,中间黑(2倍宽度),(s,t)=(1,4)
    139 s = 1;
    140 t = 4;
    141 R = s:s:floor(num/s)*s;                                 % Haar窗口高
    142 C = t:t:floor(num/t)*t;                                 % Haar窗口宽
    143 NUM = 0;                                                % Haar特征总数
    144 '---- Haar特征4:左右白,中间黑(2倍宽度),(s,t)=(1,4) ---'
    145 for I = 1:length(R)
    146     for J = 1:length(C)
    147        
    148         r = R(I)*delta;                                  % Haar窗口高
    149         c = C(J)*delta;                                  % Haar窗口宽
    150         nr = num-R(I)+1;                                 % 行方向移动个数
    151         nc = num-C(J)+1;                                 % 列方向移动个数
    152        
    153         Px0 = [0 r];                                     % 矩形坐标初始化
    154         Py0 = [0 c/4 c*3/4 c];
    155         for i = 1:nr
    156             for j = 1:nc
    157                 Px = Px0+(i-1)*delta;                    % 滑动取点
    158                 Py = Py0+(j-1)*delta;
    159                 NUM = NUM+1;
    160        
    161                 if show
    162                     plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on;
    163                     plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square;
    164                     title('Haar矩形遍历演示');xlabel('x');ylabel('y');
    165                    
    166                     plot(Px,repmat(Py',1,2),'r','LineWidth',5)
    167                     plot(repmat(Px,2,1),repmat([Py(1) Py(end)]',1,2),'r','LineWidth',5); hold off
    168                     pause(time)
    169                 end
    170                
    171             end
    172         end
    173        
    174     end
    175 end
    176 NUM
    177 %% Haar特征5:上下白,中间黑,(s,t)=(3,1)
    178 s = 3;
    179 t = 1;
    180 R = s:s:floor(num/s)*s;                                 % Haar窗口高
    181 C = t:t:floor(num/t)*t;                                 % Haar窗口宽
    182 NUM = 0;                                                % Haar特征总数
    183 '---- Haar特征5:上下白,中间黑,(s,t)=(3,1) ---'
    184 for I = 1:length(R)
    185     for J = 1:length(C)
    186        
    187         r = R(I)*delta;                                  % Haar窗口高
    188         c = C(J)*delta;                                  % Haar窗口宽
    189         nr = num-R(I)+1;                                 % 行方向移动个数
    190         nc = num-C(J)+1;                                 % 列方向移动个数
    191        
    192         Px0 = [0 r/3 r*2/3 r];                           % 矩形坐标初始化
    193         Py0 = [0 c];
    194         for i = 1:nr
    195             for j = 1:nc
    196                 Px = Px0+(i-1)*delta;                    % 滑动取点
    197                 Py = Py0+(j-1)*delta;
    198                 NUM = NUM+1;
    199                
    200                 if show
    201                     plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on;
    202                     plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square;
    203                     title('Haar矩形遍历演示');xlabel('x');ylabel('y');
    204                    
    205                     plot(repmat(Px,2,1),repmat(Py',1,length(Px)),'r','LineWidth',3);
    206                     plot(repmat([Px(1) Px(end)]',1,2),repmat(Py,2,1),'r','LineWidth',3); hold off
    207                     pause(time)
    208                 end
    209                
    210             end
    211         end
    212        
    213     end
    214 end
    215 NUM
    216 %% Haar特征6:上下白,中间黑(2倍宽度),(s,t)=(4,1)
    217 s = 4;
    218 t = 1;
    219 R = s:s:floor(num/s)*s;                                 % Haar窗口高
    220 C = t:t:floor(num/t)*t;                                 % Haar窗口宽
    221 NUM = 0;                                                % Haar特征总数
    222 '---- Haar特征6:上下白,中间黑(2倍宽度),(s,t)=(4,1) ---'
    223 for I = 1:length(R)
    224     for J = 1:length(C)
    225        
    226         r = R(I)*delta;                                  % Haar窗口高
    227         c = C(J)*delta;                                 % Haar窗口宽
    228         nr = num-R(I)+1;                                 % 行方向移动个数
    229         nc = num-C(J)+1;                                 % 列方向移动个数
    230        
    231         Px0 = [0 r/4 r*3/4 r];                           % 矩形坐标初始化
    232         Py0 = [0 c];
    233         for i = 1:nr
    234             for j = 1:nc
    235                 Px = Px0+(i-1)*delta;                    % 滑动取点
    236                 Py = Py0+(j-1)*delta;
    237                 NUM = NUM+1;
    238                 if show
    239                     plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on;
    240                     plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square;
    241                     title('Haar矩形遍历演示');xlabel('x');ylabel('y');
    242                    
    243                     plot(repmat(Px,2,1),repmat(Py',1,length(Px)),'r','LineWidth',3);
    244                     plot(repmat([Px(1) Px(end)]',1,2),repmat(Py,2,1),'r','LineWidth',3); hold off
    245                     pause(time)
    246                 end
    247                
    248             end
    249         end
    250        
    251     end
    252 end
    253 NUM
    254 %% Haar特征7:左上右下白,其它黑,(s,s)=(2,2)
    255 
    256 s = 2;
    257 t = 2;
    258 R = s:s:floor(num/s)*s;                                 % Haar窗口高
    259 C = t:t:floor(num/t)*t;                                 % Haar窗口宽
    260 NUM = 0;                                                % Haar特征总数
    261 '---- Haar特征7:左上右下白,其它黑,(s,s)=(2,2) ---'
    262 for I = 1:length(R)
    263     for J = 1:length(C)
    264        
    265         r = R(I)*delta;                                  % Haar窗口高
    266         c = C(J)*delta;                                  % Haar窗口高
    267         nr = num-R(I)+1;                                 % 行方向移动个数
    268         nc = num-C(J)+1;                                 % 行方向移动个数
    269        
    270         Px0 = [0 r/2 r];                           % 矩形坐标初始化
    271         Py0 = [0 c/2 c];                           % 矩形坐标初始化
    272         for i = 1:nr
    273             for j = 1:nc
    274                 Px = Px0+(i-1)*delta;                    % 滑动取点
    275                 Py = Py0+(j-1)*delta;
    276                 NUM = NUM+1;
    277                
    278                 if show
    279                     plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on;
    280                     plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square;
    281                     title('Haar矩形遍历演示');xlabel('x');ylabel('y');
    282                    
    283                     plot(repmat(Px,3,1),repmat(Py',1,length(Px)),'r','LineWidth',3);
    284                     plot(repmat([Px(1) Px(end)]',1,3),repmat(Py,2,1),'r','LineWidth',3); hold off
    285                     pause(time)
    286                 end
    287                
    288             end
    289         end
    290        
    291     end
    292 end
    293 NUM
    294 %% Haar特征8:四周白,中间黑,(s,s)=(3,3)
    295 s = 3;
    296 t = 3;
    297 R = s:s:floor(num/s)*s;                                 % Haar窗口高
    298 C = t:t:floor(num/t)*t;                                 % Haar窗口宽
    299 NUM = 0;                                                % Haar特征总数
    300 '---- Haar特征8:四周白,中间黑,(s,s)=(3,3) ---'
    301 for I = 1:length(R)
    302     for J = 1:length(C)
    303        
    304         r = R(I)*delta;                                  % Haar窗口高
    305         c = C(J)*delta;                                  % Haar窗口高
    306         nr = num-R(I)+1;                                 % 行方向移动个数
    307         nc = num-C(J)+1;                                 % 行方向移动个数
    308        
    309         Px0 = [0 r/3 r*2/3 r];                           % 矩形坐标初始化
    310         Py0 = [0 c/3 c*2/3 c];                           % 矩形坐标初始化
    311         for i = 1:nr
    312             for j = 1:nc
    313                 Px = Px0+(i-1)*delta;                    % 滑动取点
    314                 Py = Py0+(j-1)*delta;
    315                 NUM = NUM+1;
    316                
    317                 if show
    318                     plot([0 board],repmat((0:delta:board)',1,2),'k'); hold on;
    319                     plot(repmat((0:delta:board)',1,2),[0 board],'k'); axis tight; axis square;
    320                     title('Haar矩形遍历演示');xlabel('x');ylabel('y');
    321                    
    322                     plot(repmat(Px,4,1),repmat(Py',1,length(Px)),'r','LineWidth',3);
    323                     plot(repmat([Px(1) Px(end)]',1,4),repmat(Py,2,1),'r','LineWidth',3); hold off
    324                     pause(time)
    325                 end
    326                
    327             end
    328         end
    329        
    330     end
    331 end
    332 NUM
    View Code

    运行效果部分动态图如下


      那么这个特征如何表示呢?好了,这就是大牛们干的好事了。后人称这他们搞出来的这些东西叫Haar-Like特征。
    Viola大牛在[1]中提出的haar特征如下:

    Rainer大牛改进了这些特征,提出了更多的haar特征。如下图所示:

      这些所谓的特征不就是一堆堆带条纹的矩形么,到底是干什么用的?我这样给出解释,将上面的任意一个矩形放到人脸区域上,然后,将白色区域的像素和减去黑色区域的像素和,得到的值我们暂且称之为人脸特征值,如果你把这个矩形放到一个非人脸区域,那么计算出的特征值应该和人脸特征值是不一样的,而且越不一样越好,所以这些方块的目的就是把人脸特征量化,以区分人脸和非人脸。
    haar-like特征的特点
      Haar特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。
        通过改变特征模板的大小和位置,可在图像子窗口中穷举出大量的特征。上图的特征模板称为“特征原型”;特征原型在图像子窗口中扩展(平移伸缩)得到的特征称为“矩形特征”;矩形特征的值称为“特征值”。
    4       积分图

       积分图就是只遍历一次图像就可以求出图像中所有区域像素和的快速算法,大大的提高了图像特征值计算的效率。

           积分图主要的思想是将图像从起点开始到各个点所形成的矩形区域像素之和作为一个数组的元素保存在内存中,当要计算某个区域的像素和时可以直接索引数组的元素,不用重新计算这个区域的像素和,从而加快了计算(这有个相应的称呼,叫做动态规划算法)。积分图能够在多种尺度下,使用相同的时间(常数时间)来计算不同的特征,因此大大提高了检测速度。

           我们来看看它是怎么做到的。

           积分图是一种能够描述全局信息的矩阵表示方法。积分图的构造方式是位置(i,j)处的值ii(i,j)是原图像(i,j)左上角方向所有像素的和:

      

            

    积分图构建算法:

    1)用s(i,j)表示行方向的累加和,初始化s(i,-1)=0;

    2)用ii(i,j)表示一个积分图像,初始化ii(-1,i)=0;

    3)逐行扫描图像,递归计算每个像素(i,j)行方向的累加和s(i,j)和积分图像ii(i,j)的值

    s(i,j)=s(i,j-1)+f(i,j)

    ii(i,j)=ii(i-1,j)+s(i,j)

    4)扫描图像一遍,当到达图像右下角像素时,积分图像ii就构造好了。

    积分图构造好之后,图像中任何矩阵区域的像素累加和都可以通过简单运算得到如图所示。

              

    设D的四个顶点分别为α、β、γ、δ,则D的像素和可以表示为

    Dsum = ii( α )+ii( β)-(ii( γ)+ii( δ ));

            而Haar-like特征值无非就是两个矩阵像素和的差,同样可以在常数时间内完成。所以矩形特征的特征值计算,只与此特征矩形的端点的积分图有关,所以不管此特征矩形的尺度变换如何,特征值的计算所消耗的时间都是常量。这样只要遍历图像一次,就可以求得所有子窗口的特征值。



    5       Adaboost算法
    本节旨在介绍AdaBoost在Haar分类器中的应用,所以只是描述了它在Haar分类器中的特性,而实际上AdaBoost是一种具有一般性的分类器提升算法,它使用的分类器并不局限某一特定算法。
    [1]中给出的Adaboost算法流程如下图。
     
    由adaboost在haar特征上构建分类器的流程可知,adaboost算法就是构建多个简单的分类器,每个简单的分类器都建立在之前分类器的基础上(对之前分类器分错了的样例提高其权重),然后将这些分类器加权,得到一个强大的分类器。
    Adaboost的每一步训练出的分类器,如下图所示。其中,f表示特征的值,theta表示阈值,p则表示不等式的方向。这样的一个分类器就是基于一个特征的弱分类器。

     
    更进一步,adaboost的一般算法框架如下。可以看到,Discrete Adaboost和GentleAdaboost在分类器的计算上和权重的更新上是有差别的。还有一种是RealAdaboost,即分类器输出的是一个概率而不只是+1与-1。[3]中就比较了这三种Adaboost的变种的效果。
     

     有关adaboost算法的实现可以参考这篇博客:https://blog.csdn.net/u012679707/article/details/80369772


    6        级联
    什么是级联分类器?级联分类器就是如下图所示的一种退化了的决策树。为什么说是退化了的决策树呢?是因为一般决策树中,判断后的两个分支都会有新的分支出现,而级联分类器中,图像被拒绝后就直接被抛弃,不会再有判断了。

    级联强分类器的策略是,将若干个强分类器由简单到复杂排列,希望经过训练使每个强分类器都有较高检测率,而误识率可以放低,比如几乎99%的人脸可以通过,但50%的非人脸也可以通过,这样如果有20个强分类器级联,那么他们的总识别率为0.99^20约等于98%,错误接受率也仅为0.5^20约等于0.0001%。这样的效果就可以满足现实的需要了。文献[1]中给出了一种由简单到复杂设计级联分类器的方法,那就是添加特征法,对于第一个分类器,只用少数几个特征,之后的每个分类器都在上一个的基础上添加特征,直到满足该级的要求。
    训练级联分类器的目的就是为了检测的时候,更加准确,这涉及到Haar分类器的另一个体系,检测体系,检测体系是以现实中的一幅大图片作为输入,然后对图片中进行多区域,多尺度的检测,所谓多区域,是要对图片划分多块,对每个块进行检测,由于训练的时候用的照片一般都是20*20左右的小图片,所以对于大的人脸,还需要进行多尺度的检测,多尺度检测机制一般有两种策略,一种是不改变搜索窗口的大小,而不断缩放图片,这种方法显然需要对每个缩放后的图片进行区域特征值的运算,效率不高,而另一种方法,是不断初始化搜索窗口size为训练时的图片大小,不断扩大搜索窗口,进行搜索,解决了第一种方法的弱势。

    7        总结
    基于Haar特征的Adaboost级联分类器,在人脸的识别效果上并没有比其他算法高,其亮点在于检测速度。而速度的提升,有如下几方面的因素。第一:使用的特征简单,haar特征只需计算像素的和就可以了。第二:即便是如此简单的特征,还添加了积分图进行加速。第三,级联分类器的设定,使得大量的没有人脸的子窗口被抛弃
     
  • 相关阅读:
    BZOJ_3170_[Tjoi2013]松鼠聚会_切比雪夫距离
    BZOJ_3343_教主的魔法_分块+二分查找
    吴裕雄--天生自然HADOOP操作实验学习笔记:使用hive操作hbase
    吴裕雄--天生自然云计算安全策略:云计算安全
    吴裕雄--天生自然HADOOP操作实验学习笔记:hbase的shell应用v2.0
    吴裕雄--天生自然HADOOP操作实验学习笔记:hive DDL
    吴裕雄--天生自然HADOOP操作实验学习笔记:mapreduce和yarn命令
    吴裕雄--天生自然HADOOP操作实验学习笔记:hdfs简单的shell命令
    吴裕雄--天生自然HADOOP操作实验学习笔记:mapreduce代码编程
    吴裕雄--天生自然HADOOP操作实验学习笔记:分布式及RPC通信简介
  • 原文地址:https://www.cnblogs.com/henuliulei/p/10719208.html
Copyright © 2011-2022 走看看