AdaBoost算法程序介绍说明

关于haartraining的一些解析
Ref:http://wiki.opencv.org.cn/forum/viewtopic.php?f=10&t=11129&start=0

cvCreateTreeCascadeClass ifier
/CvTreeCascadeNode包含CvStageHaarClassifier* stage;也就是说找最后一个stage作为最深的叶leaf;
CV_CALL( leaves = icvFindDeepestLeaves( tcc ) );

CV_CALL( icvPrintTreeCascade( tcc->root ) );
//根据模式和对称性以及winsize获得haar特征,每个特征由最多三个矩形矩形加减形成,
//这里包含了所有的允许特征,允许特征是可能特征的一部分,过滤掉的是面积比较小的特征
haar_features = icvCreateIntHaarFeatures ( winsize, mode, symmetric );

printf( "Number of features used : %d\n", haar_features->count );
//分配用于训练的缓冲区,包括正负样本的矩形积分图和倾斜积分图

// CvMat normfactor;
// CvMat cls;
// CvMat weights;
training_data = icvCreateHaarTrainingDat a( winsize, npos + nneg );

sprintf( stage_name, "%s/", dirname );
suffix = stage_name + strlen( stage_name );
//获得背景信息,包括读取背景信息里背景文件的文件名信息并索引该文件,



consumed = 0;
//读取正样本,并计算通过所有的前面的stage的正采样数量,这样可以计算出检测率
//调用函数情况
//icvGetHaarTrainingDataFr omVec内部调用icvGetHaarTrainingData
//icvGetHaarTrainingData,从规定的回调函数里icvGetHaarTraininDataFro mVecCallback获得数据,
//并通过前面训练出的分类器过滤掉少量正采样,然后计算积分图,
//积分图存放在training_data结构中
poscount = icvGetHaarTrainingDataFr omVec( training_data, 0, npos,
(CvIntHaarClassifier*) tcc, vecfilename, &consumed );


proctime = -TIME( 0 );
//读负采样,并返回虚警率
//从文件中将负采样读出,并用前面的训练出的stage进行过滤获得若干被错误划分为正采样的负采样,如果得到的数量达不到nneg
//则会重复提取这些负样本,以获得nneg个负采样,所以如果当被错误划分为正采样的负采样在当前的stage后为0,则会出现死循环
//解决方法可以通过reader的round值判断。
//这种情况应该是训练收敛,因为虚警率为0,符合条件if( leaf_fa_rate <= required_leaf_fa_rate ),可以考虑退出训练
nneg = (int) (neg_ratio * poscount);
//icvGetHaarTrainingDataFr omBG内部调用
//icvGetBackgroundImage获得数据并计算积分图,将其放在training_data结构分配的内存,位置是在poscount开始nneg个数量
//training_data分配了npos + nneg个积分图内存以及权值
negcount = icvGetHaarTrainingDataFr omBG( training_data, poscount, nneg,
(CvIntHaarClassifier*) tcc, &false_alarm );
printf( "NEG: %d %g\n", negcount, false_alarm );

icvSetNumSamples( training_data, poscount + negcount );
posweight = (equalweights) ? 1.0F / (poscount + negcount) : (0.5F/poscount);
negweight = (equalweights) ? 1.0F / (poscount + negcount) : (0.5F/negcount);
//这里将正样本设置为1,负样本设置为0,在后面将用于分辨样本类型,统计检测率和虚警率
//这里也设置加权值
icvSetWeightsAndClasses( training_data,
poscount, posweight, 1.0F, negcount, negweight, 0.0F );

//预先计算每个样本(包括正负样本的前面numprecalculated特征)
//内部调用cvGetSortedIndices将所有样本的每一个特征按其特征值升序排序,idx和特征值分别放在training_data
//的 *data->valcache和*data->idxcache中;
icvPrecalculate( training_data, haar_features, numprecalculated );

/训练由多个弱分类器级连的强分类器
single_cluster->stage =
(CvStageHaarClassifier*) icvCreateCARTStageClassi fier

//cluster_idx的容量足够吗?CV_CALL( ptr = cvCreateMat( num, total, CV_32FC1 ) );ptr即val,这里的total是特征数,num为poscount
//而cluster_idx仅仅是npos+nneg之和
//CV_CALL( cluster_idx = cvCreateMat( 1, npos + nneg, CV_32SC1 ) );
//难道是KMean2的问题?vals是poscount*featurecount,
//是否综合正样本的stage特征作为一个向量,以一个向量为一个样本,vals有poscount个向量作为输入将分类后的结果放到cluster_idx
//如果这样理解则不会出现越界现象cluster_idx的容量也是够的
CV_CALL( cvKMeans2( vals, k, cluster_idx, CV_TERM_CRITERIA() ) );
//统计每个类别的数量
for( cluster = 0; cluster < k; cluster++ )
num[cluster] = 0;
//minpos大于任意一个分类,则退出分类
for( cluster = 0; cluster < k; cluster++ )

