最近要给同学在一个自动瞄准装置的基础上做一个人脸识别模块。也是上网查阅了一些资料,经过一周的整理整合,也算是有一些收获。
首先,通过阅读网上的一些现有的程序,可以发现,人脸识别大致可以分为两种方法:
第一种是仅能够识别图片中的“人脸”,也就是说,只能识别出这张图片中有一张人脸,但是不能够识别出这张人脸是谁。这是一种比较简单的识别方式。其具有的优点是:算法简单,执行速度较快。缺点自不必说,不能识别这个人是谁,再快有什么用?但我个人认为这种方式还是有一定的用处的。如用在一些基础设备的智能化提升上,就像是在消防车上加装人脸识别模式,就可以自动搜索救人啦。当然,最关键的用处还不在于此,这种方式可以作为第二种识别方式的基础,可以提升其性能。
第一种方式的理论基础大概就是利用图片中的“肤色”进行识别,相比其他几种类似的识别方法,这段代码的识别准确性还是可以保证的,而且可以对是否识别到“人脸”进行判断,非常好用。当然,大家也可以加入“眼睛”,“鼻子”等定位来提升算法的性能。
function Rer=Re()
%Rer=0;%%%0为初始值,若成功识别,则会变为1,2,3,4
I=imread('recg.jpg');%%被识别图片存储路径,要用绝对路径!!
%%%%%%%%%%%%%%%%%算法封装,可以看作一个黑盒子%%%%%%%%%%%%%%%%
O=rgb2ntsc(I);
G=O(:,:,2);
[m n]=size(G);
U=zeros(m,n);
for i=1:m
for j=1:n
if G(i,j)>0.03&&G(i,j)<0.16
U(i,j)=1;
end
end
end
Rer=1;
sr=strel('disk',6);%%创建圆盘半径(创建结构元素)
C=imclose(U,sr);
L=bwlabel(C);
B=regionprops(L,'area');
Se=[B.Area];
Sm=max(Se);
if Sm>m*n/27 %%%%%每个程序都会经过这个,在96行结束,未能识别人脸
B1=bwareaopen(C,Sm);
k_y1=m;k2=m;l2=n;
for i=1:m
if any(B1(i,:))==1
k_y1=i;
break
end
end
for i=k_y1:m
if B1(i,:)==0
k2=i;
break
end
end
for j=1:n
if any(B1(:,j))==1
l_y1=j;
break
end
end
for j=l_y1:n
if B1(:,j)==0
l2=j;
break
end
end
k_y=k2-k_y1;
l=l2-l_y1;
if k_y>.5*l&&k_y<3*l %%%%%第二层if,未能识别人脸
I1=imcrop(B1,[l_y1 k_y1 l .4*k_y]);
[n1 m1]=size(I1);
L1=bwlabel(I1);
E=regionprops(L1,'area');
Si=[E.Area];
Sm=max(Si);
if Sm/(n1*m1)>.3
B2=bwareaopen(I1,floor(.5*Sm));
g_y1=m1;
g2=m1;
for j=1:m1
if any(B2(:,j))==1
g_y1=j;
break
end
end
for j=g_y1:m1
if B2(:,j)==0;
g2=j;
break
end
end
g=g2-g_y1;
figure;
imshow(I,'border','tight','InitialMagnification','fit');
hold on
h1=line([l_y1+g_y1,l_y1+g_y1+g],[k_y1,k_y1]);
h2=line([l_y1+g_y1+g,l_y1+g_y1+g],[k_y1,k_y1+1.1*g]);
h3=line([l_y1+g_y1+g,l_y1+g_y1],[k_y1+1.1*g,k_y1+1.1*g]);
h4=line([l_y1+g_y1,l_y1+g_y1],[k_y1+1.1*g,k_y1]);
h=[h1 h2 h3 h4];
set(h,'Color',[1 0 0],'LineWidth',3);
gfframe=getframe(gcf);
gffim=frame2im(gfframe);
imwrite(gffim,'recg_result.jpg','jpg'); %%%%存储图片命名,为了保存画红框的图片
Rer=1;
%fid=fopen('re.txt','w');
%fprintf(fid,'%d',Rer);
%fclose(fid);
else%%%未能满足最近一个if判断,不能识别人脸
figure;
imshow(I);
imwrite(I,'recg_result.jpg','jpg'); %%%%存储图片命名
Rer=2;
%fid=fopen('re.txt','w');
%fprintf(fid,'%d',Rer);
%fclose(fid);
end
else
figure;
imshow(I);
imwrite(I,'recg_result.jpg','jpg'); %%%%存储图片命名
Rer=3;
%fid=fopen('re.txt','w');
%fprintf(fid,'%d',Rer);
%fclose(fid);
end
else
figure;
imshow(I);
imwrite(I,'recg_result.jpg','jpg'); %%%%存储图片命名
Rer=4;
%fid=fopen('re.txt','w');
%fprintf(fid,'%d',Rer);
%fclose(fid);
end
end
第二种识别方法是能够识别图中的“人脸”是谁。当然,这种识别方式可以以第一种识别方式作为基础,第一步判断图中是否存在人脸,第二步再判断图中的人脸是谁。这样做可以提升算法的执行效率,节约不必要的浪费。当然,这种方法的缺点就是计算量较大,运行速度有所降低。
采用这种识别方法的前提是构建“人脸”数据库,并存放相应的人脸信息。当然,如果数据库中没有这个人的信息,就不能够识别了。在做这部分的实验过程中,我采用了ORL人脸库,包含40个人每人10张人脸照片的信息,效果还是比较好,准确率能够达到80%以上。(ORL资料在后面的附件中)
function FaceRecognition
clear % calc xmean,sigma and its eigen decomposition
close all
allsamples=[];%所有训练图像
for i=1:5
for j=1:5
if(i<10)
a=imread(strcat('E:\ORL\00',num2str(i),'0',num2str(j),'.pgm'));
else
a=imread(strcat('E:\ORL\00',num2str(i),'0',num2str(j),'.pgm'));
end
b=a(1:112*92); % b是行矢量 1×N,其中N=10304,提取顺序是先列后行,即从上到下,从左到右
b=double(b);
allsamples=[allsamples; b]; % allsamples 是一个M * N 矩阵,allsamples 中每一行数据代表一张图片,其中M=200
end
end
samplemean = mean(allsamples); % 平均图片,1 × N
figure%平均图
imshow(mat2gray(reshape(samplemean,112,92)));
for i=1:25
xmean(i,:)=allsamples(i,:)-samplemean; % xmean是一个M × N矩阵,xmean每一行保存的数据是“每个图片数据-平均图片”
end;
% figure%平均图
% imshow(mat2gray(reshape(xmean(1,:),112,92)));
sigma=xmean*xmean'; % M * M 阶矩阵
[v,d]=eig(sigma);
d1=diag(d);
[d2,index]=sort(d1); %以升序排序
cols=size(v,2);% 特征向量矩阵的列数
for i=1:cols
vsort(:,i) = v(:, index(cols-i+1) ); % vsort 是一个M*col(注:col一般等于M)阶矩阵,保存的是按降序排列的特征向量,每一列构成一个特征向量
dsort(i) = d1( index(cols-i+1) ); % dsort 保存的是按降序排列的特征值,是一维行向量
end %完成降序排列 %以下选择90%的能量
dsum = sum(dsort);
dsum_extract = 0;
p = 0;
while( dsum_extract/dsum < 0.9)
p = p + 1;
dsum_extract = sum(dsort(1:p));
end
a=1:1:25;
for i=1:1:25
y(i)=sum(dsort(a(1:i)) );
end
figure
y1=ones(1,25);
plot(a,y/dsum,a,y1*0.9,'linewidth',2);
grid
title('前n个特征特占总的能量百分比');
xlabel('前n个特征值');
ylabel('占百分比');
figure
plot(a,dsort/dsum,'linewidth',2);
grid
title('第n个特征特占总的能量百分比');
xlabel('第n个特征值');
ylabel('占百分比');
i=1; % (训练阶段)计算特征脸形成的坐标系
while (i<=p && dsort(i)>0)
base(:,i) = dsort(i)^(-1/2) * xmean' * vsort(:,i); % base是N×p阶矩阵,除以dsort(i)^(1/2)是对人脸图像的标准化,特征脸
i = i + 1;
end % add by wolfsky 就是下面两行代码,将训练样本对坐标系上进行投影,得到一个 M*p 阶矩阵allcoor
%
% for i=1:20
% figure%平均图
% b=reshape(base(:,i)',112,92);%
% imshow(mat2gray(b));
% end
allcoor = allsamples * base; accu = 0; % 测试过程
for i=1:5
for j=6:10 %读入5 x 5 副测试图像
if(i<10)
if(j<10)
a=imread(strcat('E:\ORL\00',num2str(i),'0',num2str(j),'.pgm'));
else
a=imread(strcat('E:\ORL\00',num2str(i),num2str(j),'.pgm'));
end
else
if(j<10)
a=imread(strcat('E:\ORL\0',num2str(i),'0',num2str(j),'.pgm'));
else
a=imread(strcat('E:\ORL\0',num2str(i),num2str(j),'.pgm'));
end
end
b=a(1:10304);
b=double(b);
tcoor= b * base; %计算坐标,是1×p阶矩阵
for k=1:25
mdist(k)=norm(tcoor-allcoor(k,:));
end; %三阶近邻
[dist,index2]=sort(mdist);
class1=floor( index2(1)/5 )+1;
class2=floor(index2(2)/5)+1;
class3=floor(index2(3)/5)+1;
if class1~=class2 && class2~=class3
class=class1;
elseif class1==class2
class=class1;
elseif class2==class3
class=class2;
end;
if class==i
accu=accu+1;
end;
end;
end;
accuracy=accu/25 %输出识别率
一些在处理问题的过程中的心得体会,希望能帮到大家。