首先说一下这个级联分类器,OpenCV中级联分类器是根据VJ 04年的那篇论文(Robust Real-Time Face Detection)编写的,查看那篇论文,知道构建分类器的步骤如下:

1、根据haar-like特征训练多个弱分类器

2、使用adaboost算法将多个弱分类器组合成一个强分类器

3、最终的分类器是由多个强分类器级联而成

下面这幅图是弱分类器组合成强分类器的示意图(图片来源于网络):

下面这张是多个强分类器级联的示意图(图片来源于网络):

在了解了级联分类器是怎么一回事后,我们来看一看OpenCV里面级联分类器的结构

在调用OpenCV中的级联分类器对目标进行分类时,都会将一个训练好的分类器(一个训练好的.xml文件)读入到一个CvHaarClassifierCascade结构中,如下:

CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad( "haarcascade_frontalface_alt.xml", , , );

那么这个CvHaarClassifierCascade结构体里面的内容都有哪些呢?

 typedef struct CvHaarClassifierCascade
{
int flags; /* 标志位 */
int count; /* 分级分类器中强分类器的数量 */
CvSize orig_window_size; /* 训练中原始目标的大小 */  /* these two parameters are set by cvSetImagesForHaarClassifierCascade */
CvSize real_window_size; /* 待检测物体的大小 */
double scale; /* Haar块缩放的尺寸 */ CvHaarStageClassifier* stage_classifier; /* 定义强分类器数组 */
CvHidHaarClassifierCascade* hid_cascade;
}CvHaarClassifierCascade;

第一个flags,还不是很清楚,在debug模式下,flags=1112539136(好吧,这个值很诡异),我也不是很清楚

第二个count,表示整个分级分类器中强分类器的数量,即最后参与级联的强分类器的个数

第三个orig_window_size,表示的是在训练时用的正样本的尺寸,OpenCV中的尺寸是20x20

第四个和第五个,注释中说了,这两个参数需要自己设置,具体每个参数看注释

第六个stage_classifier,是强分类器指针,指向一个强分类器数组,之前的count是多少,那么此处的强分类器就有多少

最后一个hid_cascade,还不是很清楚

下面来看上面第六个参数的强分类器结构体

 typedef struct CvHaarStageClassifier
{
int count; /* number of classifiers in the battery 构成强分类器的弱分类器的数量*/
float threshold; /* threshold for the boosted classifier 叠加分类器的阈值*/
CvHaarClassifier* classifier; /* array of classifiers 定义分类器数组*/
/* these fields are used for organizing trees of stage classifiers,
rather than just stright cascades */
int next;
int child;
int parent;
}CvHaarStageClassifier;

第一个count,表示该强分类器中,弱分类器的数量,即该强分类器由多少个弱分类器组成

第二个threshold,叠加分类器的阈值(好吧。。这个我也不知道)

第三个classifier,是一个指针,指向的是一个弱分类器数组,之前的count是多少,此处的弱分类器就有多少

后面3个都不清楚。。。(望知道的网友给予帮助)

下面是弱分类器的结构

 typedef struct CvHaarClassifier
{
int count; /* number of nodes in the decision tree */
/* these are "parallel" arrays. Every index i corresponds to a node of the decision tree (root has 0-th index).
left[i] - index of the left child (or negated index if the left child is a leaf)
right[i] - index of the right child (or negated index if the right child is a leaf)
threshold[i] - branch threshold. if feature responce is <= threshold, left branch is chosen, otherwise right branch is chosed.
alpha[i] - output value correponding to the leaf. */ CvHaarFeature* haar_feature;
float* threshold;
int* left;
int* right;
float* alpha;
}CvHaarClassifier;

第一个count,在opencv里,发现始终都是1,自己想了想,因为这个结构体记录的是一个弱分类器,自然弱分类器的个数就是1了。

第二个haar_feature,也是一个指针,指向一个(因为count是1)特征结构体CvHaarFeature,这个结构体中记录的内容是弱分类器的类型(包括该haar-like特征的位置,大小,以及种类,这个结构体会在下面给出,再细说)

第三个threshold,就是那个判别函数:h(x,f,p,theta) = (p*f(x) < p*theta ? 1 : 0),中的阈值theta

   

