Matlab PCA+SVM人脸识别(一)
概述:
编程平台:Matlab;
数据库:ORL人脸数据库。黑白灰度图像(即pmg格式),共包含40个不同的人脸样本(共10张照片/每人的不同角度)。在采集过程中进行了预处理工作,在此阶段无需对图像进行归一化处理或校准操作。第三段列出了两个下载链接。
针对数据预处理问题采用主成分分析法(PCA);如需深入理解算法原理,请参考该链接
分类器: 支持向量机(SVM)。
人脸识别算法步骤概述:
1、读取训练数据集;
2、主成分分析法降维并去除数据之间的相关性;
- 数据规格化:通过消除数据单位因素对分类产生的作用(除在本次实验中所造成的影响外)。
4、SVM训练(选取径向基和函数);
5、读取测试数据、降维、规格化;
通过生成由步骤4产生的分类函数来完成分类任务。(针对多元分类问题,并采用基于一对一投票机制的方法来确定最终结果。)
7、计算正确率。
准备工作:
下载人脸库
如果你用的不是ORL人脸库,可能还需要先进行人脸检测
请将Matlab的当前目录(working directory)设定为指定文件夹位置,并在调用时使用addpath('...... ')来添加该目录。
编程实现:
读取数据:
在ReadFace.m文件中,在 flag设为0的情况下,默认会从原始图像文件中提取前五个图像用于训练模型;而在 flag设为1的情况下,则会从原始图像文件中提取后五个图像用于模型测试工作。这些图像会被系统性地加载到f_matrix变量中进行后续处理,并且每个样本对应的特征向量维度为112\times92
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
SVM分类器的径向基核函数:kfun_rbf.m
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,[])
下面分别是主成分为20维、50维、100维、150维时重构出来的第一张照片




原图为:

可见150维已经可以很好地对原图片进行重构。
注释:PGM格式的图像通常属于Linux系统的文件格式,在Windows环境下直接打开这些文件可能会遇到困难。因此,在Windows系统中无法直接打开PGM文件。在这里,我使用Matlab中的imread和imshow函数来处理文件路径。
请告知您是否尊重作者劳动成果,并完整保留原文出处信息及链接以确保权益,请感谢您的理解与配合!
