opencv 之 icvCreateHidHaarClassifierCascade 分类器信息初始化函数部分详细代码注释。
2015-02-02 11:50
716 查看
请看注释。这个函数,是人脸识别主函数,里面出现过的函数之一,作用是初始化分类器的数据,就是一个xml文件的数据初始化。
static CvHidHaarClassifierCascade* icvCreateHidHaarClassifierCascade( CvHaarClassifierCascade* cascade ) { CvRect* ipp_features = 0;//定义一个矩形框指针 float *ipp_weights = 0, *ipp_thresholds = 0, *ipp_val1 = 0, *ipp_val2 = 0;//单精度浮点数指针4个 int* ipp_counts = 0;//整形指针1个 CvHidHaarClassifierCascade* out = 0;//最终返回的值 int i, j, k, l;//for循环的控制变量 int datasize;//数据大小 int total_classifiers = 0;//总的分类器数目 int total_nodes = 0; char errorstr[1000];//错误信息数组 CvHidHaarClassifier* haar_classifier_ptr;//级联分类器指针 CvHidHaarTreeNode* haar_node_ptr; CvSize orig_window_size;//提取窗口的大小 int has_tilted_features = 0; int max_count = 0; 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 )//如果分类器的阶级数<=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 = 0; 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 <= 0 ) { 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 = 0; 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 = 0; l < classifier->count; l++ ) //这个是关键循环,主数据的获取 //以haarcascade_upperbody.xml为例,此时classifier->count=1,循环一次,进入里面获取关键数据 { for( k = 0; 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;//|是位运算,例如0|1=1,这行的作用是判断has和tilted那个是1,还不知道其意义何在 if( r.width < 0 || r.height < 0 || r.y < 0 || r.x + r.width > orig_window_size.width || (!tilted && (r.x < 0 || r.y + r.height > orig_window_size.height)) || (tilted && (r.x - r.height < 0 || 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, 0, sizeof(*out) );//对变量初始化,全部填充0 //下面是逐个赋值,初始化头部 /* init header */ out->count = cascade->count;//新分类器out的stage数目 out->stage_classifier = (CvHidHaarStageClassifier*)(out + 1);//子分类器tree的数目 haar_classifier_ptr = (CvHidHaarClassifier*)(out->stage_classifier + cascade->count);//tree指针 haar_node_ptr = (CvHidHaarTreeNode*)(haar_classifier_ptr + total_classifiers);//tree里面node的指针 out->isStumpBased = 1;//布尔类型,true out->has_tilted_features = has_tilted_features; out->is_tree = 0; /* initialize internal representation */ for( i = 0; 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 = 1; haar_classifier_ptr += stage_classifier->count; hid_stage_classifier->parent = (stage_classifier->parent == -1) ? NULL : out->stage_classifier + stage_classifier->parent; hid_stage_classifier->next = (stage_classifier->next == -1) ? NULL : out->stage_classifier + stage_classifier->next; hid_stage_classifier->child = (stage_classifier->child == -1) ? NULL : out->stage_classifier + stage_classifier->child; out->is_tree |= hid_stage_classifier->next != NULL; for( j = 0; 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 = 0; l < node_count; l++ ) { CvHidHaarTreeNode* node = hid_classifier->node + l; CvHaarFeature* feature = classifier->haar_feature + l; memset( node, -1, sizeof(*node) ); node->threshold = classifier->threshold[l]; node->left = classifier->left[l]; node->right = classifier->right[l]; if( fabs(feature->rect[2].weight) < DBL_EPSILON || feature->rect[2].r.width == 0 || feature->rect[2].r.height == 0 ) memset( &(node->feature.rect[2]), 0, sizeof(node->feature.rect[2]) ); else hid_stage_classifier->two_rects = 0; } memcpy( alpha_ptr, classifier->alpha, (node_count+1)*sizeof(alpha_ptr[0])); haar_node_ptr = (CvHidHaarTreeNode*)cvAlignPtr(alpha_ptr+node_count+1, sizeof(void*)); out->isStumpBased &= node_count == 1; } } /* #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; }
相关文章推荐
- OpenCV Haar分类器人脸检测部分代码注释
- VS中为类,函数代码自动添加版权注释信息
- VS中为类,函数代码自动添加版权注释信息
- Coherence-Enhancing Shock Filters 代码及详细注释【OpenCV】
- 网站商品信息爬虫代码及详细注释
- VS中为类,函数代码自动添加版权注释信息
- VS中为类,函数代码自动添加版权注释信息
- 自适应直方图均衡(CLAHE) 代码及详细注释【OpenCV】
- openCV实现多人脸检测,多眼部检测,完整代码和详细注释
- VS中为类,函数代码自动添加版权注释信息
- Haar特征原理与icvCreateIntHaarFeatures方法的具体实现附详细注释—— 人脸识别的尝试系列(二)
- 联合双边滤波器(joint bilateral filter) 代码及详细注释【OpenCV】
- 量子编程详解之一: QP-nano代码大餐之状态机函数详细注释
- 【安装】VS2010中为类、函数代码添加版权注释信息
- Opencv研读笔记:haartraining程序之icvCreateCARTStageClassifier函数详解(强分类器创建)~
- C#实现为类和函数代码自动添加版权注释信息的方法
- OpenCV中的DFT和iDFT的详细代码及注释
- Opencv研读笔记:haartraining程序之icvCreateCARTStageClassifier函数详解(强分类器创建)~
- L0 范数图像平滑(L0 Smooth) 代码及详细注释 【OpenCV】
- Opencv研读笔记:haartraining程序之icvCreateCARTStageClassifier函数详解(强分类器创建)