zoukankan      html  css  js  c++  java
  • opencv 之 icvCreateHidHaarClassifierCascade 分类器信息初始化函数部分详细代码注释。

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


      1 static CvHidHaarClassifierCascade* icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade )
      2 {
      3     CvRect* ipp_features = 0;//定义一个矩形框指针
      4     float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0;//单精度浮点数指针4个
      5     int* ipp_counts = 0;//整形指针1个
      6 
      7     CvHidHaarClassifierCascade* out = 0;//最终返回的值
      8 
      9     int i, j, k, l;//for循环的控制变量
     10     int datasize;//数据大小
     11     int total_classifiers = 0;//总的分类器数目
     12     int total_nodes = 0;
     13     char errorstr[1000];//错误信息数组
     14     CvHidHaarClassifier* haar_classifier_ptr;//级联分类器指针
     15     CvHidHaarTreeNode* haar_node_ptr;
     16     CvSize orig_window_size;//提取窗口的大小
     17     int has_tilted_features = 0;
     18     int max_count = 0;
     19 
     20     if( !CV_IS_HAAR_CLASSIFIER(cascade) )//判断传进来的分类器文件是否真正确
     21         CV_Error( !cascade ? CV_StsNullPtr : CV_StsBadArg, "Invalid classifier pointer" );
     22 
     23     if( cascade->hid_cascade )//判断改分类器xml文件是否已经被初始化了
     24         CV_Error( CV_StsError, "hid_cascade has been already created" );
     25 
     26     if( !cascade->stage_classifier )//如果没有阶级分类器,报错
     27         CV_Error( CV_StsNullPtr, "" );
     28 
     29     if( cascade->count <= 0 )//如果分类器的阶级数<=0,报错
     30         CV_Error( CV_StsOutOfRange, "Negative number of cascade stages" );
     31 
     32     orig_window_size = cascade->orig_window_size;//获取识别窗口的大小
     33 
     34     /* check input structure correctness and calculate total memory size needed for
     35        internal representation of the classifier cascade */
     36 
     37     for( i = 0; i < cascade->count; i++ )//对xml文件里面的每阶段的stage进行循环提取相关数据
     38     {
     39         CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
     40         //获取每次进入循环的后阶段的子分类器,以haarcascade_upperbody.xml 为例子,count是30,stage_classifier的count是20
     41 
     42         if( !stage_classifier->classifier ||//判断阶段分类器、子分类器及其stage 层数 是否合法
     43             stage_classifier->count <= 0 )
     44         {
     45             sprintf( errorstr, "header of the stage classifier #%d is invalid "
     46                      "(has null pointers or non-positive classfier count)", i );
     47             CV_Error( CV_StsError, errorstr );
     48         }
     49 
     50         max_count = MAX( max_count, stage_classifier->count );//获取子分类器stage的数目,以haarcascade_upperbody.xml为例,是20
     51         total_classifiers += stage_classifier->count;//统计出总的子分类器的stage数目,即tree,再统计
     52 
     53         for( j = 0; j < stage_classifier->count; j++ )
     54         //这个for循环主要是进入到子分类器tree里面的数据提取并且对其正确性的判断,
     55         //循环条件为字stage数目,以haarcascade_upperbody.xml为例,为20
     56         {
     57             CvHaarClassifier* classifier = stage_classifier->classifier + j;//同上,找到此时循环的tree
     58 
     59             total_nodes += classifier->count;//计算出此时循环的tree子分类器的root node 数目,再统计。以haarcascade_upperbody.xml为例,每个tree的node是1
     60             for( l = 0; l < classifier->count; l++ )
     61                 //这个是关键循环,主数据的获取
     62                 //以haarcascade_upperbody.xml为例,此时classifier->count=1,循环一次,进入里面获取关键数据
     63             {
     64                 for( k = 0; k < CV_HAAR_FEATURE_MAX; k++ )//CV_HAAR_FEATURE_MAX = 3,循环三次,feature的最大数目,以haarcascade_upperbody.xml为例,只有1个
     65                 {
     66                     if( classifier->haar_feature[l].rect[k].r.width )
     67                         //逐层递归,先找feature,再找它里面的rect标签里面的矩阵row,行的宽度
     68                         //以haarcascade_upperbody.xml为例,是2
     69                     {
     70                         CvRect r = classifier->haar_feature[l].rect[k].r;//把此时row矩阵框赋给r
     71                         int tilted = classifier->haar_feature[l].tilted;//获取xml标签tited的值
     72                         has_tilted_features |= tilted != 0;//|是位运算,例如0|1=1,这行的作用是判断has和tilted那个是1,还不知道其意义何在
     73                         if( r.width < 0 || r.height < 0 || r.y < 0 ||
     74                             r.x + r.width > orig_window_size.width
     75                             ||
     76                             (!tilted &&
     77                             (r.x < 0 || r.y + r.height > orig_window_size.height))
     78                             ||
     79                             (tilted && (r.x - r.height < 0 ||
     80                             r.y + r.width + r.height > orig_window_size.height)))
     81                             //这个if语句是对feature里面的数据矩形的各方面判断,包括矩形的宽、高、等
     82                             //矩形# %d的分类器# %d”“级分类器# %d是不是在里面”“参考(原创)级联窗口”
     83                         {
     84                             sprintf( errorstr, "rectangle #%d of the classifier #%d of "
     85                                      "the stage classifier #%d is not inside "
     86                                      "the reference (original) cascade window", k, j, i );
     87                             CV_Error( CV_StsNullPtr, errorstr );
     88                         }
     89                     }
     90                 }
     91             }
     92         }
     93     }
     94     //上面数据的判断结束后,到这里
     95 
     96     datasize = sizeof(CvHidHaarClassifierCascade) +//获取整个分类器,xml文件的数据大小
     97                sizeof(CvHidHaarStageClassifier)*cascade->count +
     98                sizeof(CvHidHaarClassifier) * total_classifiers +
     99                sizeof(CvHidHaarTreeNode) * total_nodes +
    100                sizeof(void*)*(total_nodes + total_classifiers);
    101 
    102     out = (CvHidHaarClassifierCascade*)cvAlloc( datasize );//给最终返回的变量分配内存大小
    103     memset( out, 0, sizeof(*out) );//对变量初始化,全部填充0
    104 
    105     //下面是逐个赋值,初始化头部
    106     /* init header */
    107     out->count = cascade->count;//新分类器out的stage数目
    108     out->stage_classifier = (CvHidHaarStageClassifier*)(out + 1);//子分类器tree的数目
    109     haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count);//tree指针
    110     haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);//tree里面node的指针
    111 
    112     out->isStumpBased = 1;//布尔类型,true
    113     out->has_tilted_features = has_tilted_features;
    114     out->is_tree = 0;
    115 
    116     /* initialize internal representation */
    117     for( i = 0; i < cascade->count; i++ )
    118     {
    119         CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
    120         CvHidHaarStageClassifier* hid_stage_classifier = out->stage_classifier + i;
    121 
    122         hid_stage_classifier->count = stage_classifier->count;
    123         hid_stage_classifier->threshold = stage_classifier->threshold - icv_stage_threshold_bias;
    124         hid_stage_classifier->classifier = haar_classifier_ptr;
    125         hid_stage_classifier->two_rects = 1;
    126         haar_classifier_ptr += stage_classifier->count;
    127 
    128         hid_stage_classifier->parent = (stage_classifier->parent == -1)
    129             ? NULL : out->stage_classifier + stage_classifier->parent;
    130         hid_stage_classifier->next = (stage_classifier->next == -1)
    131             ? NULL : out->stage_classifier + stage_classifier->next;
    132         hid_stage_classifier->child = (stage_classifier->child == -1)
    133             ? NULL : out->stage_classifier + stage_classifier->child;
    134 
    135         out->is_tree |= hid_stage_classifier->next != NULL;
    136 
    137         for( j = 0; j < stage_classifier->count; j++ )
    138         {
    139             CvHaarClassifier* classifier = stage_classifier->classifier + j;
    140             CvHidHaarClassifier* hid_classifier = hid_stage_classifier->classifier + j;
    141             int node_count = classifier->count;
    142             float* alpha_ptr = (float*)(haar_node_ptr + node_count);
    143 
    144             hid_classifier->count = node_count;
    145             hid_classifier->node = haar_node_ptr;
    146             hid_classifier->alpha = alpha_ptr;
    147 
    148             for( l = 0; l < node_count; l++ )
    149             {
    150                 CvHidHaarTreeNode* node = hid_classifier->node + l;
    151                 CvHaarFeature* feature = classifier->haar_feature + l;
    152                 memset( node, -1, sizeof(*node) );
    153                 node->threshold = classifier->threshold[l];
    154                 node->left = classifier->left[l];
    155                 node->right = classifier->right[l];
    156 
    157                 if( fabs(feature->rect[2].weight) < DBL_EPSILON ||
    158                     feature->rect[2].r.width == 0 ||
    159                     feature->rect[2].r.height == 0 )
    160                     memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) );
    161                 else
    162                     hid_stage_classifier->two_rects = 0;
    163             }
    164 
    165             memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0]));
    166             haar_node_ptr =
    167                 (CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*));
    168 
    169             out->isStumpBased &= node_count == 1;
    170         }
    171     }
    172 /*
    173 #ifdef HAVE_IPP
    174     int can_use_ipp = !out->has_tilted_features && !out->is_tree && out->isStumpBased;
    175 
    176     if( can_use_ipp )
    177     {
    178         int ipp_datasize = cascade->count*sizeof(out->ipp_stages[0]);
    179         float ipp_weight_scale=(float)(1./((orig_window_size.width-icv_object_win_border*2)*
    180             (orig_window_size.height-icv_object_win_border*2)));
    181 
    182         out->ipp_stages = (void**)cvAlloc( ipp_datasize );
    183         memset( out->ipp_stages, 0, ipp_datasize );
    184 
    185         ipp_features = (CvRect*)cvAlloc( max_count*3*sizeof(ipp_features[0]) );
    186         ipp_weights = (float*)cvAlloc( max_count*3*sizeof(ipp_weights[0]) );
    187         ipp_thresholds = (float*)cvAlloc( max_count*sizeof(ipp_thresholds[0]) );
    188         ipp_val1 = (float*)cvAlloc( max_count*sizeof(ipp_val1[0]) );
    189         ipp_val2 = (float*)cvAlloc( max_count*sizeof(ipp_val2[0]) );
    190         ipp_counts = (int*)cvAlloc( max_count*sizeof(ipp_counts[0]) );
    191 
    192         for( i = 0; i < cascade->count; i++ )
    193         {
    194             CvHaarStageClassifier* stage_classifier = cascade->stage_classifier + i;
    195             for( j = 0, k = 0; j < stage_classifier->count; j++ )
    196             {
    197                 CvHaarClassifier* classifier = stage_classifier->classifier + j;
    198                 int rect_count = 2 + (classifier->haar_feature->rect[2].r.width != 0);
    199 
    200                 ipp_thresholds[j] = classifier->threshold[0];
    201                 ipp_val1[j] = classifier->alpha[0];
    202                 ipp_val2[j] = classifier->alpha[1];
    203                 ipp_counts[j] = rect_count;
    204 
    205                 for( l = 0; l < rect_count; l++, k++ )
    206                 {
    207                     ipp_features[k] = classifier->haar_feature->rect[l].r;
    208                     //ipp_features[k].y = orig_window_size.height - ipp_features[k].y - ipp_features[k].height;
    209                     ipp_weights[k] = classifier->haar_feature->rect[l].weight*ipp_weight_scale;
    210                 }
    211             }
    212 
    213             if( ippiHaarClassifierInitAlloc_32f( (IppiHaarClassifier_32f**)&out->ipp_stages[i],
    214                 (const IppiRect*)ipp_features, ipp_weights, ipp_thresholds,
    215                 ipp_val1, ipp_val2, ipp_counts, stage_classifier->count ) < 0 )
    216                 break;
    217         }
    218 
    219         if( i < cascade->count )
    220         {
    221             for( j = 0; j < i; j++ )
    222                 if( out->ipp_stages[i] )
    223                     ippiHaarClassifierFree_32f( (IppiHaarClassifier_32f*)out->ipp_stages[i] );
    224             cvFree( &out->ipp_stages );
    225         }
    226     }
    227 #endif
    228 */
    229     cascade->hid_cascade = out;
    230     assert( (char*)haar_node_ptr - (char*)out <= datasize );
    231 
    232     cvFree( &ipp_features );
    233     cvFree( &ipp_weights );
    234     cvFree( &ipp_thresholds );
    235     cvFree( &ipp_val1 );
    236     cvFree( &ipp_val2 );
    237     cvFree( &ipp_counts );
    238 
    239     return out;
    240 }
  • 相关阅读:
    SQL Azure (17) SQL Azure V12
    Microsoft Azure News(5) Azure新DV2系列虚拟机上线
    Azure Redis Cache (3) 在Windows 环境下使用Redis Benchmark
    Azure PowerShell (11) 使用自定义虚拟机镜像模板,创建Azure虚拟机并绑定公网IP(VIP)和内网IP(DIP)
    Windows Azure Virtual Machine (31) 迁移Azure虚拟机
    Windows Azure Web Site (16) Azure Web Site HTTPS
    Azure China (12) 域名备案问题
    一分钟快速入门openstack
    管理员必备的Linux系统监控工具
    Keepalived+Nginx实现高可用和双主节点负载均衡
  • 原文地址:https://www.cnblogs.com/linguanh/p/4267441.html
Copyright © 2011-2022 走看看