casecade结构和HAAR检测流程

//使用样例,其中_cascadeCvHaarClassifierCascade结构,

//cascade为CvHidHaarClassifierCascade结构

for(i = 0; i < _cascade->count; i++ )

{

    int j, k, l;

    for(j = 0; j < cascade->stage_classifier[i].count;j++ )

    {

        for(l = 0; l < cascade->stage_classifier[i].classifier[j].count;l++ )

        {

            CvHaarFeature* feature =  &_cascade->stage_classifier[i].classifier[j].haar_feature[l];

              

            CvHidHaarFeature* hidfeature =  &cascade->stage_classifier[i].classifier[j].node[l].feature;

        }

    }

}

*******************************************************************************

typedef struct CvHaarClassifierCascade

{

         int  flags;

         int  count;   //表示有多少个stage,即多少个stage_classifier

         CvSize orig_window_size;   

         CvSize real_window_size;   

         double scale;   

         CvHaarStageClassifier* stage_classifier;   

         CvHidHaarClassifierCascade* hid_cascade;

} CvHaarClassifierCascade;

 

在检测时,用的是hid_cascade;下面介绍CvHidHaarClassifierCascade结构。

CvHidHaarClassifierCascade中的stage_classifier指向了stage的首地址,保存着一系列连续的stage。每个stage中包含了一系列的树,每棵树都有一系列的节点。

 

typedef struct CvHidHaarClassifierCascade

{

    int  count;  //表示有多少个stage,即多少个stage_classifier

    int  isStumpBased;

    int  has_tilted_features;

    int  is_tree;

    double inv_window_area;

    CvMat sum, sqsum, tilted;

    CvHidHaarStageClassifier* stage_classifier;

    sqsumtype *pq0, *pq1, *pq2, *pq3;

    sumtype *p0, *p1, *p2, *p3;

 

    void** ipp_stages;

} CvHidHaarClassifierCascade;

 

 

typedef struct CvHidHaarStageClassifier

{

    int  count; //表示有多少个树,即多少个classifier

    float threshold;

    CvHidHaarClassifier* classifier;

    Int  two_rects;

 

    struct CvHidHaarStageClassifier* next;

    struct CvHidHaarStageClassifier* child;

    struct CvHidHaarStageClassifier* parent;

} CvHidHaarStageClassifier;

 

 

typedef struct CvHidHaarClassifier

{

    int count;  //表示有多少个树节点,即多少个node

    //CvHaarFeature* orig_feature;

    CvHidHaarTreeNode* node;

    float* alpha;

} CvHidHaarClassifier;

 

 

typedef struct CvHidHaarTreeNode

{

    CvHidHaarFeature feature;

    float threshold;  //判断往左还是往右的阈值,大于阈值往左,小于阈值往右

    int left;

    int right;

} CvHidHaarTreeNode;

  

typedef struct CvHidHaarFeature

{

    struct

    {

        sumtype *p0, *p1, *p2, *p3;

        float weight;

    }  rect[CV_HAAR_FEATURE_MAX];

} CvHidHaarFeature;

其中CV_HAAR_FEATURE_MAX3,一个CvHidHaarFeature表示一个Haar特征,即3个或者2rect,以及rect相应的权重。

 

 

 下面为HAAR特征检测的具体流程:

一.在计算每个窗口的haar值时,使用CvHidHaarClassifierCascade结构的casecade,因此需要以下步骤。

1. 创建CvHidHaarClassifierCascade结构对应的casecade

即申请内存,并填写casecade中相关的头信息,如有多少个stage,每个stage下有多少个tree,每个tree下有多少个node,以及相关的阈值等信息。

2. 填写每个haar feature对应的积分图中矩形框的指针。

包括casecade指向的积分图的指针sum,更多的是相应haar特征对应的矩形框指针以及权重。每个haar特征对应着2个或者3个带权重的矩形框,分别用p0,p1,p2,p3指向每个矩形框的四个顶点在积分图中的相应位置。

另外,这里haar特征对应的矩形框是根据窗口大小变化的。如样本是20*20,某个haar特征对应的某一个矩形框是4*4,当scanWindow的窗口放大为40*40时,该矩形框也扩大为8*8

所有的矩形框顶点的指针都是基于原图的积分图的,当窗口缩放时,其haar特征对应的矩形框的顶点位置也会发生相应的缩放。

二.有了CvHidHaarClassifierCascade结构的casecade,就可以计算每个window对应的stage值了。实际上,在每一个window尺寸上创建好casecade后,就会计算该window大小下所有窗口的stage值,保存满足条件的那些窗口。然后再创建下一个缩放window尺寸上的casecade,并替换掉上一个尺寸的casecade,再计算新window大小下所有窗口的stage值,继续保存满足条件的那些窗口。如此循环,直至缩放的窗口小于样本的尺寸,或者缩放的窗口大于原图的尺寸。其中计算每个固定尺寸窗口的stage值的过程见三中详述。

三.计算每一个window尺寸上所有窗口的stage值。将满足条件的窗口保存下来。这个过程用cvRunHaarClassifierCascadeSum函数判断,当cvRunHaarClassifierCascadeSum返回值大于0,才会保存此时检测的窗口位置,作为备选,参与后面的聚类过程。

1. static int cvRunHaarClassifierCascadeSum ( const CvHaarClassifierCascade* _cascade,CvPoint pt, int start_stage )

其中入参cascade为分类器,pt为检测窗口的左上角的坐标。其中窗口大小已经在外层保存了。start_stage为计算串口haar值的起始stage,若为0,则所有的stage都参与计算。

该函数计算指定窗口中分类器对应的haar值,并根据分类器的结果判定是否满足要求。满足返回1,不满足返回0

2. cvRunHaarClassifierCascadeSum函数调用icvEvalHidHaarClassifier来计算出每个树对应节点的haar特征值,然后再和该节点的阈值比较,如果小于阈值,就进去左边分支;如果大于阈值,就进入右边分支;直至分支的索引小于等于0,此时得到的alpha为该树的计算结果。

icvEvalHidHaarClassifier函数在计算指定窗口中分类器对应的haar值,使用了积分图。即使用该windown尺寸下casecade中所有haar特征的p0,p1,p2,p3。每移动一次窗口,p0,p1,p2,p3指针移动相应的位置,再计算(*p0+*p3-*p1-*p2),其值为图像中矩形框位置的灰度和。将其乘以相应的权重,即可得到haar特征值。下面为相应的代码:

do

{

CvHidHaarTreeNode* node = classifier->node + idx;

double t = node->threshold * variance_norm_factor;

double sum = calc_sum(node->feature.rect[0],p_offset) * node->feature.rect[0].weight;

sum += calc_sum(node->feature.rect[1],p_offset) * node->feature.rect[1].weight;

if( node->feature.rect[2].p0 )

    sum += calc_sum(node->feature.rect[2],p_offset) * node->feature.rect[2].weight;

idx = sum < t ? node->left : node->right;

}

while( idx > 0 );

3. 当用icvEvalHidHaarClassifier计算所有树的节点后,再判断所有树的累积和(所有树的alpha之和)是否大于stage阈值,如果大于阈值则返回1,否则返回负值。返回1,则再进行下一个stage计算,直至所有的stage计算完毕,并且每个累积和都大于每个stage相应的阈值,则cvRunHaarClassifierCascadeSum返回1

这时一个窗口计算完毕,保存此时检测的窗口位置,作为备选,参与后面的聚类过程。

然后平移窗口,重复上述,2,3的步骤,直至窗口移动到图像的右下边界。

四.当所有满足尺寸要求的窗口遍历完毕,并将满足条件的窗口保存完毕后,再对保存的窗口进行聚类,和最小邻域过滤。

 

 

你可能感兴趣的:(OpenCV学习,C/C++)