opencv 之 icvCreateHidHaarClassifierCascade 分类器信息初始化函数部分详细代码注释。
请看注释。这个函数,是人脸识别主函数,里面出现过的函数之一,作用是初始化分类器的数据,就是一个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;
}
opencv 之 icvCreateHidHaarClassifierCascade 分类器信息初始化函数部分详细代码注释。的更多相关文章
- 常见的JS手写函数汇总(代码注释、持续更新)
最近在复习面试中常见的JS手写函数,顺便进行代码注释和总结,方便自己回顾也加深记,内容也会陆陆续续进行补充和改善. 一.手写深拷贝 <script> const obj1 = { name ...
- atitit opencv apiattilax总结 约500个函数 .xlsx
atitit opencv apiattilax总结 约500个函数 .xlsx 1.1. CxCore中文参考手册 1 1.2. 机器学习中文参考手册 knn svm 1 1.3. CvAu ...
- iOS: 聊聊 Designated Initializer(指定初始化函数)
iOS: 聊聊 Designated Initializer(指定初始化函数) 一.iOS的对象创建和初始化 iOS 中对象创建是分两步完成: 分配内存 初始化对象的成员变量 我们最熟悉的创建NSOb ...
- 第3阶段——内核启动分析之start_kernel初始化函数(5)
内核启动分析之start_kernel初始化函数(init/main.c) stext函数启动内核后,就开始进入start_kernel初始化各个函数, 下面只是浅尝辄止的描述一下函数的功能,很多函数 ...
- 金融量化分析【day112】:量化平台的使用-初始化函数
一.set_benchmark - 设置基准 1.实现代码 # 导入函数库 import jqdata #初始化函数,设定基准等等 def initialize(context): set_bench ...
- 《扩展和嵌入python解释器》1.4 模块方法表和初始化函数
<扩展和嵌入python解释器>1.4 模块方法表和初始化函数 1.4 模块方法表和初始化函数 下面,我演示如何从Python程序调用spam_system().首先,我们需要在’方法 ...
- 痞子衡嵌入式:深扒IAR启动函数流程之段初始化函数__iar_data_init3实现
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是IAR启动函数流程里的段初始化函数__iar_data_init3实现. 本篇是 <IAR启动函数流程及其__low_level_ ...
- linux-0.11分析:init文件 main.c的第二个初始化函数trap_init() 第五篇随笔
2.第二个初始化函数,trap_init() 参考 [github这个博主的 厉害][ https://github.com/sunym1993/flash-linux0.11-talk ] kern ...
- linux-0.11分析:init文件 main.c的第一个初始化函数mem_int 第四篇随笔
init文件夹 mian.c 参考 [github这个博主的 厉害][ https://github.com/sunym1993/flash-linux0.11-talk ] 首先先看看这个mian. ...
随机推荐
- 字符串转换为数字---使用java7的装箱功能
以前转换只知道使用Xxx.prasexxx方法,原来,还可以直接装箱自动转换. //String类型字符串 String intStr = "123"; int str2int1 ...
- Swift小练习-引导页
任何一门语言,只要长期不用就会忘掉,得时不时的敲敲小项目,练练手; let scrollViewBG = UIScrollView.init(frame: SLScreenRect) let imag ...
- XPath注入跟SQL注入差不多,只不过这里的数据库走的xml格式
SQL注入这块不想细聊了,相信很多朋友都听到耳朵长茧,不外乎是提交含有SQL操作语句的信息给后端,后端如果没有做好过滤就执行该语句,攻击者自然可以随意操纵该站点的数据库. 比如有一个图书馆站点book ...
- 各种android应用模仿源码
V2EX的非官方Android客户端,极力遵循Material Design风格 下载 湘潭大学三翼校园"四季电台" Android客户端 下载 高仿煎蛋客户端 下载 ...
- 关于c++的 vector 容器的使用及创建方法
1.vector向量容器的使用,vector具有自动管理的功能,可以进行元素的查找删除 创建方法: (1) vector<int > v; 创建了一个v的容器,没指定容量: (2) v ...
- C++ 控制台代码输出控制
在C++控制台应用程序中可以控制控制台输出的字体颜色和 接受任意按键退出 #ifndef CONSOLE_UTILS_H #define CONSOLE_UTILS_H #include <wi ...
- xcodebuild编译ipa
#!/bin/sh # autoBuild.sh # CTest # # Created by Ethan on 14-11-3. # Copyright (c) 2014年 Ethan. All r ...
- 学习笔记:java线程安全
首先得明白什么是线程安全: 线程安全是编程中的术语,指某个函数 (计算机科学).函数库在多线程环境中被调用时,能够正确地处理各个线程的局部变量,使程序功能正确完成. 这是维基百科里的资料,看完后还不是 ...
- SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享
SQL Server定时自动抓取耗时SQL并归档数据发邮件脚本分享 第一步建库和建表 USE [master] GO CREATE DATABASE [MonitorElapsedHighSQL] G ...
- 《深入理解Java虚拟机》垃圾收集器
说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物.事实上,GC的历史远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态 ...