基于DSP的人脸检测

基于DSP的人脸检测


一、目标

利用VisualDSP++ 5.0、仿真器、EBF-561实验平台实现该算法,了解人脸检测常用方法,掌握模板匹配算法实现人脸检测的基本原理,并在 DSP 实验板上实现一般环境图像中单个正面人脸的检测,并在实验板的 LCD 显示屏进行显示。

二、实现方案

实验原理

本实验所探讨的是一般环境图像中单个正面端正人脸的检测问题。这种条件下的人脸检测的方法主要有模板匹配方法、可变形模板方法等。概括的说,基于模板匹配的方法是在图形灰度上直接比较目标模板和候选图像区域之间的相似性,而基于特征匹配的方法是比较从图像中抽取的一定特征的相似性。

本实验主要用到两种模板:双眼模板和不同长宽比的模板。在检测时首先使用双眼模板进行粗筛选,然后使用不同长宽比的人脸模板确定出区域的位置和范围,接着通过确定出来的位置和匹配模板的相似度程度来确定是否是人脸。

模板生成,我们在人脸检测中使用了6个模板:一个用于初筛选的双眼模板,五个用于检测不同长宽比的人脸模板。采用多个人脸模板是为了适应不同人脸部的不同长宽比。模板是通过对多个样本平均构造出来的。首先在选取的样本图像上用手工画出人脸的区域作为人脸样本。由于各个样本的尺度大小和灰度分布不同,因此首先对他们进行尺度和灰度标准化,然后将所用样本取灰度平均值并压缩到需要的尺度作为原始模板。拷贝原始模板的眼睛部分,进行灰度分布标准化后作为双眼模板,对原始模板分别按照1:0.9、1:1、1:1.、1:2、1:1.3的宽长比变形,进行灰度分布标准化后作为人脸模板。

在模板生成中最主要的工作是图像的尺度变换和灰度分布标准化,尺度变换主要是基于线性插值的重采样方法。将图像看成一个二维矩阵 D[W][H],其中 W 和 H 分别表示图像的宽和高。

(1)图像的灰度值

1

(2)灰度分布的方差

2

(3)灰度均衡化

对于输入的每个样本图像,为了将其灰度平均值和方差变换到事先设定的灰度平均值和方差,从而将样本中每个像素点的灰度值进行如下变换:

3

假设人脸模板的灰度矩阵为 T[M][N],输入图像区域的灰度矩阵为 R[M][N],灰度均值,那么他们之间的相关系数 r(T,R)和对应像素灰度值的平均偏差d(T,R)分别为:

4

r(T,R)越大表示模板与输入图像区域的匹配程度越高;而d(T,R)正相反。将他们综合起来作为匹配程度的度量:

5

其中权重系数我们取经验值35.0。

实验步骤

(1)初始化最大匹配度,设当前图像
(2)设当前扫描点(x,y)为图像起始点(0,0)
(3)检测扫描区域是否为双眼区,(即计算区域灰度均方值是否大于20)若不是则转(6)
(4)检测相应区域是否为人脸(即计算R与模板T的相关系数是否大于0.3),是则求出当前区域与人脸的匹配度D,否则转(6)
(5)若 D>Dmax,记录当前区域的位置和大小,并令 Dmax=D
(6)若 x+24<W,x=x+1,转(3)
(7)若 y+31<H,x=0,y=y+1 转(3)

三、核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
/*********计算相关系数********/
double funcR(unsigned char test[],unsigned char tem[],int len,int pts,double meanr,double meant,double varr,double vart)
{
int i=0;double r=0;
pts=pts+16;
for (i=0;i<len;i++)
{
r=r+pow((tem[i]-meant)*(test[i+pts]-meanr),2);
}
r=r/len/varr/vart;
return r;
}

/**********计算匹配程度********/
double funcD(unsigned char test[],unsigned char tem[],int len,int pts,double meanr,double meant,double varr,double vart)
{
int i=0;double a=35;double r=0;double d=0;double D=0;
pts=pts+16;
for (i=0;i<len;i++)
{
r=r+pow((tem[i]-meant)*(test[i+pts]-meanr),2);
d=d+(tem[i]-test[i+pts])*(tem[i]-test[i+pts]);
}
r=r/len/varr/vart;
d=d/len;
D=r+a/(1+d);
return D;
}

/***************需要添加内容***************/
/*******计算均值和方差***********/
double meanc=0;double varc=0;
for (i=0;i<68*40;i++)
{
meanc=meanc+image_c[i];
}
meanc=meanc/68/40;
for (i=0;i<68*40;i++)
{
varc=varc+pow(image_c[i]-meanc,2);
}
varc=varc/68/40;

double meand=0;double vard=0;
for (i=0;i<69*37;i++)
{
meand=meand+image_d[i];
}
meand=meand/69/37;
for (i=0;i<69*37;i++)
{
vard=vard+pow(image_d[i]-meand,2);
}
vard=vard/69/37;

double meane=0;double vare=0;
for (i=0;i<68*38;i++)
{
meane=meane+image_e[i];
}
meane=meane/68/38;
for (i=0;i<68*38;i++)
{
vare=vare+pow(image_e[i]-meane,2);
}
vare=vare/68/38;

double meaneye=0;double vareye=0;
for (i=0;i<68*18;i++)
{
meaneye=meaneye+image_eye[i];
}
for (i=0;i<68*18;i++)
{
meaneye=meaneye+image_eye[i];
}
meaneye=meaneye/68/18;