//这里得到符合要求的正样本分类,
cur_num = 0;
cur_node = last_node = NULL;
//best_num保留的是当前强分类器所有弱分类器特征值之和
for( cluster = 0; (cluster < k) && (cur_num < best_num); cluster++ )
{
CvTreeCascadeNode* new_node;

int num_splits;
int last_pos;
int total_pos;

printf( "Cluster: %d\n", cluster );
last_pos = negcount;
//将分类好的正样本根据cluster与负样本组合,则训练出k个node,
//与前面不一样的是正样本放后面负样本放前面
//重新计算加权
icvSetWeightsAndClasses( training_data,
poscount, posweight, 1.0F, negcount, negweight, 0.0F );

//注意这里的idx和上面的不同,不再是NULL了
new_node->stage = (CvStageHaarClassifier*)


static
CvIntHaarClassifier* icvCreateCARTStageClassi fier( CvHaarTrainingData* data,
CvMat* sampleIdx,
CvIntHaarFeatures* haarFeatures,
float minhitrate,
float maxfalsealarm,
int symmetric,
float weightfraction,
int numsplits,
CvBoostType boosttype,
CvStumpError stumperror,
int maxsplits )
int num_splits;
//N,是弱分类器的序号
//SMP由weightfraction决定,表示通过剔除小权值的样本后与总体样本数的%比值,
//weightfraction会改变参与下一个弱分类器的样本数量,即大权值样本
//考虑AdaBoost算法,权值更新的时候一般正确分类的权值会乘一个因子,应该对应权值会变小,这样是否会减少参与训练的正样本数?
//由于函数cvTrimWeights内部与门限相同的权值会被保留,减少的数目有限,(考虑一种极端情况,正确分类的都被踢除掉)
//F表示symmetric环境下奇数弱分类器,如果考虑是从0计数,则应该是第偶数个弱分类器,是否指示采用对称特征???

#ifdef CV_VERBOSE
printf( "+----+----+-+---------+---------+---------+---------+\n" );
printf( "| N |%%SMP|F| ST.THR | HR | FA | EXP. ERR|\n" );
printf( "+----+----+-+---------+---------+---------+---------+\n" );
#endif

//userdata包含了参与训练的积分图和特征,其指针应该是用于回调的用户参数
userdata = cvUserdata( data, haarFeatures );

//权值只有在LB这样的boosttype中起作用icvBoostStartTrainingLB。
//这里讨论非LB情况,函数根据cls值计算参与训练特征的weakTrainVals,weakTrainVals或为+1或为-1
trainer = cvBoostStartTraining( &data->cls, weakTrainVals, &data->weights,
sampleIdx, boosttype );

乎剔除小权值的特征,将大权值的index放到trimmedIdx数据结构中
trimmedIdx = cvTrimWeights( &data->weights, sampleIdx, weightfraction );
numtrimmed = (trimmedIdx) ? MAX( trimmedIdx->rows, trimmedIdx->cols ) : m;

//data->valcache有预计算特征值
//flags是CV_COL_SAMPLE或CV_ROW_SAMPLE
//weakTrainVals?
//
//得到对称特征
if( classifier->feature[i].desc[0] == 'h' )

{//倾斜
int tmp = 0;




//计算各对称特征的特征值
for( j = 0; j < numtrimmed; j++ )

/调用icvEvalCARTHaarClassifie r函数计算训练出来的弱分类器对于所有参与训练的样本的特征值
eval.data.fl[idx] = classifier->eval_r( (CvIntHaarClassifier*) classifier,
(sum_type*) (data->sum.data.ptr + idx * data->sum.step),
(sum_type*) (data->tilted.data.ptr + idx * data->tilted.step),
data->normfactor.data.fl[idx] );

//这里应该是更新各个样本的weight
alpha = cvBoostNextWeakClassifie r( &eval, &data->cls, weakTrainVals,
&data->weights, trainer );

//统计正样本数量,并且计算出正样本的对于弱分类器的特征值(一个弱分类器对应一个特征)
//icvEvalCARTHaarClassifie r中的left right是否是考虑多特征情况下,按照一定顺序编号
//找到最适合的特征值返回
eval.data.fl[numpos] = 0.0F;
for( j = 0; j < seq->total; j++ )
{
classifier = *((CvCARTHaarClassifier**) cvGetSeqElem( seq, j ));
eval.data.fl[numpos] += classifier->eval_r(
(CvIntHaarClassifier*) classifier,
(sum_type*) (data->sum.data.ptr + idx * data->sum.step),
(sum_type*) (data->tilted.data.ptr + idx * data->tilted.step),
data->normfactor.data.fl[idx] );
}

//根据检测率取门限,通过该门限获得虚警率
threshold = eval.data.fl[(int) ((1.0F - minhitrate) * numpos)];


CvClassifier* cvCreateCARTClassifier( CvMat* trainData,
//包含每个样本预计算的特征的特征值,按特征值升序排列的索引数组在trainParams的sortedIdx中
int flags,
CvMat* trainClasses,//+1,-1
CvMat* typeMask,
CvMat* missedMeasurementsMask,
CvMat* compIdx,
CvMat* sampleIdx,//如果不为NULL,样本的序,按权值升序排列
CvMat* weights,//样本权值
CvClassifierTrainParams* trainParams )

CvClassifier* cvCreateMTStumpClassifie r( CvMat* trainData,//预先计算的特征值
int flags,
CvMat* trainClasses,//样本分类+1或者-1
CvMat* typeMask,
CvMat* missedMeasurementsMask,
CvMat* compIdx,
CvMat* sampleIdx,//剔除小权值样本后的序号数组
CvMat* weights,//样本权值
CvClassifierTrainParams* trainParams )

//datan为预计算特征数,如果能得到新的特征(getTrainData!=NULL)则n应该为所有能够得到的特征数,n肯定大于等于datan
//当在进行对称训练的时候cvCreateMTStumpClassifie r中的getTrainData为NULL,此时为训练剩下的特征数
assert( datan <= n );
//m为所有可能参与训练的样本数,如果剔除了小权值样本,则sampleIdx!=NULL,此时为l为实际参与训练的样本数,
//按照权值对样本排序产生sampleIdx与按照特征值对样本排序产生sortedata
if( sampleIdx != NULL )

//filter!=NULL表示剔除小权值样本并且样本按照特特征值排序
if( filter != NULL || sortedn < n )

你可能感兴趣的:(AdaBoost算法程序介绍说明)