基於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

相關文章
相關標籤/搜索