学习Haar-Like特征和AdaBoost进行人脸识别

由于课程学习的原因,最近一个月一直在了解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;
		}
	}
}


对于AdaBoost中弱分类器的设计,是整个学习过程中困扰我最长时间的,也是最后感觉收获最大的地方。对于AdaBoost的的整个算法公式和流程在以上大神博文中都有详细的解释,我这里只讨论怎么根据主要的参考论文设计弱分类器。下面图片中所描述的涉及到两个问题:

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


对于级联结构分类器没有更多的关注,只是了解了大概结构和理论知识,希望知道的网友能一起交流学习,指点一二,感激不尽!由于本人编程能力有限,对于这篇论文只是零星的实现了一些片段算法,没有构成完整的能工作的系统,有些遗憾,希望将来能回头弥补。同时,由于需要做team seminar presentation,制作了自己基于参考论文理解的PPT,需要的朋友可以下载参考。 点这里

最后,如果你对本文有意见或者建议,请及时留言,大家一起多多交流!







  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值