转载自: http://blog.csdn.net/wuxiaoyao12/article/details/48088999
上图显示的参数,大多与opencv_traincascade.exe的输入参数已知。其中maxCatCount和featSize定义如下
maxCatCount:int maxCatCount; // 0 in case of numerical features
featSize:int featSize; // 1 in case of simple features (HAAR,LBP) and N_BINS(9)*N_CELLS(4) in case of Dalal's HOG features
feature结构对于上两值默认的是:
CvFeatureParams::CvFeatureParams() : maxCatCount( 0 ),featSize( 1 ) {...};
其中
LBP:maxCatCount = 256;
HOG:featSize = N_BINS * N_CELLS;
其他情况均用默认值。
关于maxWeakCount、stageThreshold和weakClassifiers,如下:
- voidCvCascadeBoost::write(FileStorage&fs,constMat&featureMap)const
- {
- CvCascadeBoostTree*weakTree;
- fs<<CC_WEAK_COUNT<<weak->total;//弱分类器总数
- fs<<CC_STAGE_THRESHOLD<<threshold;//见后续补充
- fs<<CC_WEAK_CLASSIFIERS<<"[";
- for(intwi=0;wi<weak->total;wi++)
- {
- weakTree=*((CvCascadeBoostTree**)cvGetSeqElem(weak,wi));
- weakTree->write(fs,featureMap);
- }
- fs<<"]";
- }
- voidCvCascadeBoostTree::write(FileStorage&fs,constMat&featureMap)
- {
- intmaxCatCount=((CvCascadeBoostTrainData*)data)->featureEvaluator->getMaxCatCount();
- intsubsetN=(maxCatCount+31)/32;
- queue<CvDTreeNode*>internalNodesQueue;
- intsize=(int)pow(2.f,(float)ensemble->get_params().max_depth);
- Ptr<float>leafVals=newfloat[size];
- intleafValIdx=0;
- intinternalNodeIdx=1;
- CvDTreeNode*tempNode;
- CV_DbgAssert(root);
- internalNodesQueue.push(root);
- fs<<"{";
- fs<<CC_INTERNAL_NODES<<"[:";
- while(!internalNodesQueue.empty())
- {
- tempNode=internalNodesQueue.front();
- CV_Assert(tempNode->left);//左分支存在
- if(!tempNode->left->left&&!tempNode->left->right)//leftnodeisleaf左分支是叶子节点
- {
- leafVals[-leafValIdx]=(float)tempNode->left->value;
- fs<<leafValIdx--;//0-1-2...
- }
- else//左分支不是叶子节点
- {
- internalNodesQueue.push(tempNode->left);
- fs<<internalNodeIdx++;//123...
- }
- CV_Assert(tempNode->right);//右分支存在
- if(!tempNode->right->left&&!tempNode->right->right)//rightnodeisleaf右分支是叶子节点
- {
- leafVals[-leafValIdx]=(float)tempNode->right->value;
- fs<<leafValIdx--;//0,-1,-2...
- }
- else//右分支不是叶子节点
- {
- internalNodesQueue.push(tempNode->right);
- fs<<internalNodeIdx++;//123...
- }
- intfidx=tempNode->split->var_idx;//var_idx:分裂中所用到的变量的索引
- fidx=featureMap.empty()?fidx:featureMap.at<int>(0,fidx);
- fs<<fidx;
- if(!maxCatCount)
- fs<<tempNode->split->ord.c;//c:用在数值变量的分裂上的阈值。规则如下:如果var_value<c,那么next_node<-left,否则next_node<-right。
- else
- for(inti=0;i<subsetN;i++)
- fs<<tempNode->split->subset[i];//subset:二值集合,用在在类别向量的分裂上。规则如下:如果var_value在subset里,那么next_node<-left,否则next_node<-right。
- internalNodesQueue.pop();
- }
- fs<<"]";//CC_INTERNAL_NODES
- fs<<CC_LEAF_VALUES<<"[:";
- for(intni=0;ni<-leafValIdx;ni++)
- fs<<leafVals[ni];//即从上面得到的节点value
- fs<<"]";//CC_LEAF_VALUES
- fs<<"}";
- }
补充threshold:
- inti,count=data->sample_count,nz_count=0;
- doublesum,threshold;
- if(params.weight_trim_rate<=0.||params.weight_trim_rate>=1.)
- EXIT;
- //useweak_evalastemporarybufferforsortedweights
- cvCopy(weights,weak_eval);
- icvSort_64f(weak_eval->data.db,count,0);
- //asweighttrimming(调整)occursimmediatelyafterupdatingtheweights,
- //wheretheyarerenormalized,weassumethattheweightsum=1.
- sum=1.-params.weight_trim_rate;
- for(i=0;i<count;i++)
- {
- doublew=weak_eval->data.db[i];
- if(sum<=0)
- break;
- sum-=w;
- }
- threshold=i<count?weak_eval->data.db[i]:DBL_MAX;
关于features:
- void_writeFeatures(conststd::vector<Feature>features,cv::FileStorage&fs,constcv::Mat&featureMap)
- {
- fs<<FEATURES<<"[";
- constcv::Mat_<int>&featureMap_=(constcv::Mat_<int>&)featureMap;
- for(intfi=0;fi<featureMap.cols;fi++)//个数即featureMap.cols
- if(featureMap_(0,fi)>=0)
- {
- fs<<"{";
- features[fi].write(fs);
- fs<<"}";
- }
- fs<<"]";
- }
- voidCvHaarEvaluator::Feature::write(FileStorage&fs)const
- {
- fs<<CC_RECTS<<"[";
- for(intri=0;ri<CV_HAAR_FEATURE_MAX&&rect[ri].r.width!=0;++ri)//CV_HAAR_FEATURE_MAX=3,上图就表示了我们只用了一个特征
- {
- fs<<"[:"<<rect[ri].r.x<<rect[ri].r.y<<
- rect[ri].r.width<<rect[ri].r.height<<rect[ri].weight<<"]";
- }
- fs<<"]"<<CC_TILTED<<tilted;//bool型
- }
类haar特征的tilted取法如下(包括特征计算)
- voidCvHaarEvaluator::generateFeatures()
- {
- intmode=((constCvHaarFeatureParams*)((CvFeatureParams*)featureParams))->mode;
- intoffset=winSize.width+1;
- for(intx=0;x<winSize.width;x++)
- {
- for(inty=0;y<winSize.height;y++)
- {
- for(intdx=1;dx<=winSize.width;dx++)
- {
- for(intdy=1;dy<=winSize.height;dy++)
- {
- //haar_x2
- if((x+dx*2<=winSize.width)&&(y+dy<=winSize.height))
- {
- features.push_back(Feature(offset,false,x,y,dx*2,dy,//开始tilted都是false
- x+dx,dx,+2));
- }
- //haar_y2
- if((x+dx<=winSize.width)&&(y+dy*2<=winSize.height))
- {
- features.push_back(Feature(offset,
- x,dy*2,
- x,y+dy,+2));
- }
- //haar_x3
- if((x+dx*3<=winSize.width)&&(y+dy<=winSize.height))
- {
- features.push_back(Feature(offset,
- x,dx*3,
- x+dx,+3));
- }
- //haar_y3
- if((x+dx<=winSize.width)&&(y+dy*3<=winSize.height))
- {
- features.push_back(Feature(offset,dy*3,+3));
- }
- if(mode!=CvHaarFeatureParams::BASIC)
- {
- //haar_x4
- if((x+dx*4<=winSize.width)&&(y+dy<=winSize.height))
- {
- features.push_back(Feature(offset,dx*4,+2));
- }
- //haar_y4
- if((x+dx<=winSize.width)&&(y+dy*4<=winSize.height))
- {
- features.push_back(Feature(offset,dy*4,+2));
- }
- }
- //x2_y2
- if((x+dx*2<=winSize.width)&&(y+dy*2<=winSize.height))
- {
- features.push_back(Feature(offset,+2,+2));
- }
- if(mode!=CvHaarFeatureParams::BASIC)
- {
- if((x+dx*3<=winSize.width)&&(y+dy*3<=winSize.height))
- {
- features.push_back(Feature(offset,+9));
- }
- }
- if(mode==CvHaarFeatureParams::ALL)
- {
- //tiltedhaar_x2
- if((x+2*dx<=winSize.width)&&(y+2*dx+dy<=winSize.height)&&(x-dy>=0))
- {
- features.push_back(Feature(offset,true,//这里开始tilted是true
- x,
- x,+2));
- }
- //tiltedhaar_y2
- if((x+dx<=winSize.width)&&(y+dx+2*dy<=winSize.height)&&(x-2*dy>=0))
- {
- features.push_back(Feature(offset,2*dy,+2));
- }
- //tiltedhaar_x3
- if((x+3*dx<=winSize.width)&&(y+3*dx+dy<=winSize.height)&&(x-dy>=0))
- {
- features.push_back(Feature(offset,y+dx,+3));
- }
- //tiltedhaar_y3
- if((x+dx<=winSize.width)&&(y+dx+3*dy<=winSize.height)&&(x-3*dy>=0))
- {
- features.push_back(Feature(offset,3*dy,
- x-dy,+3));
- }
- //tiltedhaar_x4
- if((x+4*dx<=winSize.width)&&(y+4*dx+dy<=winSize.height)&&(x-dy>=0))
- {
- features.push_back(Feature(offset,+2));
- }
- //tiltedhaar_y4
- if((x+dx<=winSize.width)&&(y+dx+4*dy<=winSize.height)&&(x-4*dy>=0))
- {
- features.push_back(Feature(offset,4*dy,+2));
- }
- }
- }
- }
- }
- }
- numFeatures=(int)features.size();
- }
- CvHaarEvaluator::Feature::Feature(intoffset,bool_tilted,
- intx0,inty0,intw0,inth0,floatwt0,
- intx1,inty1,intw1,inth1,floatwt1,
- intx2,inty2,intw2,inth2,floatwt2)
- {
- tilted=_tilted;
- rect[0].r.x=x0;
- rect[0].r.y=y0;
- rect[0].r.width=w0;
- rect[0].r.height=h0;
- rect[0].weight=wt0;
- rect[1].r.x=x1;
- rect[1].r.y=y1;
- rect[1].r.width=w1;
- rect[1].r.height=h1;
- rect[1].weight=wt1;
- rect[2].r.x=x2;
- rect[2].r.y=y2;
- rect[2].r.width=w2;
- rect[2].r.height=h2;
- rect[2].weight=wt2;
- if(!tilted)
- {
- for(intj=0;j<CV_HAAR_FEATURE_MAX;j++)
- {
- if(rect[j].weight==0.0F)
- break;
- CV_SUM_OFFSETS(fastRect[j].p0,fastRect[j].p1,fastRect[j].p2,fastRect[j].p3,rect[j].r,offset)
- }
- }
- else
- {
- for(intj=0;j<CV_HAAR_FEATURE_MAX;j++)
- {
- if(rect[j].weight==0.0F)
- break;
- CV_TILTED_OFFSETS(fastRect[j].p0,offset)
- }
- }
- }
另外,是不是觉得参数输入与输出不配,其实如下:(人家是有默认输入的)
- Feature(intoffset,
- intx2=0,inty2=0,intw2=0,inth2=0,floatwt2=0.0F);
- #defineCV_SUM_OFFSETS(p0,p1,p2,p3,rect,step)\
- /*(x,y)*/\
- (p0)=(rect).x+(step)*(rect).y;\
- /*(x+w,y)*/\
- (p1)=(rect).x+(rect).width+(step)*(rect).y;\
- /*(x,y+h)*/\
- (p2)=(rect).x+(step)*((rect).y+(rect).height);\
- /*(x+w,y+h)*/\
- (p3)=(rect).x+(rect).width+(step)*((rect).y+(rect).height);
- #defineCV_TILTED_OFFSETS(p0,y)*/\
- (p0)=(rect).x+(step)*(rect).y;\
- /*(x-h,y+h)*/\
- (p1)=(rect).x-(rect).height+(step)*((rect).y+(rect).height);\
- /*(x+w,y+w)*/\
- (p2)=(rect).x+(rect).width+(step)*((rect).y+(rect).width);\
- /*(x+w-h,y+w+h)*/\
- (p3)=(rect).x+(rect).width-(rect).height\
- +(step)*((rect).y+(rect).width+(rect).height);
Feature类组成如下:
- classFeature
- {
- public:
- Feature();
- Feature(intoffset,floatwt2=0.0F);
- floatcalc(constcv::Mat&sum,constcv::Mat&tilted,size_ty)const;
- voidwrite(cv::FileStorage&fs)const;
- booltilted;
- struct
- {
- cv::Rectr;
- floatweight;
- }rect[CV_HAAR_FEATURE_MAX];
- struct
- {
- intp0,p3;
- }fastRect[CV_HAAR_FEATURE_MAX];
- };
- inlinefloatCvHaarEvaluator::operator()(intfeatureIdx,intsampleIdx)const
- {
- floatnf=normfactor.at<float>(0,sampleIdx);
- return!nf?0.0f:(features[featureIdx].calc(sum,tilted,sampleIdx)/nf);
- }
- inlinefloatCvHaarEvaluator::Feature::calc(constcv::Mat&_sum,constcv::Mat&_tilted,size_ty)const
- {
- constint*img=tilted?_tilted.ptr<int>((int)y):_sum.ptr<int>((int)y);
- floatret=rect[0].weight*(img[fastRect[0].p0]-img[fastRect[0].p1]-img[fastRect[0].p2]+img[fastRect[0].p3])+
- rect[1].weight*(img[fastRect[1].p0]-img[fastRect[1].p1]-img[fastRect[1].p2]+img[fastRect[1].p3]);
- if(rect[2].weight!=0.0f)
- ret+=rect[2].weight*(img[fastRect[2].p0]-img[fastRect[2].p1]-img[fastRect[2].p2]+img[fastRect[2].p3]);
- returnret;
- }
补充
HOG计算:
- voidCvHOGEvaluator::generateFeatures()
- {
- intoffset=winSize.width+1;
- SizeblockStep;
- intx,t,w,h;
- for(t=8;t<=winSize.width/2;t+=8)//t=sizeofacell.blocksize=4*cellSize
- {
- blockStep=Size(4,4);
- w=2*t;//widthofablock
- h=2*t;//heightofablock
- for(x=0;x<=winSize.width-w;x+=blockStep.width)
- {
- for(y=0;y<=winSize.height-h;y+=blockStep.height)
- {
- features.push_back(Feature(offset,t));
- }
- }
- w=2*t;
- h=4*t;
- for(x=0;x<=winSize.width-w;x+=blockStep.width)
- {
- for(y=0;y<=winSize.height-h;y+=blockStep.height)
- {
- features.push_back(Feature(offset,2*t));
- }
- }
- w=4*t;
- h=2*t;
- for(x=0;x<=winSize.width-w;x+=blockStep.width)
- {
- for(y=0;y<=winSize.height-h;y+=blockStep.height)
- {
- features.push_back(Feature(offset,2*t,t));
- }
- }
- }
- numFeatures=(int)features.size();
- }
- CvHOGEvaluator::Feature::Feature(intoffset,intx,inty,intcellW,intcellH)
- {
- rect[0]=Rect(x,cellW,cellH);//cell0
- rect[1]=Rect(x+cellW,cellH);//cell1
- rect[2]=Rect(x,y+cellH,cellH);//cell2
- rect[3]=Rect(x+cellW,cellH);//cell3
- for(inti=0;i<N_CELLS;i++)
- {
- CV_SUM_OFFSETS(fastRect[i].p0,fastRect[i].p1,fastRect[i].p2,fastRect[i].p3,rect[i],offset);
- }
- }
- voidCvLBPEvaluator::generateFeatures()
- {
- intoffset=winSize.width+1;
- for(intx=0;x<winSize.width;x++)
- for(inty=0;y<winSize.height;y++)
- for(intw=1;w<=winSize.width/3;w++)
- for(inth=1;h<=winSize.height/3;h++)
- if((x+3*w<=winSize.width)&&(y+3*h<=winSize.height))
- features.push_back(Feature(offset,h));
- numFeatures=(int)features.size();
- }
- CvLBPEvaluator::Feature::Feature(intoffset,int_blockWidth,int_blockHeight)
- {
- Recttr=rect=cvRect(x,_blockWidth,_blockHeight);
- CV_SUM_OFFSETS(p[0],p[1],p[4],p[5],tr,offset)
- tr.x+=2*rect.width;
- CV_SUM_OFFSETS(p[2],p[3],p[6],p[7],offset)
- tr.y+=2*rect.height;
- CV_SUM_OFFSETS(p[10],p[11],p[14],p[15],offset)
- tr.x-=2*rect.width;
- CV_SUM_OFFSETS(p[8],p[9],p[12],p[13],offset)
- }