第四个left,第五个right不是很清楚(求知道的同学详解啊~~~~)

第六个alpha,就是这个弱分类器的权重(每一个强分类器都是由多个弱分类器按照各自的权重进行表决,而得到的)

特征的结构体如下

 #define CV_HAAR_FEATURE_MAX  3
// 一个Haar特征由2~3个具有相应权重的矩形组成
typedef struct CvHaarFeature
{
int tilted; // 0 means up-right feature, 1 means 45-rotated feature
struct
{
CvRect r;
float weight;
} rect[CV_HAAR_FEATURE_MAX];
// 2-3 rectangles with weights of opposite signs and with absolute values inversely proportional to the areas of the rectangles. if rect[2].weight != 0, then the feature     consists of 3 rectangles, otherwise it consists of 2.
}CvHaarFeature;

第一个参数titled,0表示该特征是标准的haar-like特征,1表示旋转45°后的特征

  标准的haar-like特征如下:

      

  而旋转45°后的特征如下:

      

第二个参数是个结构体数组,每个结构体中包括一个矩形和一个权重,这个数组的大小是CV_HAAR_FEATURE_MAX(3)(注释中说:此处可能有2~3个矩形,这里的矩形等看了下面的解释就知道了),这个矩形和权重有什么用呢?

  在debug模式下,查看第一个弱分类器数组内的元素

  第一个元素:

 rect[].r.x =
rect[].r.y =
rect[].r.width =
rect[].r.height =
rect[].weight = -

  第二个元素:

 rect[].r.x =
rect[].r.y =
rect[].r.width =
rect[].r.height =
rect[].weight =

  第三个元素则全都是0

  这么看这些坐标,并不是很清楚,我们可以画个图:

  

  由图可见,第一个矩形表示的是A+B区域,第二个矩形表示的是B区域。

  此时再看一看每个元素的权重weight,结合积分图的概念,发现第一个矩形的积分图乘以其权重加上第二个积分图乘以其权重,恰好得到下述结果:

  (A+B)*(-1)+B*2=B-A

  看到这个公式,大家都不会陌生,这正式VJ论文中给出的众多haar-like模板中的其中一个模板的计算方法(此处不知如何表达,大家将就,看懂就行) 

我们继续考察第二个弱分类器的特征部分,其特征参数如下:

 rect[].r.x = , rect[].r.y =
rect[].r.width = , rect[].r.height =
rect[].weight = - rect[].r.x = , rect[].r.y =
rect[].r.width = , rect[].r.height =
rect[].weight =

数组的第三个元素依然都是是0,对其绘图:

  

  第一块矩形区域是A+B+C,第二块矩形区域是B,积分图乘以权重,再相加,可得:

  (A+B+C)*(-1)+B*3 = 2*B-A-C

  也是haar-like特征模板之一(此处不知如何表达,大家将就,看懂就行)

刚刚找了好久,找到一个第三个元素权重不为0的,该数组三个元素如下:

 rect[].r.x = , rect[].r.y =
rect[].r.width = , rect[].r.height = ;
rect[].weight = - rect[].r.x = , rect[].r.y =
rect[].r.width = , rect[].r.height = ;
rect[].weight = rect[].r.x = , rect[].r.y =
rect[].r.width = , rect[].r.height = ;
rect[].weight =

绘图可得:

  

  将每个矩形乘以相应的权重,相加可得:

  (A+B+C+D)*(-1)+2*B + 2*C = B+C-(A+D)

  也是模板之一

  (佩服设计这个结构体的程序员)

到此,四个结构体都说完了,如有不对,请大家指正

