aihot  2017-05-12 14:50:14  OpenCV |   查看评论   

2.用于快速Haar特征运算的Integral Image的提出:极大地提高了训练速度和检测速度
3.用于物体检测的AdaBoost方法的提出:Haar特征作为弱分类器判据与Adaboost结合到了一起
4.Cascade级联方式的提出:极大地提高了AdaBoost的检测速度
[实在是一篇很NB的文章,每一个贡献都掷地有声]

2002年, Rainer Lienhart and Jochen Maydt 在 IEEE ICIP 上发表文章An Extended Set of Haar-like Features for Rapid Object Detection.
1. 提出了扩展的Haar特征,并证明了新的Haar特征集提高了检测的能力
2. 提出了一种针对已训练完成的AdaBoost的修整

2002年, Rainer Lienhart & Alexander Kuranov & Vadim Pisarevsky 在MRL Technical Report上发表Empirical Analysis of Detection Cascades of Boosted Classifiers for Rapid Object Detection.
1. 提出了训练时进行样本丰富化
2. 指出:logitBoost could not be used due to convergence problem on later stages in the cascade training.
3. 通过试验得出结论,在人脸检测上Gentle AdaBoost的效果要好于 Discrete 和 Real

2004年, Bo WU & Haizhou AI & Chang HUANG & Shihong LAO在Computer Society上发表文章Fast Rotation Invariant Multi-View Face Detection Based on Real AdaBoost.
1. 提出了使用Real Boost检测旋转人脸

*****************还有一篇巨大量负样本的速度提高方法找不到了……

第三部分,OpenCV中AdaBoost训练程序略解

这里只介绍一个大概的情况,具体的都写在的注释里了.

1.结构:
程序的总体结构是一棵多叉树,每个节点多少个叉由初始设定的maxtreesplits决定

 

树节点结构:
typedef struct CvTreeCascadeNode
{
CvStageHaarClassifier* stage; // 指向该节点stage强分类器的指针

struct CvTreeCascadeNode* next; // 指向同层下一个节点的指针
struct CvTreeCascadeNode* child; // 指向子节点的指针
struct CvTreeCascadeNode* parent; // 指向父节点的指针

struct CvTreeCascadeNode* next_same_level;//最后一层叶节点之间的连接
struct CvTreeCascadeNode* child_eval; //用于连接最终分类的叶节点和根节点
int idx; //表示该节点是第几个节点
int leaf; //从来没有用到过的参数
} CvTreeCascadeNode;

这里需要说明的是child_eval这个指针,虽说人脸检测是一个单分类问题,程序中的maxtreesplits的设置值为0,没有分叉,但是树本身是解决多分类问题的,它有多个叶节点,也就有多个最终的分类结果。但是我们使用的时候,虽然是一个多分类的树,也可能我们只需要判断是或者不是某一类。于是我们就用root_eval和child_eval把这个分类上的节点索引出来,更方便地使用树结构。当然,这一点在本程序中是没有体现的。

分类器结构:
每个树节点中都包含了一个CvStageHaarClassifier强分类器,而每个CvStageHaarClassifier包含了多个CvIntHaarClassifier弱分类器。当CvIntHaarClassifier被使用的时候,被转化为CvCARTHaarClassifier,也就是分类树与衰减数分类器作为一个弱分类器。

typedef struct CvCARTHaarClassifier
{
CV_INT_HAAR_CLASSIFIER_FIELDS()

int count; /* 在决策树中的节点数 number of nodes in the decision tree */
int* compidx; //特征序号
CvTHaarFeature* feature; //选出的特征。数组
CvFastHaarFeature* fastfeature;

float* threshold; /* array of decision thresholds */
int* left; /* array of left-branch indices */
int* right; /* array of right-branch indices */
float* val; /* array of output values */
} CvCARTHaarClassifier;

CvCARTHaarClassifier结构中包含了弱分类器的左值右值阈值等数组,在我们的程序中CART只选用了一个特征进行分类,即退化成了stump。这里的数组里面就只存有一个元了

那么这里为什么要使用一个如此复杂的结构呢。大体来说有两个好处:
1、 方便弱分类器之间的切换,当我们不选用CART而是其他的弱分类器结构的时候,就可以调用CvIntHaarClassifier时转换成其他的指针
2、 这样方便了Haar训练的过程和Boost过程的衔接。

2.方法:
在这个程序中,函数指针是一种很常用的手法。函数指针的转换使读程序的人更难把握程序的脉络,在这里举一个最极端的例子,来说明程序中这种手法的应用。

我们在cvBoost.cpp文件中的cvCreateMTStumpClassifier函数(这是一个生成多阈值(Multi-threshold)stump分类器的函数)下看到了一个这样的调用:
findStumpThreshold_16s[stumperror](……….)
这里对应的stumperror值是2

在cvboost.cpp中我们找到了一个这样的数组
CvFindThresholdFunc findStumpThreshold_16s[4] = {
icvFindStumpThreshold_misc_16s,
icvFindStumpThreshold_gini_16s,
icvFindStumpThreshold_entropy_16s,
icvFindStumpThreshold_sq_16s
};
这个数组的类型是一个类型定义过的函数指针typedef int (*CvFindThresholdFunc)(…..)

因此这个数组中的四项就是四个指针,我们在cvCreateMTStumpClassifier中调用的也就是其中的第三项icvFindStumpThreshold_entropy_16s。

 

除特别注明外,本站所有文章均为 赢咖4注册 原创,转载请注明出处来自adaboost算法

留言与评论(共有 0 条评论)
   
验证码:
[lianlun]1[/lianlun]