请看注释。这个函数,是人脸识别主函数,里面出现过的函数之一,作用是初始化分类器的数据,就是一个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;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章