对OpenCV中Haar特征CvHaarClassifierCascade等结构理解的更多相关文章

  1. 对OpenCV中3种乘法操作的理解掌握

    参考了<Opencv中Mat矩阵相乘——点乘.dot.mul运算详解 >“http://blog.csdn.net/dcrmg/article/details/52404580”的相关内容 ...

  2. opencv之haar特征+AdaBoos分类器算法流程(二)

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...

  3. opencv之haar特征+AdaBoos分类器算法流程(三)

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...

  4. 浅析人脸检测之Haar分类器方法:Haar特征、积分图、 AdaBoost 、级联

    浅析人脸检测之Haar分类器方法 一.Haar分类器的前世今生 人脸检测属于计算机视觉的范畴,早期人们的主要研究方向是人脸识别,即根据人脸来识别人物的身份,后来在复杂背景下的人脸检测需求越来越大,人脸 ...

  5. 模式匹配之常见匹配算法---SIFT/SURF、haar特征、广义hough变换的特性对比分析

    识别算法概述: SIFT/SURF基于灰度图, 一.首先建立图像金字塔,形成三维的图像空间,通过Hessian矩阵获取每一层的局部极大值,然后进行在极值点周围26个点进行NMS,从而得到粗略的特征点, ...

  6. OpenCV中的矩阵和图像类型

    任务刚刚做完,就迫不及待的来写写在OpenCV中常见的几类数据类型: 在使用OpenCV时我们时常会碰到IplImage这个数据类型,IplImage就是我们通常说的“图像”进行编码的基本结构,这些图 ...

  7. OpenCV中基于Haar特征和级联分类器的人脸检测

    使用机器学习的方法进行人脸检测的第一步需要训练人脸分类器,这是一个耗时耗力的过程,需要收集大量的正负样本,并且样本质量的好坏对结果影响巨大,如果样本没有处理好,再优秀的机器学习分类算法都是零. 今年3 ...

  8. AdaBoost中利用Haar特征进行人脸识别算法分析与总结1——Haar特征与积分图

    原地址:http://blog.csdn.net/watkinsong/article/details/7631241 目前因为做人脸识别的一个小项目,用到了AdaBoost的人脸识别算法,因为在网上 ...

  9. 【计算机视觉】Opencv中的Face Detection using Haar Cascades

    [计算机视觉]Opencv中的Face Detection using Haar Cascades 标签(空格分隔): [图像处理] 声明:引用请注明出处http://blog.csdn.net/lg ...

随机推荐

  1. 九度oj 题目1411:转圈

    题目描述: 在一个有向图有n个顶点(编号从1到n),给一个起点s,问从起点出发,至少经过一条边,回到起点的最短距离. 输入: 输入包括多组,每组输入第一行包括三个整数n,m,s(1<=n< ...

  2. 【转】hibernate映射(单向双向的一对多、多对一以及一对一、多对一)

    多对一关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是多指向一 一对多关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是一指向多 也就是说一对多和多对一的映射策略是一样的,只是站 ...

  3. 简单实用jstl实现代码编写

    package com.ceshi; import java.io.IOException; import javax.servlet.jsp.JspException; import javax.s ...

  4. Codeforces 899B Months and Years

    题目大意 给定 $n$($1\le n\le 24$)个正整数 $a_1,\dots, a_n$ 判断 $a_1$ 到 $a_n$ 是否可能为连续 $n$ 个月份的天数. 解法 由于 $n\le 24 ...

  5. Educational Codeforces Round 10——B. z-sort

    B. z-sort time limit per test 1 second memory limit per test 256 megabytes input standard input outp ...

  6. BZOJ4316 小C的独立集 【仙人掌】

    题目 图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨. 这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多. ...

  7. 刷题总结——寻宝游戏(bzoj3991 dfs序)

    题目: Description 小B最近正在玩一个寻宝游戏,这个游戏的地图中有N个村庄和N-1条道路,并且任何两个村庄之间有且仅有一条路径可达.游戏开始时,玩家可以任意选择一个村庄,瞬间转移到这个村庄 ...

  8. Java面试题之多线程同步和互斥有几种实现方法,都是什么?

    线程同步是指线程之间所具有的一种制约关系,一个线程的执行依赖另外一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒. 线程互斥是指对于共享的进程系统资源,每个线程访问时的排他 ...

  9. from __future__ import unicode_literals, absolute_import

    Q:python模块中的相对导入,绝对导入,有些地方会写 from __future__ import absolute_import 希望有个更详细的讲解. A: 相对导入:在不指明 package ...

  10. 【bzoj4596】[Shoi2016]黑暗前的幻想乡 (矩阵树定理+容斥)

    Description 四年一度的幻想乡大选开始了,最近幻想乡最大的问题是很多来历不明的妖怪涌入了幻想乡,扰乱了幻想乡昔日的秩序.但是幻想乡的建制派妖怪(人类)博丽灵梦和八云紫等人整日高谈所有妖怪平等 ...