声明:本文转载自http://blog.csdn.net/light_lj/article/details/26703959
概述:
编程平台:Matlab;
数据: ORL人脸库。pgm格式的图片。40人,每人10幅图,图像大小为112*92像素。 图像本身已经经过处理,不需要进行归一化和校准等工作;下载地址第三段的两个都是下载链接数据处理:主成分分析法(PCA);有关算法原理可以参考这里
分类器: 支持向量机(SVM)。
人脸识别算法步骤概述:
1、读取训练数据集;
2、主成分分析法降维并去除数据之间的相关性;
3、数据规格化(去除数据单位因素对分类造成的影响,这个对此实验造成的影响不大);
4、SVM训练(选取径向基和函数);
5、读取测试数据、降维、规格化;
6、用步骤4产生的分类函数进行分类(多分类问题,采用一对一投票策略,归位得票最多的一类);
7、计算正确率。
准备工作:
下载人脸库
如果你用的不是ORL人脸库,可能还需要先进行人脸检测
把Matlab的左上角当前路径(current folder)设置为你的.m的保存的路径,或者用addpath('...... ')设置
编程实现:
读取数据:
ReadFace.m文件,若flag=0,表述读取原文件的前五幅图作为训练数据,若flag=1,表述读取原文件的后五幅图作为测试数据,数据存入f_matrix中,每一行为一个文件,每行为112*92列。
- function [f_matrix,realclass] = ReadFace(npersons,flag)
- %读取ORL人脸库照片里的数据到矩阵
- %输入:
- % nPersons-需要读入的人数,每个人的前五幅图为训练样本,后五幅为验证样本
- % imgrow-图像的行像素为全局变量
- % imgcol-图像的列像素为全局变量
- % flag-标志,为0表示读入训练样本,为1表示读入测试样本
- %输出:
- %已知全局变量:imgrow=112; imgcol=92;
- global imgrow;
- global imgcol;
- realclass=zeros(npersons*5,1);
- f_matrix=zeros(npersons*5,imgrow*imgcol);
- for i=1:npersons
- facepath='E:\ORL_face\s';
- facepath=strcat(facepath,num2str(i));
- facepath=strcat(facepath,'\');
- cachepath=facepath;
- for j=1:5
- facepath=cachepath;
- if flag==0 %读入训练样本图像的数据
- facepath=strcat(facepath,'0'+j);
- else %读入测试样本数据
- facepath=strcat(facepath,num2str(5+j));
- realclass((i-1)*5+j)=i;
- end
- facepath=strcat(facepath,'.pgm');
- img=imread(facepath);
- f_matrix((i-1)*5+j,:)=img(:)';
- end
- end
- end
主成分分析:
去除原成分各维之间的相关性并进行降维,对降维后维数的选择要看你对最小平方误差的要求,被舍去的协方差矩阵的特征根的平方和与所有特征根的平方和就是最小平方误差。这里选择降至20维。下面是fastPCA.m
- function [ pcaA,V] = fastPCA( A,k,mA)
- %快速PCA,主成份分析
- %输入:A-样本矩阵,每行是一个样本,列是样本的维数
- % k-降至k维
- %输出:pacA-降维后的k维样本特征向量组成的矩阵,即主成分
- % v-主成分分量
- m=size(A,1);
- Z=(A-repmat(mA,m,1));
- T=Z*Z';
- [V,D]=eigs(T,k);%计算T的最大的k个特征值和特征向量
- V=Z'*V; %协方差矩阵的特征向量
- for i=1:k %特征向量单位化
- l=norm(V(:,i));
- V(:,i)=V(:,i)/l;
- end
- pcaA=Z*V; %线性变换,降至k维
- end
数据规范化:
scaling.m
- function [ scaledface] = scaling( faceMat,lowvec,upvec )
- %特征数据规范化
- %输入——faceMat需要进行规范化的图像数据,
- % lowvec原来的最小值
- % upvec原来的最大值
- upnew=1;
- lownew=-1;
- [m,n]=size(faceMat);
- scaledface=zeros(m,n);
- for i=1:m
- scaledface(i,:)=lownew+(faceMat(i,:)-lowvec)./(upvec-lowvec)*(upnew-lownew);
- end
- end
SVM分类器训练:
multiSVMtrain.m
- function [ multiSVMstruct ] =multiSVMtrain( traindata,nclass,gamma,c)
- %多类别的SVM训练器
- % Detailed explanation goes here
- for i=1:nclass-1
- for j=i+1:nclass
- X=[traindata(5*(i-1)+1:5*i,:);traindata(5*(j-1)+1:5*j,:)];
- Y=[ones(5,1);zeros(5,1)];
- multiSVMstruct{i}{j}=svmtrain(X,Y,'Kernel_Function',@(X,Y) kfun_rbf(X,Y,gamma),'boxconstraint',c);
- end
- end
- end
- function [ K ] = kfun_rbf(u,v,gamma)
- %SVM分类器的RBF核函数
- % Detailed explanation goes here
- m1=size(u,1);
- m2=size(v,1);
- K=zeros(m1,m2);
- for i=1:m1
- for j=1:m2
- K(i,j)=exp(-gamma*norm(u(i,:)-v(j,:))^2);
- end
- end
- end
SVM分类器对测试数据进行分类:
multiSVM.m
- function [ class] = multiSVM(testface,multiSVMstruct,nclass)
- %对测试数据进行分类
- m=size(testface,1);
- voting=zeros(m,nclass);
- for i=1:nclass-1
- for j=i+1:nclass
- class=svmclassify(multiSVMstruct{i}{j},testface);
- voting(:,i)=voting(:,i)+(class==1);
- voting(:,j)=voting(:,j)+(class==0);
- end
- end
- [~,class]=max(voting,[],2);
- end
主函数:
face.m
- clc,clear
- npersons=40;%选取40个人的脸
- global imgrow;
- global imgcol;
- imgrow=112;
- imgcol=92;
- disp('读取训练数据...')
- f_matrix=ReadFace(npersons,0);%读取训练数据
- nfaces=size(f_matrix,1);%样本人脸的数量
- disp('.................................................')
- %低维空间的图像是(nperson*5)*k的矩阵,每行代表一个主成分脸,每个脸20维特征
- disp('训练数据PCA特征提取...')
- mA=mean(f_matrix);
- k=20;%降维至20维
- [pcaface,V]=fastPCA(f_matrix,k,mA);%主成分分析法特征提取
- disp('.................................................')
- disp('显示主成分脸...')
- visualize(V)%显示主分量脸
- disp('.................................................')
- disp('训练特征数据规范化...')
- disp('.................................................')
- lowvec=min(pcaface);
- upvec=max(pcaface);
- scaledface = scaling( pcaface,lowvec,upvec);
- disp('SVM样本训练...')
- disp('.................................................')
- gamma=0.0078;
- c=128;
- multiSVMstruct=multiSVMtrain( scaledface,npersons,gamma,c);
- disp('读取测试数据...')
- disp('.................................................')
- [testface,realclass]=ReadFace(npersons,1);
- disp('测试数据特征降维...')
- disp('.................................................')
- m=size(testface,1);
- for i=1:m
- testface(i,:)=testface(i,:)-mA;
- end
- pcatestface=testface*V;
- disp('测试特征数据规范化...')
- disp('.................................................')
- scaledtestface = scaling( pcatestface,lowvec,upvec);
- disp('SVM样本分类...')
- disp('.................................................')
- class= multiSVM(scaledtestface,multiSVMstruct,npersons);
- accuracy=sum(class==realclass)/length(class);
- display(['正确率:',num2str(accuracy)])
补充:
显示主分量脸:
在主函数的第21行 有一句程序是“visualize(V)%显示主成分脸”,这个是吧20个最大特征之对应的特征向量(就是低维空间的基)以图像的形式显示出来,其他所有图片就是这20张图片(主分量)的线性组合,保存为文件visualize.m
- function visualize( B )
- %显示主成分分量脸(变换空间中的基向量,即单位特征向量)
- %输入:B——每列是个主成分分量
- % k——主成分的维数
- global imgrow;
- global imgcol;
- figure
- img=zeros(imgrow,imgcol);
- for i=1:20
- img(:)=B(:,i);
- subplot(4,5,i);
- imshow(img,[])
- end
- end
下面是调用visualize.m显示的主分量人脸:
基于主分量的人脸重构:
- approx=mA;
- for i=1:k
- approx=approx+pcaface(1,i)*V(:,i)';%pcaface的第一个参数代表你要重建的人脸,这里对第一个人的第一张脸脸进行重建
- end
- disp('人脸重建')
- figure
- B=reshape(approx',112,92);
- imshow(B,[])
原图为:
可见150维已经可以很好地对原图片进行重构。
附:pgm格式的图片好像是Linux的格式,在Windows上无法直接打开,在这里我是用Matlab的指令打开:imshow(imread('文件路径'))。