基于MATLAB,运用PCA+SVM的特征脸方法人脸识别

概述:

此文章将要描述一种基于MATLAB平台,运用PCA主成分分析方法对图片数据进行降维,运用SVM支持向量机分类器对降维后的图片数据进行分类处理,从而达到人脸识别的目的。php


首先要感谢如下几篇文章的做者(后面引用会标识文章标号)html

1.Matlab PCA+SVM人脸识别(一)(A),matlab代码大部分都来自于A篇文章。而且其GUI界面值得借鉴,具体可参考Matlab PCA+SVM人脸识别(二)——GUI界面设计(B).算法


2.人脸识别经典算法一:特征脸方法(Eigenface)(C)特征脸(Eigenface)理论基础-PCA(主成分分析法)(D),C篇对关于特征脸识别方法的步骤进行了详细的讲述,而且在一些关键细节问题中有着讲解,D篇对于PCA降维的原理有深刻的剖析,都是很是不错的文章。编程


3.主成分分析PCA(E)PCA (主成分分析)详解 (写给初学者) 结合matlab(F)E篇列出了具体的数据供你们检验,你们能够根据数据来验证数学过程,简单易懂。F篇与前篇有点类似,对初学者颇有帮助。小程序


4.浅谈协方差矩阵(G)此篇文章对于你们了解协方差矩阵以及matlab实现颇有做用windows


准备:

1.编程平台:MATLAB。机器学习

    首先你得保证你的机器上安装有matlab,建议较高的版本。ide


2.libsvm工具箱。函数

    本人在对第一篇文章中代码关于SVM分类的部分没有运行成功,因此运用了libsvm工具箱对样本训练,测试,并无运用第一篇文章的代码,若是你能成功可忽略,但建议安装此工具箱,其对SVM分类有很大帮助。若是你同样没有成功,这里推荐一个连接,有关于libsvm工具箱的安装配置的视频。工具


3.数据ORL人脸库。

    这个数据为已经预处理的数据,格式为pgm,属于Linux格式,windows环境下没法直接打开,能够在matlab中打开,打开方式imshow(imread('图片路径'));数据是400张人脸图片,属于40我的,每一个人10张,每张大小112*92像素,数据下载地址在第一篇文章中有,这里也给个连接,第四段两个连接均可下载。


4.主成分分析法PCA。

    主成分分析法是一种降维的方法,上面给出了几个有用的连接,本文只给出代码,以及代码说明,关于原理,你们尽可参照上面几个连接,写得很是详细也很是通俗。


5.SVM支持向量机分类器。

    SVM支持向量机是一个二类分类器,可是本次人脸识别不只只是分出两类,而是须要分出40个类别。本人之前有过一点机器学习基础,因此在支持向量机原理的理解上没有多大问题,若是读者没有SVM基础,可参考SVM入门(H),以及写的很是给力的帖子,SVM三层境界(I)


    注:也许不少初学者看到这么多的资料,连接都已经晕了,失去了学习的动力。先别灰心,稍后我会把代码以及代码运行的结果和过程展现给你们,当你们看到这些图像的变换的美妙,就会有学习的兴趣。


编程实现:

     如下将要展现的是几个.m文件的代码,.m文件便是能在matlab上面打开运行的代码文件,能够在其中定义函数,若是matlab的当前路径指定在含有这些.m文件的文件夹中,运行时就能够调用这些文件中定义的函数。


首先展现第一个.m文件,即是图片数据读取函数ReadFace.m

function [f_matrix,realclass]=ReadFace(n_persons,flag)
%ORL人脸库。pgm格式的图片。40人,每人10幅图,图像大小为112*92像素。
%每一个人有10幅照片,前5幅看成训练集,后5幅看成测试集
%
%输入变量flag:
%   flag是一个标识变量
%   当flag为0时,表示输入为训练集,flag为1时,表示输入为测试集
%
%输入变量n_persons:
%   n_persons标志着你想要识别的人脸个数
%
%输出变量realclass:
%   realclass是一个n_person*5行,1列的列向量。
%   realclass便是数据的标签,不管训练集测试集都进行了标签处理
%
%输出变量f_matrix:
%   f_matrix是一个n_person*5行,112*92列的矩阵
%   每一行即是每一张图片的灰度数据
%   将每一张图片列向量排成一个列向量后转置获得放入f_matrix各行当中

