本例是一个汽车外形的识别程序。
源码下载:https://download.csdn.net/download/tanmx219/10623808
xml分类器及检测原理训练得到的xml分类器文件内容如下所示,
BOOST
LBP
24
48
GAB
9.9500000476837158e-01
5.0000000000000000e-01
9.4999999999999996e-01
1
100
256
1
10
3
-1.0521354675292969e+00
一般的参数都不难理解,我这里只讲几个比较难理解的参数,
程序中的subsets是指分类器中每个特征树下面的internalNodes节点,
表示这一层有几个弱分类器
表示这一层的threshold,这个threshold要跟所有弱分类器的输出之和比较后然后决定这层的输出时0还是1
internalNodes 表示的是这个弱分类器,以一个实际的internalNodes为例,
0 -1 4 1438712153 -216989541 -1056911107 -721088487
277360815 1535640456 706631871 1068310687
-8.9545452594757080e-01 7.0357143878936768e-01
其中 0 和 -1表示的是叶节点的索引(leafindex);
后面的那个数值4是predictCategoricalStump函数中的stump.featureIdx,他表示的是这个节点属于哪个feature,即feature的索引,可利用这个索引跟输入图像的序号快速定位输入图像的积分图然后求得这个索引对应的特征值(3.0以前的老版本中对应的是Node->split->var_idx)
后面那8个数是CvDTreeSplit的subset的内容(subsets[0]~subsets[7]),算出来的特征值会跟这个subset里的特定子集比较来看是不是属于这个子集。
leafValues表示左右child的值,二叉树如果向左分裂就是左值,向右分裂就是右值。
从上面图可以看出,OpenCV由弱分类器“并联”组成强分类器,而由强分类器“串联”组成级联分类器。
为了检测到不同大小的目标,一般有两种做法:逐步缩小图像;或者,逐步放大检测窗口。缩小图像就是把图像长宽同时按照一定比例(默认1.1 or 1.2)逐步缩小,然后检测;放大检测窗口是把检测窗口长宽按照一定比例逐步放大,这时位于检测窗口内的特征也会对应放大,然后检测。在默认的情况下,OpenCV是采取逐步缩小的情况,如下图所示,最先检测的图片是底部那张大图。
然后,对应每张图,级联分类器的大小固定的检测窗口器开始遍历图像,以便在图像找到位置不同的目标。对照程序来看,这个固定的大小就是上图的红色框,大小是XML分类器中规定的参数决定的,
24
48
这样,为了找到图像中不同位置的目标,需要逐次移动检测窗口,随着检测窗口的移动,窗口中的特征相应也随着窗口移动,这样就可以遍历到图像中的每一个位置,完成所有的特征检测。
main主程序如下所示
#include
#pragma comment(lib, "opencv_world341d.lib")
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
String TEST_DIR = "data_file\\test";
String CAR_CXML = "data_file\\cascade.xml";
String NAME_WIN = "Entrenar OpenCV";
CascadeClassifier car_detector;
// read all the data
if (!car_detector.load(CAR_CXML)) { cout attr = (const char**)(chunk + 1);
count = 0;
// 如果链表中还没节点(内容),则该chunk就是第一个,如果已经有了节点,
// 就把chunk作为下一个节点
if( !last )
first = last = chunk;
else
last = last->next = chunk;
}
last->attr[count*2] = attrname->str.ptr; // last->attr[count*2] 指针指向tag的内存
}
if( last ) // 读取value(!last表示标签名称tag, last表示是value值)
{
CvFileNode stub;
// 跳过空格和一些无效字符
if( *ptr != '=' )
{
ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
if( *ptr != '=' )
CV_PARSE_ERROR( "Attribute name should be followed by \'=\'" );
}
// 确认值是放在双引号之中的
c = *++ptr;
if( c != '\"' && c != '\'' )
{
ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
if( *ptr != '\"' && *ptr != '\'' )
CV_PARSE_ERROR( "Attribute value should be put into single or double quotes" );
}
// 取value值,读以的结果保存在stub->data.str
ptr = icvXMLParseValue( fs, ptr, &stub, CV_NODE_STRING );
assert( stub.tag == CV_NODE_STRING );
// 注意,这里last->attr取得的tag和value,只不过是把last->attr的指针指向数据的内存
last->attr[count*2+1] = stub.data.str.ptr;
count++;
}
c = *ptr;
have_space = cv_isspace(c) || c == '\0';
if( c != '>' )
{
ptr = icvXMLSkipSpaces( fs, ptr, CV_XML_INSIDE_TAG );
c = *ptr;
}
if( c == '>' )
{
if( tag_type == CV_XML_HEADER_TAG )
CV_PARSE_ERROR( "Invalid closing tag for
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?