图像特征之:haarlike
###Haar-like特征
最早是由Papageorgiou等应用于人脸表示,Viola和Jones在此基础上,使用3种类型4种形式的特征。Haar特征分为三类:边缘特征、线性特征、中心特征和对角线特征,组合成特征模板。特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白色矩形像素和减去黑色矩形像素和。Haar特征值反映了图像的灰度变化情况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述特定走向(水平、垂直、对角)的结构。

基本haarlike特征如下

###Haar Like特征值的计算-积分图
积分图就是只遍历一次图像就可以求出图像中所有区域像素和的快速算法,大大的提高了图像特征值计算的效率。积分图主要的思想是将图像从起点开始到各个点所形成的矩形区域像素之和作为一个数组的元素保存在内存中,当要计算某个区域的像素和时可以直接索引数组的元素,不用重新计算这个区域的像素和,从而加快了计算(这有个相应的称呼,叫做动态规划算法)。积分图能够在多种尺度下,使用相同的时间(常数时间)来计算不同的特征,因此大大提高了检测速度。
void IntegralImage(uchar *timag, double *cumsum, int width, int height)
{
cumsum[0] = timag[0];
for (int i = 1; i < width; i++)
{
cumsum[i] = cumsum[i - 1] + timag[i] / 255.0;
cumsum[i * width] = cumsum[(i - 1) * width] + timag[i * width] / 255.0;
}
for (int i = 1; i < width; i++)
{
double colsum = timag[i];
for (int j = 1; j < height; j++)
{
colsum += timag[j * width + i];
cumsum[j* width + i] = cumsum[j * width + i - 1] + colsum;
}
}
}
以下代码为编译的matlab mex源代码,你可以看到代码复杂度是比较高的,O(N^5),相对matlab而言,C语言循环效率还是很高的,同样的代码我在做测试的时候,对于20*20的图片,matlab执行大约是0.3s,而C执行时间大约为1.5ms,提升了将近200X。
#include <mex.h>
#include <string.h>
#include <math.h>
#include <assert.h>
typedef unsigned char uchar;
void Haarlike(uchar *imag, int width, int height, double *vectorT)
{
assert(width == height);
// matlab 传递为列向量,将其转置
double *timag = new double[width * height];
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
timag[i * width + j] = imag[j * width + i] / 255.0;
}
}
double *cumsum = new double[width * height];
cumsum[0] = timag[0];
for (int i = 1; i < width; i++)
{
cumsum[i] = cumsum[i - 1] + timag[i];
cumsum[i * width] = cumsum[(i - 1) * width] + timag[i * width];
}
for (int i = 1; i < width; i++)
{
double colsum = timag[i];
for (int j = 1; j < height; j++)
{
colsum += timag[j * width + i];
cumsum[j* width + i] = cumsum[j * width + i - 1] + colsum;
}
}
int index = 0;
int st[][2] = {1, 2, 2, 1, 1, 3, 3, 1, 2, 2};
double temp, ij, ij1, ij2, ij3, i1j, i1j1, i1j2, i1j3;
double i2j, i2j1, i2j2, i2j3, i3j, i3j1, i3j2, i3j3;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
for (int k = 0; k < 5; k++)
{
// 不同尺度
int scaleX = floor(width / double(st[k][0]));
int scaleY = floor(height / double(st[k][1]));
for (int m = 1; m <= scaleY; m++)
{
for (int n = 1; n <= scaleX; n++)
{
if (m * st[k][1] + i - 1 < height && n * st[k][0] + j - 1 < width)
{
switch(k)
{
case 0:
ij = cumsum[i * width + j];
ij1 = cumsum[i * width + j + n * st[k][0] - 1];
i1j = cumsum[(i + m * st[k][1] / 2 - 1) * width + j];
i1j1 = cumsum[(i + m * st[k][1] / 2 - 1) * width + j + n * st[k][0] - 1];
i2j = cumsum[(i + m * st[k][1] - 1) * width + j];
i2j1 = cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] - 1];
temp = i1j1 + ij - i1j - ij1 - i2j1 - i1j + i2j + i1j1;
break;
case 1:
ij = cumsum[i * width + j];
ij1 = cumsum[i * width + j + n * st[k][0] / 2 - 1];
ij2 = cumsum[i * width + j + n * st[k][0] - 1];
i1j = cumsum[(i + m * st[k][1] - 1) * width + j];
i1j1 = cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] / 2 - 1];
i1j2 =cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] - 1];
temp = i1j1 + ij - i1j - ij1 - i1j2 - ij1 + i1j1 + ij2;
break;
case 2:
ij = cumsum[i * width + j];
ij1 = cumsum[i * width + j + n * st[k][0] - 1];
i1j = cumsum[(i + m * st[k][1] / 3 - 1) * width + j];
i1j1 = cumsum[(i + m * st[k][1] / 3 - 1) * width + j + n * st[k][0] - 1];
i2j = cumsum[(i + m * st[k][1] * 2 / 3 - 1) * width + j];
i2j1 = cumsum[(i + m * st[k][1] * 2 / 3 - 1) * width + j + n * st[k][0] - 1];
i3j = cumsum[(i + m * st[k][1] - 1) * width + j];
i3j1 = cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] - 1];
temp = i1j1 + ij - i1j - ij1 + i3j1 + i2j -i3j - i2j1 -2 * (i2j1 + i1j - i2j - i1j1);
break;
case 3:
ij = cumsum[i * width + j];
ij1 = cumsum[i * width + j + n * st[k][0] / 3 - 1];
ij2 = cumsum[i * width + j + n * st[k][0] * 2 / 3 - 1];
ij3 = cumsum[i * width + j + n * st[k][0]- 1];
i1j = cumsum[(i + m * st[k][1] - 1) * width + j];
i1j1 = cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] / 3 - 1];
i1j2 = cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] * 2 / 3 - 1];
i1j3 = cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] - 1];
temp = ij + i1j1 - i1j - ij1 + i1j3 + ij2 - i1j2 - ij3 - 2 * (i1j2 + ij1 - i1j1 -ij2);
break;
case 4:
ij = cumsum[i * width + j];
ij1 = cumsum[i * width + j + n * st[k][0] / 2 - 1];
ij2 = cumsum[i * width + j + n * st[k][0] - 1];
i1j = cumsum[(i + m * st[k][1] / 2 - 1) * width + j];
i1j1 = cumsum[(i + m * st[k][1] / 2 - 1) * width + j + n * st[k][0] / 2 - 1];
i1j2 = cumsum[(i + m * st[k][1] / 2 - 1) * width + j + n * st[k][0] - 1];
i2j = cumsum[(i + m * st[k][1] - 1) * width + j];
i2j1 = cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] / 2 - 1];
i2j2 = cumsum[(i + m * st[k][1] - 1) * width + j + n * st[k][0] - 1];
temp = ij + i1j1 - i1j - ij1 + i2j2 + i1j1 - i2j1 -i1j2 - (i2j1 + i1j - i2j - i1j1 + i1j2 - ij1 -
i1j1 - ij2);
break;
}
vectorT[index] = temp;
index++;
}
}
}
}
}
}
delete[] cumsum;
delete[] timag;
}
void mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
uchar *imag;
imag = (uchar *)mxGetPr(prhs[0]);
int row = mxGetM(prhs[0]);
int col = mxGetN(prhs[0]);
int len = 78640;
double *vectorT;
plhs[0] = mxCreateDoubleMatrix(len, 1, mxREAL);
vectorT = mxGetPr(plhs[0]);
Haarlike(imag, col, row, vectorT);
}
此文章版权归snailgoers所有,如有转载,请注明來自原作者
评论