double meand=0;double vard=0;
for (i=0;i<100*100;i++)
{
meand=meand+image[i];
}
meand=meand/100/100;
for (i=0;i<100*100;i++)
{
elt_r=vard+pow(image[i]-meand,2);
}
vard=vard/100/100;

/***********灰度值均衡化************/
double sumc=0,sume=0,sumeyes=0,sumdet=0;
double meanc=0,meane=0,meaneyes=0,u0=110,meandet=0;
double sc=0,se=0,seyes=0,s0=60,sdet=0;
for(i=0;i<68*40;i++)
{
sumc=sumc+image_c[i];
}
meanc=sumc/(68*40);
for(i=0;i<68*38;i++)
{
sume=sume+image_e[i];
}
meane=sume/(68*38);

for(i=0;i<68*18;i++)
{
sumeyes=sumeyes+image_eyes[i];
}
meaneyes=sumeyes/(68*18);
for(i=0;i<68*40;i++)
{
sc=sc+(image_c[i]-meanc)*(image_c[i]-meanc);
}
sc=sqrt(sc/(68*40));
for(i=0;i<68*38;i++)
{
se=se+(image_e[i]-meane)*(image_e[i]-meane);
}
se=sqrt(se/(68*38));
for(i=0;i<68*18;i++)
{
seyes=seyes+(image_eyes[i]-meaneyes)*(image_eyes[i]-meaneyes);
}
seyes=sqrt(seyes/(68*18));
for(i=0;i<68*40;i++)
{
image_c[i]=(s0/sc)*(image_c[i]-meanc)+u0;
}
for(i=0;i<68*38;i++)
{
image_e[i]=(s0/se)*(image_e[i]-meane)+u0;
}

for(i=0;i<68*18;i++)
{
image_eyes[i]=(s0/seyes)*(image_eyes[i]-meaneyes)+u0;
}

for(i=0;i<100*100;i++)
{
sumdet=sumdet+image[i];
}
meandet=sumdet/(100*100);

for(i=0;i<100*100;i++)
{
sdet=sdet+pow(image[i]-meandet,2);
}
sdet=sqrt(sdet/(100*100));

/**************人眼检测****************
/**************人眼检测*******************/
double Dmax=0,r=0;
int k=0,ms=0,t=0,x=0,y=0;
int local[3][2];
double D[3];
D[0]=-100,D[1]=-100,D[2]=-100;
double Dmat[6];
for (i=0;i<100;i++)
{
for(j=0;j<100;j++)
{
detect[i][j]=image[k];
k++;
}
}
for(j=0;j<100-18;j++)
{
for(i=0;i<100-68;i++)
{
ms=0;
for(t=0;t<18;t++)
{
for(k=0;k<68;k++)
{
ms=ms+detect[j+t][i+k]*detect[j+t][i+k];
}
}
ms=ms/(68*18);
if(ms>20)
{
x=j;
y=i;
r=funcR(image,meandet,sdet,image_eyes,u0,s0,18,68,x,y);
if(r>0.3)
{
Dmax=funcD(image,meandet,sdet,image_eyes,u0,s0,18,68,x,y);
if (Dmax>D[0])
{
D[2]=D[1];
local[2][0]=local[1][0];
local[2][1]=local[1][1];
D[1]=D[0];
local[1][0]=local[0][0];
local[1][1]=local[0][1];
D[0]=Dmax;
local[0][0]=x;
local[0][1]=y;
}
else if(Dmax>D[1])
{
D[2]=D[1];
local[2][0]=local[1][0];
local[2][1]=local[1][1];
D[1]=Dmax;
local[1][0]=x;
local[1][1]=y;
}
else if(Dmax>D[2])
{
D[2]=Dmax;
local[2][0]=x;
local[2][1]=y;
}
}
}
}
}


/***************人脸匹配******************/

Dmat[0]=funcD(image,meandet,sdet,image_c,u0,s0,40,68,local[0][0],local[0][1]);
Dmat[1]=funcD(image,meandet,sdet,image_c,u0,s0,40,68,local[1][0],local[1][1]);
Dmat[2]=funcD(image,meandet,sdet,image_c,u0,s0,40,68,local[2][0],local[2][1]);

Dmat[3]=funcD(image,meandet,sdet,image_e,u0,s0,38,68,local[0][0],local[0][1]);
Dmat[4]=funcD(image,meandet,sdet,image_e,u0,s0,38,68,local[1][0],local[1][1]);
Dmat[5]=funcD(image,meandet,sdet,image_e,u0,s0,38,68,local[2][0],local[2][1]);

int temp=Dmat[0],l,p;
for(i=0;i<6;i++)
{
if(temp<Dmat[i])
temp=Dmat[i];
l=i/3;
p=i%3;
}
x=local[p][0];
y=local[p][1];
int x_end=0,y_end=0;

/***************画出人脸大致范围****************/
if(l=0)
{
x_end=y+68;
y_end=x+40;
}
if(l=1)
{
x_end=y+68;
y_end=x+38;
}
for(i=y;i<x_end;i++)
{
image[i+x*Kuan]=0;
image[i+y_end*Kuan]=0;
}
for(j=x;j<y_end;j++)
{
image[y+j*Chang]=0;
image[x_end+j*Chang]=0;
}