人脸检测是将人脸从复杂的背景图像中检测出来,它是实现人脸识别的基础和前提。
使用人脸肤色模板对灰度图像进行肤色重建,使其变成彩色图像,效果如下:
在函数function R=gray2rgb1(img1,img2)中,img1代表需要彩色重建的灰度图像,img2代表彩色人脸模板。
function R=gray2rgb1(img1,img2)
% img1 - Source Image (gray image)
% img2 - Selected color image for coloring the gray image.
imt=rgb2gray(im);
% imt=img1;
ims=img2;
[sx sy sz]=size(imt);
[tx ty tz]=size(ims);
if sz~=1
imt=rgb2gray(imt);
end
if tz~=3
disp ('img2 must be a color image (not indexed)');
else
imt(:,:,2)=imt(:,:,1);
imt(:,:,3)=imt(:,:,1);
% Converting to ycbcr color space
nspace1=rgb2ycbcr(ims);
nspace2= rgb2ycbcr(imt);
ms=double(nspace1(:,:,1));
mt=double(nspace2(:,:,1));
m1=max(max(ms));
m2=min(min(ms));
m3=max(max(mt));
m4=min(min(mt));
d1=m1-m2;
d2=m3-m4;
% Normalization
dx1=ms;
dx2=mt;
dx1=(dx1*255)/(255-d1);
dx2=(dx2*255)/(255-d2);
[mx,my,mz]=size(dx2);
%Luminance Comparison
disp('Please wait..................');
for i=1:mx
for j=1:my
iy=dx2(i,j);
tmp=abs(dx1-iy);
ck=min(min(tmp));
[r,c] = find(tmp==ck);
ck=isempty(r);
if (ck~=1)
nimage(i,j,2)=nspace1(r(1),c(1),2);
nimage(i,j,3)=nspace1(r(1),c(1),3);
nimage(i,j,1)=nspace2(i,j,1);
end
end
end
rslt=ycbcr2rgb(nimage);
figure,imshow(uint8(imt));
figure,imshow(uint8(rslt));
R=uint8(rslt);
toc
end
由于图像在取像时,人脸很容易受到周围环境中的关照影响,包括光源的方向,明暗等,这可能造成人脸区域的一些有效信息的丢失,从而导致人脸漏检和错检现象。为了解决人脸因为光照造成人脸检测率降低的问题,因此有必要对输入的图像光照补偿处理,下面使用非线性光照补偿。代码如下:
function [Dst]=nolinetransaction(Scr)
img_ycbcr=rgb2ycbcr(Scr);
img_y=img_ycbcr(:,:,1);
Dim=size(img_y);
Num=Dim(1)*Dim(2);
Pixsum=0.05*Num;
sum=0;
Sum=0;
[count,level]=imhist(img_y);
for i=1:256
sum=sum+count(i);
if sum>Pixsum
B=i-1;
break;
end
end
for i=256:-1:1
Sum=Sum+count(i);
if Sum>Pixsum
E=i+1;
break;
end
end
for i=1:Dim(1)
for j=1:Dim(2)
if img_y(i,j)<B
img_y(i,j)=0;
elseif img_y(i,j)>=B && img_y(i,j)<=E
img_y(i,j)=255*(log(double(img_y(i,j))-log(B)))/(log(E)-log(B));
else
img_y(i,j)=255;
end
end
end
Dst=ycbcr2rgb(img_ycbcr);
根据人脸肤色在YCbCr空间上类似呈现高斯分布,因此可以根据这一特征,将一幅图像中的人脸和背景分开,实现二值化,高斯人脸检测代码如下:
function p=gaosi(x1)
I=rgb2ycbcr(x1); %颜色空间转换
% I=T_YCbCr(I);
% figure;
% imshow(I);
[a,b,c]=size(I); %得到图像的像素点个数
cb=double(I(:,:,2));
cr=double(I(:,:,3));
for i=1:a
for j=1:b
w=[cb(i,j),cr(i,j)];
m=[117.4316 148.5599];
n=[260.1301 12.1430;12.1430 150.4574];
p(i,j)=exp((-0.5)*(w-m)*inv(n)*(w-m)');%算某象素点的概率
if (p(i,j)<0.5)
p(i,j)=0;
else
p(i,j)=1;
end
end
end
通过对高斯人脸检测得到的二值图像进行形态学操作进一步确定人脸的位置并使用矩形框进行标记,在函数function []=kuang(p,x1)中,p代表二值图像,x1代表二值图像对应的RGB图像,具体代码如下:
function []=kuang(p,x1)
% SE = strel('disk',5);
% imf=imopen(p,SE); %开运算(即先腐蚀再膨胀),消除杂散点
% imf=medfilt2(imf,[3,3]);%中值滤波
se=strel('disk',3);
se1=strel('disk',1);
imf=imerode(p,se);
imf=imdilate(imf,se1);
[w,h]=size(imf);
imf=bwareaopen(imf,round(w*h/900));
% imf=bwareaopen(imf,1000);%开运算,去除像素点少于1000的区域
figure;
imshow(imf);
[L,num]=bwlabel(imf,4); %连通区域标记
B=zeros(size(imf));
for i=1:num
Area(i)=bwarea(L==i);%计算每个皮肤区域的面积
end
for i=1:num
[r,c] = find(L==i) ;
left(i)=min(c);
right(i)=max(c);
up(i)=min(r);
down(i)=max(r);
end
for i=1:num
%计算各矩形区域面积
Rect_Area(i)=(down(i)-up(i))*(right(i)-left(i));
end
%计算各区域的填充率
Ratio=Area./Rect_Area;
for i=1:num
if Ratio(i)>=0.5%若相应区域的填充率大于0.5则保留该区域
[x,y]=find(L==i);%第i块区域的坐标值
B=B+bwselect(imf,y,x,4);%把填充率大于0.5皮肤区域叠加起来
end
end
% B=bwareaopen(B,1000);%开运算,去除像素点少于1000的区域
figure;
imshow(B);
%%%%%%%%%%%%%%%%%%%%%%%%%%根据面积比来进一步除去一些较小的非人脸区域%%%%%%%%%%%%%%%%%%%%%%%%%%
[L1,num1]=bwlabel(B,4); %连通区域标记
B1=zeros(size(B));
for i=1:num1
Area(i)=bwarea(L1==i);%计算每个皮肤区域的面积
end
maxarea=max(Area);%取最大值
q=Area/maxarea;%每块区域的面积与最大区域面积的比值
for i=1:num1
if q(i)>=0.3%若相应区域的面积比值大于0.3则保留该区域
[x,y]=find(L1==i);%第i块区域的坐标值
B1=B1+bwselect(B,y,x,4);%把面积比值大于0.3皮肤区域叠加起来
end
end
figure;
imshow(B1);
%%%%%%%%%%%%%%%%%%%%%%%%%%根据肤色区域的长宽比来除去一些非人脸区域%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[L2,num2]=bwlabel(B1,4); %连通区域标记
B2=zeros(size(B1));
for i=1:num2
[r,c] = find(L2==i);
left(i)=min(c);
right(i)=max(c);
up(i)=min(r);
down(i)=max(r);
end
for i=1:num2
if ((down(i)-up(i))/(right(i)-left(i)))>0.8&&((down(i)-up(i))/(right(i)-left(i)))<2
[x,y]=find(L2==i);
B2=B2+bwselect(B1,y,x,4);%%%把满足长宽比在0.8到2的区域留下
end
end
figure,
imshow(B2);
figure,
imshow(x1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%把人脸框出来%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[L3 num3]=bwlabel(B2,8); %连通区域标记
for i=1:num3
[r,c] = find(L3==i);
left(i)=min(c);
right(i)=max(c);
up(i)=min(r);
down(i)=max(r);
end
hold on;
for i=1:num3
if(down(i)>(up(i)+(right(i)-left(i))*1.2)) %人脸长宽比限制1.2
down(i)=up(i)+(right(i)-left(i))*1.2;
end
x=[left(i);left(i);right(i);right(i);left(i)];
y=[up(i);down(i);down(i);up(i);up(i)];
plot(x,y,'g','LineWidth',2); %画框
% drawnow;
end
hold off;
clc
close all
I1=imread("需要检测的灰度图像地址");
I2=imread("人脸彩色图像模板地址");
R=gray2rgb1(I1,I2);%肤色重建
DST=nolinetransaction(Scr);%光照补偿
p=gaosi(DST);%高斯人脸检测二值化
kuang(p,R);%将图像中所有人脸使用矩形框进行标记,并显示