此文章將要描述一種基於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