您的位置:首页 > 其它

AdaBoost算法程序介绍说明

2012-12-04 16:44 435 查看
关于haartraining的一些解析

Ref:http://wiki.opencv.org.cn/forum/viewtopic.php?f=10&t=11129&start=0

cvCreateTreeCascadeClassifier

/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 = icvCreateHaarTrainingData( winsize, npos + nneg );

sprintf( stage_name, "%s/", dirname );

suffix = stage_name + strlen( stage_name );

//获得背景信息,包括读取背景信息里背景文件的文件名信息并索引该文件,

consumed = 0;

//读取正样本,并计算通过所有的前面的stage的正采样数量,这样可以计算出检测率

//调用函数情况

//icvGetHaarTrainingDataFromVec内部调用icvGetHaarTrainingData

//icvGetHaarTrainingData,从规定的回调函数里icvGetHaarTraininDataFromVecCallback获得数据,

//并通过前面训练出的分类器过滤掉少量正采样,然后计算积分图,

//积分图存放在training_data结构中

poscount = icvGetHaarTrainingDataFromVec( 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);

//icvGetHaarTrainingDataFromBG内部调用

//icvGetBackgroundImage获得数据并计算积分图,将其放在training_data结构分配的内存,位置是在poscount开始nneg个数量

//training_data分配了npos + nneg个积分图内存以及权值

negcount = icvGetHaarTrainingDataFromBG( 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*) icvCreateCARTStageClassifier

//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* icvCreateCARTStageClassifier( 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++ )

/调用icvEvalCARTHaarClassifier函数计算训练出来的弱分类器对于所有参与训练的样本的特征值

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 = cvBoostNextWeakClassifier( &eval, &data->cls, weakTrainVals,

&data->weights, trainer );

//统计正样本数量,并且计算出正样本的对于弱分类器的特征值(一个弱分类器对应一个特征)

//icvEvalCARTHaarClassifier中的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* cvCreateMTStumpClassifier( 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

//当在进行对称训练的时候cvCreateMTStumpClassifier中的getTrainData为NULL,此时为训练剩下的特征数

assert( datan <= n );

//m为所有可能参与训练的样本数,如果剔除了小权值样本,则sampleIdx!=NULL,此时为l为实际参与训练的样本数,

//按照权值对样本排序产生sampleIdx与按照特征值对样本排序产生sortedata

if( sampleIdx != NULL )

//filter!=NULL表示剔除小权值样本并且样本按照特特征值排序

if( filter != NULL || sortedn < n )
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: