opencv 之 icvCreateHidHaarClassifierCascade 分类器信息初始化函数部分详细代码注释。
阅读原文时间:2024年06月21日阅读:1

请看注释。这个函数,是人脸识别主函数,里面出现过的函数之一,作用是初始化分类器的数据,就是一个xml文件的数据初始化。


static CvHidHaarClassifierCascade* icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
{
CvRect* ipp_features = ;//定义一个矩形框指针
float *ipp_weights = , *ipp_thresholds = , *ipp_val1 = , *ipp_val2 = ;//单精度浮点数指针4个
int* ipp_counts = ;//整形指针1个

 CvHidHaarClassifierCascade\* out = ;//最终返回的值

 int i, j, k, l;//for循环的控制变量  
 int datasize;//数据大小  
 int total\_classifiers = ;//总的分类器数目  
 int total\_nodes = ;  
 char errorstr\[\];//错误信息数组  
 CvHidHaarClassifier\* haar\_classifier\_ptr;//级联分类器指针  
 CvHidHaarTreeNode\* haar\_node\_ptr;  
 CvSize orig\_window\_size;//提取窗口的大小  
 int has\_tilted\_features = ;  
 int max\_count = ;

 if( !CV\_IS\_HAAR\_CLASSIFIER(cascade) )//判断传进来的分类器文件是否真正确  
     CV\_Error( !cascade ? CV\_StsNullPtr : CV\_StsBadArg, "Invalid classifier pointer" );

 if( cascade->hid\_cascade )//判断改分类器xml文件是否已经被初始化了  
     CV\_Error( CV\_StsError, "hid\_cascade has been already created" );

 if( !cascade->stage\_classifier )//如果没有阶级分类器,报错  
     CV\_Error( CV\_StsNullPtr, "" );

 if( cascade->count <=  )//如果分类器的阶级数<=0,报错  
     CV\_Error( CV\_StsOutOfRange, "Negative number of cascade stages" );

 orig\_window\_size = cascade->orig\_window\_size;//获取识别窗口的大小

 /\* check input structure correctness and calculate total memory size needed for  
    internal representation of the classifier cascade \*/

 for( i = ; i < cascade->count; i++ )//对xml文件里面的每阶段的stage进行循环提取相关数据  
 {  
     CvHaarStageClassifier\* stage\_classifier = cascade->stage\_classifier + i;  
     //获取每次进入循环的后阶段的子分类器,以haarcascade\_upperbody.xml 为例子,count是30,stage\_classifier的count是20

     if( !stage\_classifier->classifier ||//判断阶段分类器、子分类器及其stage 层数 是否合法  
         stage\_classifier->count <=  )  
     {  
         sprintf( errorstr, "header of the stage classifier #%d is invalid "  
                  "(has null pointers or non-positive classfier count)", i );  
         CV\_Error( CV\_StsError, errorstr );  
     }

     max\_count = MAX( max\_count, stage\_classifier->count );//获取子分类器stage的数目,以haarcascade\_upperbody.xml为例,是20  
     total\_classifiers += stage\_classifier->count;//统计出总的子分类器的stage数目,即tree,再统计

     for( j = ; j < stage\_classifier->count; j++ )  
     //这个for循环主要是进入到子分类器tree里面的数据提取并且对其正确性的判断,  
     //循环条件为字stage数目,以haarcascade\_upperbody.xml为例,为20  
     {  
         CvHaarClassifier\* classifier = stage\_classifier->classifier + j;//同上,找到此时循环的tree

         total\_nodes += classifier->count;//计算出此时循环的tree子分类器的root node 数目,再统计。以haarcascade\_upperbody.xml为例,每个tree的node是1  
         for( l = ; l < classifier->count; l++ )  
             //这个是关键循环,主数据的获取  
             //以haarcascade\_upperbody.xml为例,此时classifier->count=1,循环一次,进入里面获取关键数据  
         {  
             for( k = ; k < CV\_HAAR\_FEATURE\_MAX; k++ )//CV\_HAAR\_FEATURE\_MAX = 3,循环三次,feature的最大数目,以haarcascade\_upperbody.xml为例,只有1个  
             {  
                 if( classifier->haar\_feature\[l\].rect\[k\].r.width )  
                     //逐层递归,先找feature,再找它里面的rect标签里面的矩阵row,行的宽度  
                     //以haarcascade\_upperbody.xml为例,是2  
                 {  
                     CvRect r = classifier->haar\_feature\[l\].rect\[k\].r;//把此时row矩阵框赋给r  
                     int tilted = classifier->haar\_feature\[l\].tilted;//获取xml标签tited的值  
                     has\_tilted\_features |= tilted != ;//|是位运算,例如0|1=1,这行的作用是判断has和tilted那个是1,还不知道其意义何在  
                     if( r.width <  || r.height <  || r.y <  ||  
                         r.x + r.width > orig\_window\_size.width  
                         ||  
                         (!tilted &&  
                         (r.x <  || r.y + r.height > orig\_window\_size.height))  
                         ||  
                         (tilted && (r.x - r.height <  ||  
                         r.y + r.width + r.height > orig\_window\_size.height)))  
                         //这个if语句是对feature里面的数据矩形的各方面判断,包括矩形的宽、高、等  
                         //矩形# %d的分类器# %d”“级分类器# %d是不是在里面”“参考(原创)级联窗口”  
                     {  
                         sprintf( errorstr, "rectangle #%d of the classifier #%d of "  
                                  "the stage classifier #%d is not inside "  
                                  "the reference (original) cascade window", k, j, i );  
                         CV\_Error( CV\_StsNullPtr, errorstr );  
                     }  
                 }  
             }  
         }  
     }  
 }  
 //上面数据的判断结束后,到这里

 datasize = sizeof(CvHidHaarClassifierCascade) +//获取整个分类器,xml文件的数据大小  
            sizeof(CvHidHaarStageClassifier)\*cascade->count +  
            sizeof(CvHidHaarClassifier) \* total\_classifiers +  
            sizeof(CvHidHaarTreeNode) \* total\_nodes +  
            sizeof(void\*)\*(total\_nodes + total\_classifiers);

 out = (CvHidHaarClassifierCascade\*)cvAlloc( datasize );//给最终返回的变量分配内存大小  
 memset( out, , sizeof(\*out) );//对变量初始化,全部填充0

 //下面是逐个赋值,初始化头部  
 /\* init header \*/  
 out->count = cascade->count;//新分类器out的stage数目  
 out->stage\_classifier = (CvHidHaarStageClassifier\*)(out + );//子分类器tree的数目  
 haar\_classifier\_ptr = (CvHidHaarClassifier\*)(out->stage\_classifier + cascade->count);//tree指针  
 haar\_node\_ptr = (CvHidHaarTreeNode\*)(haar\_classifier\_ptr + total\_classifiers);//tree里面node的指针

 out->isStumpBased = ;//布尔类型,true  
 out->has\_tilted\_features = has\_tilted\_features;  
 out->is\_tree = ;

 /\* initialize internal representation \*/  
 for( i = ; i < cascade->count; i++ )  
 {  
     CvHaarStageClassifier\* stage\_classifier = cascade->stage\_classifier + i;  
     CvHidHaarStageClassifier\* hid\_stage\_classifier = out->stage\_classifier + i;

     hid\_stage\_classifier->count = stage\_classifier->count;  
     hid\_stage\_classifier->threshold = stage\_classifier->threshold - icv\_stage\_threshold\_bias;  
     hid\_stage\_classifier->classifier = haar\_classifier\_ptr;  
     hid\_stage\_classifier->two\_rects = ;  
     haar\_classifier\_ptr += stage\_classifier->count;

     hid\_stage\_classifier->parent = (stage\_classifier->parent == -)  
         ? NULL : out->stage\_classifier + stage\_classifier->parent;  
     hid\_stage\_classifier->next = (stage\_classifier->next == -)  
         ? NULL : out->stage\_classifier + stage\_classifier->next;  
     hid\_stage\_classifier->child = (stage\_classifier->child == -)  
         ? NULL : out->stage\_classifier + stage\_classifier->child;

     out->is\_tree |= hid\_stage\_classifier->next != NULL;

     for( j = ; j < stage\_classifier->count; j++ )  
     {  
         CvHaarClassifier\* classifier = stage\_classifier->classifier + j;  
         CvHidHaarClassifier\* hid\_classifier = hid\_stage\_classifier->classifier + j;  
         int node\_count = classifier->count;  
         float\* alpha\_ptr = (float\*)(haar\_node\_ptr + node\_count);

         hid\_classifier->count = node\_count;  
         hid\_classifier->node = haar\_node\_ptr;  
         hid\_classifier->alpha = alpha\_ptr;

         for( l = ; l < node\_count; l++ )  
         {  
             CvHidHaarTreeNode\* node = hid\_classifier->node + l;  
             CvHaarFeature\* feature = classifier->haar\_feature + l;  
             memset( node, -, sizeof(\*node) );  
             node->threshold = classifier->threshold\[l\];  
             node->left = classifier->left\[l\];  
             node->right = classifier->right\[l\];

             if( fabs(feature->rect\[\].weight) < DBL\_EPSILON ||  
                 feature->rect\[\].r.width ==  ||  
                 feature->rect\[\].r.height ==  )  
                 memset( &(node->feature.rect\[\]), , sizeof(node->feature.rect\[\]) );  
             else  
                 hid\_stage\_classifier->two\_rects = ;  
         }

         memcpy( alpha\_ptr, classifier->alpha, (node\_count+)\*sizeof(alpha\_ptr\[\]));  
         haar\_node\_ptr =  
             (CvHidHaarTreeNode\*)cvAlignPtr(alpha\_ptr+node\_count+, sizeof(void\*));

         out->isStumpBased &= node\_count == ;  
     }  
 }  

/*
#ifdef HAVE_IPP
int can_use_ipp = !out->has_tilted_features && !out->is_tree && out->isStumpBased;

 if( can\_use\_ipp )  
 {  
     int ipp\_datasize = cascade->count\*sizeof(out->ipp\_stages\[0\]);  
     float ipp\_weight\_scale=(float)(1./((orig\_window\_size.width-icv\_object\_win\_border\*2)\*  
         (orig\_window\_size.height-icv\_object\_win\_border\*2)));

     out->ipp\_stages = (void\*\*)cvAlloc( ipp\_datasize );  
     memset( out->ipp\_stages, 0, ipp\_datasize );

     ipp\_features = (CvRect\*)cvAlloc( max\_count\*3\*sizeof(ipp\_features\[0\]) );  
     ipp\_weights = (float\*)cvAlloc( max\_count\*3\*sizeof(ipp\_weights\[0\]) );  
     ipp\_thresholds = (float\*)cvAlloc( max\_count\*sizeof(ipp\_thresholds\[0\]) );  
     ipp\_val1 = (float\*)cvAlloc( max\_count\*sizeof(ipp\_val1\[0\]) );  
     ipp\_val2 = (float\*)cvAlloc( max\_count\*sizeof(ipp\_val2\[0\]) );  
     ipp\_counts = (int\*)cvAlloc( max\_count\*sizeof(ipp\_counts\[0\]) );

     for( i = 0; i < cascade->count; i++ )  
     {  
         CvHaarStageClassifier\* stage\_classifier = cascade->stage\_classifier + i;  
         for( j = 0, k = 0; j < stage\_classifier->count; j++ )  
         {  
             CvHaarClassifier\* classifier = stage\_classifier->classifier + j;  
             int rect\_count = 2 + (classifier->haar\_feature->rect\[2\].r.width != 0);

             ipp\_thresholds\[j\] = classifier->threshold\[0\];  
             ipp\_val1\[j\] = classifier->alpha\[0\];  
             ipp\_val2\[j\] = classifier->alpha\[1\];  
             ipp\_counts\[j\] = rect\_count;

             for( l = 0; l < rect\_count; l++, k++ )  
             {  
                 ipp\_features\[k\] = classifier->haar\_feature->rect\[l\].r;  
                 //ipp\_features\[k\].y = orig\_window\_size.height - ipp\_features\[k\].y - ipp\_features\[k\].height;  
                 ipp\_weights\[k\] = classifier->haar\_feature->rect\[l\].weight\*ipp\_weight\_scale;  
             }  
         }

         if( ippiHaarClassifierInitAlloc\_32f( (IppiHaarClassifier\_32f\*\*)&out->ipp\_stages\[i\],  
             (const IppiRect\*)ipp\_features, ipp\_weights, ipp\_thresholds,  
             ipp\_val1, ipp\_val2, ipp\_counts, stage\_classifier->count ) < 0 )  
             break;  
     }

     if( i < cascade->count )  
     {  
         for( j = 0; j < i; j++ )  
             if( out->ipp\_stages\[i\] )  
                 ippiHaarClassifierFree\_32f( (IppiHaarClassifier\_32f\*)out->ipp\_stages\[i\] );  
         cvFree( &out->ipp\_stages );  
     }  
 }  

#endif
*/
cascade->hid_cascade = out;
assert( (char*)haar_node_ptr - (char*)out <= datasize );

 cvFree( &ipp\_features );  
 cvFree( &ipp\_weights );  
 cvFree( &ipp\_thresholds );  
 cvFree( &ipp\_val1 );  
 cvFree( &ipp\_val2 );  
 cvFree( &ipp\_counts );

 return out;  

}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章