由于课程学习的原因,最近一个月一直在了解AdaBoost的原理及实现方法。这算是我学习的第一个比较复杂的算法,最后也没有完全实现,只是实现了一个类似与教学用的demo。但这个过程也得益于网络上各路大神们经典博文的参考,才能够更深入一点理解AdaBoost。下面列出相关参考论文以及博文链接。其中也会添加一些自己在学习中对该算法细节的一些思考,如有错误尽请拍砖指正!主要参考论文:
《Rapid Object Detection using a Boosted Cascade of Simple Features》Paul Viola & Michael Jones
《Robust Real-Time Face Detection》Paul Viola & Michael Jones
在这两位大牛写的论文中,使用了Haar-Like Features 通过积分图的方法进行了人脸特征的计算;通过Haar-Like Features的特征值,通过设计、构建、和选择弱分类器,找出其中产生最小误差的特征(即弱分类器),在每一轮AdaBoost的权值更新中进行样本分布,从而实现了增加误分类样本的权值,减少正确分类的样本的权值。这里弱分类器的设计使用了树桩(stump)的方法,类似于decision tree, 但是每一层只有一个节点,即底层节点,故称为树桩。论文的最后一部分,构建了级联算法结构(Cascade Structure)。大大增加了算法运行的速度,实现实时检测。同时分析了增加级联结构所需要折衷的方法。因为级联结构中:其一,高的阈值,得到低的误检率和低的检测率;低的阈值导致高的误检率和高的检测率,据说这是由于级联分类器中阈值的设置引起的。其二,如果不断增加特征的数量,就会导致计算量的增加,实现实时效果困难;如果减少特征数量,就会导致检测率下降,这也需要折衷。总结为三大板块:Haar-Like Features + 积分图、AdaBoost算法及弱分类器的设计、级联分类器。
Haar-Like特征参考博文:点这里 点这里 点这里
下面这篇论文中把基本的Haar-Like特征进行了扩展,提出了旋转和中心Haar-Like特征,以及检测窗中特征数量的计算公式:
《An Extended Set of Haar-Like Features for Rapid Object Detection》R.Leinhart
积分图的计算: 点这里
其他论文: 《Integral Image for Block Matching》 Gabriele Facciolo,Nicolas Limare, Enric Meinhardt
对整篇论文,Haar-like特征,积分图,AdaBoost算法,级联分类器总结的比较好的博文,请看这位大神: 点这里 这篇博文中也有Haar-like特征的详细计算过程
专门讲AdaBoost算法,一直到误差界的理解,请看这位大神:点这里 通过公式推导,理解算法也很重要
这篇博文中介绍了很多关于Boosting、AdaBoost、Haar分类器等很多背景内容,如果需要了解的,可以点这里
下面我将结合自己的学习过程谈谈积分图和AdaBoost:
很多博文中提出了很多关于积分图的计算方法,称为快速积分图计算的方法,有时间可以去学习一下,因为这段时间的关系,确实没来得及学习。下面贴出我根据论文写的可能没考虑速度的积分图计算方法,适合于初学者。由于在积分图中得到图像信息的计算时间是常数,速度很快,应该在以后的很多算法和领域都会用到这个概念吧!
void integralImage(long **srcImg, long **integralImg, int height, int width) { integralImg[0][0] = srcImg[0][0]; char j,i; long s; //scalar accumulator for(j = 1; j < height; j++) { integralImg[j][0] = integralImg[j-1][0] + srcImg[j][0]; //the integral for only first column } for(i = 1; i < width; i++) { s = srcImg[0][i]; integralImg[0][i] = integralImg[0][i-1] + s; //the integral for only first row for(j = 1; j < height; j++) { s = s + srcImg[j][i]; integralImg[j][i] = integralImg[j][i-1] + s; } } }
1、怎么计算最小(或者满足要求)的误差,确定那个Haar-Like特征的阈值?
2、怎么根据选择的阈值,分类效果等确定最好的那个弱分类器(即选择哪个特征)?
首先假设有一个训练样本集{x1,x2,x3,...xm},为了更方便理解,可以假设这些样本都是24 x 24的样本图像,当然这些都是被标定(label)过的。每幅图像内有特征{h1,h2,h3,...,hn},特征数量很多,n也许很大,根据前面的参考博文及参考论文中可以知道,这里假设的24 x 24图片中有160,000个特征。因为每个样本大小相同,在同一个样本中,同一类特征对应不同的位置,被当做是不同特征。既然大小相同,那么可以认为在每个样本之间,相对应的位置会出现相同的特征,即使特征数量一样,但是特征值不一样。对上图的整个过程,我的理解可以用下面一个类似矩阵的来表示:
这一堆数据表示:用每个特征h去处理每一幅图像(即训练样本),然后得到特征值,所以每一列代表同一个特征处理所有样本的特征值。上面的数据有m行,n列。然后根据误差e定义的公式,遍历每一列数据,得到每一列的一系列误差值,在这中间寻找最小的误差值作为这一列的最优误差,同时可以通过这个最优误差值确定这一列的最优阈值。这样我们就得到了n个代表每一列的最优误差。再次,在这n个每一列的最优误差集中,寻找最小误差。这样我们就能选择产生这个最小误差的特征,即诞生了第一个弱分类器。对于这个理解,同时还参考了《基于AdaBoost的人脸检测方法及眼睛定位算法研究》 龙伶敏。
下面贴出Matlab的弱分类器设计代码,基于某位网友的idea,自己做了一些修改,感谢那位网友。
function [thresh,parity,err,finalTarget] = weakClassifier(srcData,weight,target,dataNum) % % srcData -- feature values % weight -- the weight of weak classifier % target -- the original labele array of training samples % dataNum -- the number of samples % posWeight = 0; negWeight = 0; for i = 1: dataNum if target(i) == 1 posWeight = weight(i) + posWeight; % the total sum of positive example weights T+ elseif target(i) == 0 negWeight = weight(i) + negWeight; % the total sum of negative example weights T- else disp('the weakClassifier is wrong!'); end end [sortData,index] = sort(srcData); lposWeight = 0; % sum of positive weights below the current example S+ lnegWeight = 0; % sum of negative weights below the current example S- bestErr = 0.5; bestParity = 0; bestThreshold = -1; %the process of creating weak classifiers for i = 2 : dataNum if target(index(i - 1)) == 1 lposWeight = weight(index(i - 1)) + lposWeight; else lnegWeight = weight(index(i - 1)) + lnegWeight; end if sortData(i) ~= sortData(i - 1) if (lposWeight + negWeight - lnegWeight) < bestErr bestErr = lposWeight + negWeight - lnegWeight; bestParity = -1; bestThreshold = (sortData(i) + sortData(i - 1))/2; elseif (lnegWeight + posWeight - lposWeight) < bestErr bestErr = lnegWeight + posWeight - lposWeight; bestParity = 1; bestThreshold = (sortData(i) + sortData(i - 1))/2; end end end finalTarget = zeros(1,dataNum); % weak classifier with lowest error thresh = bestThreshold; parity = bestParity; err = bestErr; for i = 1 : dataNum if parity * srcData(i) < parity * thresh; finalTarget(i) = 1; else finalTarget(i) = 0; end end
最后,如果你对本文有意见或者建议,请及时留言,大家一起多多交流!