当前位置:文档之家› OPENCV ADABOOST人脸检测训练程序阅读笔记(LBP特征)

OPENCV ADABOOST人脸检测训练程序阅读笔记(LBP特征)

1、训练程序整体流程(1)读输入参数并打印相关信息(2)进入训练程序最外层入口classifier.train1)读正负样本,将正负样本放入imgLiast中,先读正样本,后读负样本2)load(dirName)判断之前是否有已训练好的xml文件,若有,不在重新训练该stage的xml文件,没有返回false,初始化参数3)计算requiredLeafFARate=pow(maxFalseAlarm,numStages)/max_depth,该参数是stage停止条件(利用训练样本集来计算tempLeafFARate,若tempLeafFARate小于这一参数,则退出stage训练循环);4)Stage训练循环5)更新训练样本集,计算tempLeafFARate(负样本被预测为正样本的个数除以读取负样本的次数,第一次没有训练之前,这个比值为1,因为没训练之前,所有负样本都被预测成了正样本,当第一层训练好以后,负样本采集时会先用第一层的分类器预测一次,若能分类,则不选用,选用负样本的数目是固定的,但选用这么多负样本总共要选的次数会随着层数的增多而加大,因为层数越大,分类器的分类能力也要求越大,说需要的样本就是前面分类器所不恩呢该识别的,故在采集时也比较困难。

)6)判断stage是否退出训练,若tempLeafFARate<requiredLeafFARate则退出stage训练,否则继续;7)强训练器训练入口tempStage->train()a.建立训练数据data=new CvCascadeBoostTrainData(主要是一些参数的设置,还有特征值的计算)b.初始化样本权重update_weights(0);c.弱分类器训练循环i)tree->train—》do_trainai)根节点的初始root=data->subsample_data(_subsample_idx);(主要是对根节点的一些参数进行初始化,parent0,count1,split0,value0,class_idx0,maxlr0,left=right=0,等等)bi)CV_CALL(try_split_node(root)),根据根节点计算整颗数的各节点的参数配置aii)calc_node_value(node);计算节点的回归值,类似于分类投票值sum(w*class_lable),正样本的class_lable取,负样本的class_lable取-1;计算节点的风险值node_risk,noderisk is the sum of squared errors:sum_i((Y_i-<node_value>)^2)bii)判断节点是否可以分裂(判断依据:样本值和设计的节点最大深度);再利用node_risk与regression_accuracy,如果这个节点的所有训练样本的节点估计值的绝对差小于这个参数,节点不再进行分裂cii)找出最佳分裂best_split=find_best_split(node);aiii)定义DTreeBestSplitFinder finder(this,node);biii)parallel_reduce(cv::BlockedRange(0,data->var_count),finder);此时调用DTreeBestSplitFinder类的操作符DTreeBestSplitFinder::operator()(constBlockedRange&range)aiv)遍历所有特征vi=vi1;vi<vi2;vi++biv)res=tree->find_split_cat_reg()得到特征为split->var_idx=vi的最佳分裂的质量split->quality(split->quality越大越好)av)将特征为vi所有样本的特征值返回到cat_labelsbv)计算每个特征值取值不权值和和响应和,例如特征值为,则将所有特征值列表中特征值为的样本权值相加,LBP的特征值范围是0~255,故有256个categorycv)计算每个category的平均响应值,即将每个category的响应和除以每个category的样本权值和dv)icvSortDblPtr(sum_ptr,mi,0);把256个值进行升序排序,注意sum_ptr里存的是sum[i]的地址,这里排序的依据是特征值还是按照每个特征值的平均响应来排序???个人感觉是按特征值的平均响应来排序fv)将每个特征值的平均响应值乘以该特征值的总权值得到每个特征值的总响应gv)遍历subset_i=0;subset_i<mi-1;subset_i++avi)计算索引是subset_i在排序前的idxbvi)获取索引idx对应的样本总权重cvi)获取索引idx对应的样本总响应dvi)以subset_i为分裂点,计算分裂质量(sumL*sumL)/weightL+(sumR*sumR)/weightRfvi)若最佳分裂质量小于这个质量,则更新最佳分裂质量hv)经过训练得到最佳分裂点和最佳分裂质量,将遍历得到的值更新到split结构体各参数。

Iv)得到该特征对应的split->subset,for(i=0;i<=best_subset;i++)avi)计算索引是i在排序前的idxbvi)split->subset[idx>>5]|=1<<(idx&31);subset[8],每个数组里存放32位的整数,整数值由idx决定,idx也就是特征值大小civ)若bestSplit->quality<split->quality,将split拷贝到bestSplitciii)初始化一个bestSplit,将finder.bestSplit拷贝到bestSplit,并返回bestSplitdii)将bestSplit赋给node->spliteii)计算节点方向quality_scale=calc_node_dir(node);aiii)获取最佳特征的索引vibiii)遍历所有样本i=0;i<n;i++aiv)计算第i个样本的特征为vi的特征值idxbiv)获取第i个样本的权重wciv)d=idx>=0?CV_DTREE_CAT_DIR(idx,subset):0CV_DTREE_CAT_DIR(idx,subset)=(2*((subset[(idx)>>5]&(1<<((idx)&31)))==0)-1)(d=1或者d=-1)div)sum+=d*w;sum_abs+=(d&1)*wfiv)dir[i]=(char)d;ciii)R=(sum_abs+sum)*0.5;(取向正样本的所有权重和)diii)L=(sum_abs-sum)*0.5;;(取向负样本的所有权重和)fiii)node->maxlr=MAX(L,R);giii)返回node->split->quality/(L+R);fii)split_node_data(node);aiii)complete_node_dir(node);对每个样本的归类属性再一次定义,确保每个样本要么分到左边要么分到右边biii)遍历样本,得到左节点和右节点的样本数nl和nrciii)对左节点和右节点初始化diii)分别计算左节点和右节点的每个特征对应的分类样本数(这中间的代码不是很懂!!!)gii)try_split_node(node->left);Iii)try_split_node(node->right);ii)cvSeqPush(weak,&tree);将训练好的树添加到弱分类器重iii)update_weights(tree);更新样本权重ai)weak_eval[i]=f(x_i)in[-1,1]对应代码为weak_eval->data.db[i]*=-orig_response->data.i[i];i为0~n-1,n为样本数目bi)w_i*=exp(-y_i*f(x_i))iv)trim_weights();调整权重,但在程序中未看出调整,该函数是根据更新后的权重调整subsample_mask的数据,即利用阈值判断正样本被检测正确的将subsample_mask的数据赋值为1;v)强制退出循环判断cvCountNonZero(subsample_mask),若subsample_mask中数据全为0,则直接退出弱分类器循环,这种情况应该不会出现d.弱分类器训练循环终止条件判断while(!isErrDesired()&&(weak->total<params.weak_count));(isErrDesired()计算负样本的虚警率,若小于maxfalserat返回true,反之返回false;isErrDesired()还计算stage阈值,具体计算过程:对正样本进行预测,预测值放在eval向量中,对向量中的预测值排序(本人默认为升序),计算阈值索引int thresholdIdx= (int)((1.0F-minHitRate)*numPos);threshold=eval[thresholdIdx];这样在检测时,根据叶子节点的预测值小于这个阈值即认为是负样本)8)如果强分类器重弱分类器的个数大于0,返回ture,否则返回false9)返回ture时输出和打印相关信息,否则退出stage循环10)保存stage的xml文件(3)输出和打印相关信息。

相关主题