imgrow=112;imgcol=92;
global imgrow;   %载入图片行数
global imgcol;    %载入图片列数
realclass=zeros(n_persons*5,1);
f_matrix=zeros(n_persons*5,imgrow*imgcol);
for i=1:n_persons
    %路径设置
    %函数num2str(i)说明:将数字转化为字符
    facepath=strcat('F:\MATLAB人脸识别\Face\facedata\s',num2str(i),'\');  %路径因不一样状况而定
    cachepath=facepath;
    for j=1:5
        facepath=cachepath;
        if flag==0
            %函数strcat(a,b,...)说明:将输入字符a,b...链接成单个字符
            facepath=strcat(facepath,num2str(j));
        else
            facepath=strcat(facepath,num2str(j+5));
        end
        realclass((i-1)*5+j)=i;
        facepath=strcat(facepath,'.pgm');
        %函数imread说明:读取输入路径的图片,将每一个像素灰度值保存在输出的矩阵中
        img=imread(facepath);
        f_matrix((i-1)*5+j,:)=img(:)';
    end
end
end



代码当中有着详细的注释,代码与第一篇文章中提供的代码大同小异,根据本人状况修改了一点路径的代码,以及增长了对训练集标签的标识,且增长了注释。如今对代码进行一些说明。

代码第一行有对函数的申明,function []=ReadFace(),中括号为函数的输出,小括号为函数的输入,函数名与文件名一致,一个.m文件当中能够有多个函数申明,但当外面的函数想要调用这个文件中的函数时,只能调用与文件名一致的函数。因此这个文件叫ReadFace.m

何为训练集以及测试集?

    在机器学习方法当中,分为监督学习,非监督学习,强化学习。而SVM支持向量机是一种监督学习的算法。所谓监督学习,就是给予机器一套题目并附上标准答案,让它去作题,本身总结了一套作题的方法(这些方法就是创建的模型),它在根据已经学习好的方法来作一套新的题目,把题目作对,尽量打高分。

    训练集就是给予机器的一套题目及标准答案,测试集就是给它的一套新题。而训练集有标签和数据之分,标签就是标准答案,标签有着1和0,就表示这些训练集中有两类,像咱们的人脸数据有40种人脸,咱们就用1到40来表示。数据就是有着多维的表征一个事物的数据,就是给机器的第一套题目。测试集也有数据,就是后面给机器测试的题目,若是测试集本来含有标签,这些标签就能够做为标准给机器前面训练总结的方法(模型)打分,查看准确率。

    在这我的脸库中,每一个人有10张图,咱们将前5张做为训练集,就有200张图。用一个矩阵来表示这200张图,就造成了一个200*10304的矩阵。后5张图用来当测试集,能够看代码中的说明。

当flag为0时,找出训练集的标签realclass(200*1的矩阵)与数据f_matrix(200*10304的矩阵).

当flag为1时,就是找出测试集来测试分类效果,得出准确率。

SVM训练的目的就是利用训练集找到这么一个分类函数(模型),再在测试集中检测。关于SVM的具体原理查看上面的H和I篇。


--------------------------------分割线---------------------------------------


第二个.m文件的文件名为fastPCA.m,用于将样本进行降维处理,参考上面主成分分析PCA文章D,E,F篇,上面有通俗且具体的阐述。

function [ pcaA,V] = fastPCA( A,k,mA)  
%快速PCA,主成份分析  
%输入:A-样本矩阵,每行是一个样本,列是样本的维数  
%            k-降至k维  
%           mA-图像矩阵f_matrix每一列的均值排成一个行向量,即mean(f_matrix)
%输出:pacA-降维后,训练样本在低维空间中的系数坐标表示 
%            V-主成分份量,即低维空间当中的基  
%
m=size(A,1);  %m为读取图片的张数
Z=(A-repmat(mA,m,1));  %中心化样本矩阵
%通常用中心化的矩阵代替原矩阵。为何?由于将数据集的均值归零(预处理),也就是只取数据的误差部分
T=Z*Z';  
[V1,D]=eigs(T,k);%计算T的最大的k个特征值和特征向量  
V=Z'*V1;         %协方差矩阵的特征向量  
%这一点是关键步骤,极可能不少初学者没法理解:
%按理来说,协方差矩阵的计算公式为(假设上面中心化的Z已经求出):
%V = (Z'*Z)./(size(Z,1)-1)(先无论单位化,V=Z'*Z)(这里是一行为一个样本,一列为一个维数的状况)
%协方差矩阵是N*N的方阵,维数N应该与原图片f_matrix(200*10304)维数相等
%f_matrix中行数200为图片个数,列数10304为维数
%那为何这里是T=Z*Z',再求T的K个最大特征值和特征向量V1,再用V=Z'*V1来求协方差矩阵特征向量呢?
%由于咱们若是求V=Z'*Z这个V就是一个10304*10304的矩阵,MATLAB奔溃了,太复杂
%咱们能够这样看P^-1*(Z*Z')*P=S等价于P^-1*(Z')^-1*Z'*Z*Z'*P=S等价于(Z'*P)^-1*(Z'*Z)*(Z'*P)=S
%注:P^-1是P的逆矩阵,(Z')^-1为Z'的逆矩阵,类推,建议你们写在纸上
%最后一个式子能够看出Z'*Z的特征向量矩阵为Z'*P,而Z*Z'的特征向量矩阵为P,即为程序中的V1
%这是一种简便方法,为的就是避免像V=Z'*Z这种维数过高的计算。
%可查看C篇文章步骤4
for i=1:k       %特征向量单位化  
    l=norm(V(:,i));  
    V(:,i)=V(:,i)/l;  
end  
%单位化后的V才能是真正的低维空间的基,须要知足正交化单位化两个条件
%具体缘由参考D篇文章
pcaA=Z*V;       %线性变换,降至k维  ,将中心化的矩阵投影到低维空间的基中,V就是低维空间的基
%pcaA为低维空间的坐标表示,即一个图像的判断依据
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);  
    %将图像数据中一个样本的不一样维度的值,最小值和最大值规范到-1和1,其余值按比例规范到(-1,1)
end  
end


-----------------------------------------------------分割线-----------------------------------------------------


第四个文件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


由于降至20维,因此其在低维中的基即是这20张特征脸,其余全部的通过了降维的脸均可以由这20张特征脸线性表示,即咱们要进行脸部识别时,把选择要识别的脸进行降维处理后,再右乘这些基(特征脸)所构成的矩阵,就能获得这些脸在低维中的线性表示。这些表示就是识别的依据。


特征脸截图:




-------------------------------------------------分割线---------------------------------------------------------


第五个文件recognition.m中的代码,在A篇文章当中没有,是我本身编写的脸部识别的小程序,比较简单,没有像A篇文章中同样作GUI界面。

function recognition(mA,V,model) 
%函数做用:人脸识别模块,利用已经建好的模型,从新找一个样本进行识别
%输入:
%           mA-均值
%           V-协方差矩阵特征向量
%           model-经过SVM对训练集训练得出的已经创建好的模型
%%
global imgrow;  
global imgcol;  
%%
%弹出输入框,选择要识别的图片
select_person_num=str2double(cell2mat(inputdlg('请输入想要识别的人的编号(总共40我的):')));%总共40我的
select_img_num=str2double(cell2mat(inputdlg('请输入此人图片的编号(总共10张):')));%总共10张图
%%
%对图片信息进行处理,化为1*10304的行向量
disp('读取选择的图片...')  
select_facepath=strcat('F:\MATLAB人脸识别\Face\facedata\s',num2str(select_person_num),'\',num2str(select_img_num),'.pgm');
select_img=imread(select_facepath);
select_matrix=zeros(1,imgrow*imgcol);
select_matrix(1,:)=select_img(:)';
select_matrix=(select_matrix-mA)*V;%PCA降维后的低维表示
%%
%图形归一化
disp('规范化选择的图片...')  
select_matrix = scaling( select_matrix,min(select_matrix),max(select_matrix));  
%%
%测试选择的图片,accuracy只有两个值,100%表示匹配正确,0%表示匹配错误
disp('测试选择的图片...')  
[select_predict_label,accuracy,decision_values]=svmpredict(select_person_num,select_matrix,model);
%%
%显示原有图片和匹配图片进行比较
disp('显示选择的图片...')  
figure(2);
subplot(1,2,1);imshow(select_img);title('你选择的图片');
subplot(1,2,2);
imshow(imread(strcat('F:\MATLAB人脸识别\Face\facedata\s',num2str(select_predict_label),'\',num2str(1),'.pgm')));
title('匹配的图片');


程序运行到此会弹出输入框,让用户选择想要识别的图片,当Accuracy=100%表示识别正确,若是Accuracy=0%表示识别错误。

                    


输入编码后选择的图片,以及匹配到的图片对比。



-------------------------------------------------分割线---------------------------------------------------------


第六个文件face.m中的代码为主程序。读者想要看到整个效果,只须要将此文件中的程序所有选中按F9便可运行。



注:个人SVM分类器是用libsvm工具箱当中的函数实现的两个关键函数即是svmtrain和svmpredict,核函数选用线性核函数。


以上暂时是初稿,确定还有不少须要修改的地方,若是读者有什么疑问或是看到什么错误,但愿能留言,我会加以请教。你们相互学习,相互进步。


转自:http://blog.csdn.net/yb536/article/details/40586695

相关文章
相关标签/搜索