1.Haar特征
最早的Haar特征由PapageorgiouC.等提出(《A general framework for object detection》),后来PaulViola和Michal Jones提出利用积分图像法快速计算Haar特征的方法(《Rapid object detection using a boosted cascade of simplefeatures》)。之后,Rainer Lienhart 和 Jochen Maydt用对角特征对Haar特征库进行了扩展(《An extended set of Haar-like features for rapid objectdetection》)。OpenCV的Haar分类器就是基于扩展后的特征库(含下图中的1、2、3,共14种)实现的。
1.1 Haar特征定义
Haar特征是基于“块”的特征,也被称为矩形特征。Haar特征(模板)分为三类:边缘特征、线性特征、中心特征和对角线特征。特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白色矩形像素和减去黑色矩形像素和。Haar特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。
对于图中的1.a这类特征,特征数值计算公式为:v=Sum白-Sum黑,而对于2.c这类来说,计算公式如下:v=Sum白-2*Sum黑;之所以将黑色区域像素和乘以2,是为了使两种矩形区域中像素数目一致。
1.2 Haar特征的数量
通过改变特征模板的大小和位置,可在图像子窗口中穷举出大量的特征。上图的特征模板称为“特征原型”;特征原型在图像子窗口中扩展(平移伸缩)得到的特征称为“矩形特征”;矩形特征的值称为“特征值”。
矩形特征可位于图像任意位置,大小也可以任意改变,所以矩形特征值是矩形模版类别、矩形位置和矩形大小这三个因素的函数。故类别、大小和位置的变化,使得很小的检测窗口含有非常多的矩形特征。对于一个给定的24X24的窗口,根据不同的位置,以及不同的缩放,可以产生超过160,000个特征,因此计算一幅图像的所有Haar特征是一件工作量很大的事。
具体的计算Haar特征个数的公式为Rainer Lienhart提出的:
【图像处理】计算Haar特征个数:http://blog.csdn.net/xiaowei_cqu/article/details/8216109
计算Haar特征个数:http://blog.csdn.net/wangli071125/article/details/9083517
1.3 Haar特征的快速计算-积分图
通过一次遍历图像得到“积分图”(Integralimage),也叫Summed Area Table,之后任何一个Haar矩形特征都可以通过查表的方法(Look Up Table)和有限次简单运算得到,大大减少了运算次数。
原图像A经过“积分”后得到相同大小的图像B,B中(x,y)处的值B(x,y)是原图像(x,y)位置左上角方向所有像素的和,即: 举例:
得到图像的积分图后,特征模板的Haar特征值就很好求了。举例如下:
红色矩形为特征模板,矩形中白色区域像素和为B(5)+B(1)-B(2)-B(6),矩形中黑色区域像素和为B(4)+B(2)-B(3)-B(5)。二者作差即可得特征值。
此外,对于对角线矩形特征模板,需要构建旋转积分图像。具体可参考:
利用积分图像法快速计算Haar特征:http://blog.csdn.net/xiaowei_cqu/article/details/8219324
积分图构建采用增量算法:
1)用s(i,j)表示行方向的累加和,初始化s(i,-1)=0;
2)用ii(i,j)表示一个积分图像,初始化ii(-1,i)=0;
3)逐行扫描图像,递归计算每个像素(i,j)行方向的累加和s(i,j)和积分图像ii(i,j)的值
s(i,j)=s(i,j-1)+f(i,j)
ii(i,j)=ii(i-1,j)+s(i,j)
4)扫描图像一遍,当到达图像右下角像素时,积分图像ii就构造好了。
下面给出的代码是MATLAB 调用.C文件来计算积分图(for循环较多,C语言会快很多)
(关于MATLAB调用.C和.CPP文件,可以参考我的博文:MATLAB调用编译.C和.CPP文件)
#include
#include "mex.h"
// compute integral img
// s(i,j) = s(i-1,j)+i(i,j)
// ii(i,j) = ii(i,j-1)+s(i,j)
// s(i,j) = s(i+j*M);
// s(0,j) = i(0,j);ii(i,0)=s(i,0)
/* Input Arguments */
#define img_IN prhs[0]
/* Output Arguments */
#define ii_OUT plhs[0]
/*ii为输出积分图,img为输入原图像,M为行,N为列*/
static void integral(
double ii[],
double *img,
int M,
int N)
{
int i;
int j;
double *s = new double[M*N];
/*列累积*/
for(j=0; j