使用OpenCV進行人臉識別

不斷維護的地址:http://plzcoding.com/face-recognition-with-opencv/html

怎樣使用OpenCV進行人臉識別ios

         本文大部分來自OpenCV官網上的Face Reconition with OpenCV這節內容(http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html),小弟我嘗試翻譯一些重要內容。這部份內容是Philipp Wagner寫的,他的github:https://github.com/bytefish,他的網站http://www.bytefish.de/,應該是個德國人。下面應該是他的照片。c++

1

         友情提示,要看懂代碼前,你得先知道OpenCV的安裝和配置,會用C++,用過一些OpenCV函數。基本的圖像處理和矩陣知識也是須要的。[gm:我是簫鳴的註釋]因爲我僅僅是翻譯,對於六級才過的我,確定有一些翻譯錯的或者不當的地方,因此請你們糾錯。git

1.1.介紹Introduction

從OpenCV2.4開始,加入了新的類FaceRecognizer,咱們可使用它便捷地進行人臉識別實驗。本文既介紹代碼使用,又介紹算法原理。(他寫的源代碼,咱們能夠在OpenCV的opencv\modules\contrib\doc\facerec\src下找到,固然也能夠在他的github中找到,若是你想研究源碼,天然能夠去看看,不復雜)github

 

目前支持的算法有web

        Eigenfaces特徵臉createEigenFaceRecognizer()算法

         Fisherfaces  createFisherFaceRecognizer()數據庫

         LocalBinary Patterns Histograms局部二值直方圖 createLBPHFaceRecognizer()編程

下面全部的例子中的代碼在OpenCV安裝目錄下的samples/cpp下面都能找到,全部的代碼商用或者學習都是免費的。windows

 

1.2.人臉識別Face Recognition

對人類來講,人臉識別很容易。文獻[Tu06]告訴咱們,僅僅是才三天的嬰兒已經能夠區分周圍熟悉的人臉了。那麼對於計算機來講,到底有多難?其實,迄今爲止,咱們對於人類本身爲什麼能夠區分不一樣的人所知甚少。是人臉內部特徵(眼睛、鼻子、嘴巴)仍是外部特徵(頭型、髮際線)對於人類識別更有效?咱們怎麼分析一張圖像,大腦是如何對它編碼的?David HubelTorstenWiesel向咱們展現,咱們的大腦針對不一樣的場景,如線、邊、角或者運動這些局部特徵有專門的神經細胞做出反應。顯然咱們沒有把世界當作零散的塊塊,咱們的視覺皮層必須以某種方式把不一樣的信息來源轉化成有用的模式。自動人臉識別就是如何從一幅圖像中提取有意義的特徵,把它們放入一種有用的表示方式,而後對他們進行一些分類。基於幾何特徵的人臉的人臉識別多是最直觀的方法來識別人臉。第一個自動人臉識別系統在[Kanade73]中又描述:標記點(眼睛、耳朵、鼻子等的位置)用來構造一個特徵向量(點與點之間的距離、角度等)。經過計算測試和訓練圖像的特徵向量的歐氏距離來進行識別。這樣的方法對於光照變化很穩健,但也有巨大的缺點:標記點的肯定是很複雜的,即便是使用最早進的算法。一些幾何特徵人臉識別近期工做在文獻[Bru92]中有描述。一個22維的特徵向量被用在一個大數據庫上,單靠幾何特徵不能提供足夠的信息用於人臉識別。

 

特徵臉方法在文獻[TP91]中有描述,他描述了一個全面的方法來識別人臉:面部圖像是一個點,這個點是從高維圖像空間找到它在低維空間的表示,這樣分類變得很簡單。低維子空間低維是使用主元分析(Principal Component Analysis,PCA)找到的,它能夠找擁有最大方差的那個軸。雖然這樣的轉換是從最佳重建角度考慮的,可是他沒有把標籤問題考慮進去。[gm:讀懂這段須要一些機器學習知識]。想象一個狀況,若是變化是基於外部來源,好比光照。軸的最大方差不必定包含任何有鑑別性的信息,所以此時的分類是不可能的。所以,一個使用線性鑑別(Linear Discriminant Analysis,LDA)的特定類投影方法被提出來解決人臉識別問題[BHK97]。其中一個基本的想法就是,使類內方差最小的同時,使類外方差最大。

近年來,各類局部特徵提取方法出現。爲了不輸入的圖像的高維數據,僅僅使用的局部特徵描述圖像的方法被提出,提取的特徵(頗有但願的)對於局部遮擋、光照變化、小樣本等狀況更強健。有關局部特徵提取的方法有蓋伯小波(Gabor Waelets)([Wiskott97]),離散傅立葉變換(DiscreteCosinus Transform,DCT)([Messer06]),局部二值模式(LocalBinary Patterns,LBP)([AHP04])。使用什麼方法來提取時域空間的局部特徵依舊是一個開放性的研究問題,由於空間信息是潛在有用的信息。

1.3.人臉庫Face Database

咱們先獲取一些數據來進行實驗吧。我不想在這裏作一個幼稚的例子。咱們在研究人臉識別,因此咱們須要一個真的人臉圖像!你能夠本身建立本身的數據集,也能夠從這裏(http://face-rec.org/databases/)下載一個。

AT&TFacedatabase又稱ORL人臉數據庫,40我的,每人10張照片。照片在不一樣時間、不一樣光照、不一樣表情(睜眼閉眼、笑或者不笑)、不一樣人臉細節(戴眼鏡或者不戴眼鏡)下采集。全部的圖像都在一個黑暗均勻的背景下采集的,正面豎直人臉(有些有有輕微旋轉)。

 

YaleFacedatabase A ORL數據庫對於初始化測試比較適合,但它是一個簡單的數據庫,特徵臉已經能夠達到97%的識別率,因此你使用其餘方法很可貴到更好的提高。Yale人臉數據庫是一個對於初始實驗更好的數據庫,由於識別問題更復雜。這個數據庫包括15我的(14個男人,1個女人),每個都有11個灰度圖像,大小是320*243像素。數據庫中有光照變化(中心光照、左側光照、右側光照)、表情變化(開心、正常、悲傷、瞌睡、驚訝、眨眼)、眼鏡(戴眼鏡或者沒戴)。

         壞消息是它不能夠公開下載,可能由於原來的服務器壞了。但咱們能夠找到一些鏡像(好比 theMIT)但我不能保證它的完整性。若是你須要本身剪裁和校準圖像,能夠閱讀個人筆記(bytefish.de/blog/fisherfaces)。

 

ExtendedYale Facedatabase B 此數據庫包含38我的的2414張圖片,而且是剪裁好的。這個數據庫重點是測試特徵提取是否對光照變化強健,由於圖像的表情、遮擋等都沒變化。我認爲這個數據庫太大,不適合這篇文章的實驗,我建議使用ORL數據庫。

1.3.1. 準備數據

咱們從網上下了數據,下了咱們須要在程序中讀取它,我決定使用CSV文件讀取它。一個CSV文件包含文件名,緊跟一個標籤。

/path/to/image.ext;0

         假設/path/to/image.ext是圖像,就像你在windows下的c:/faces/person0/image0.jpg。最後咱們給它一個標籤0。這個標籤相似表明這我的的名字,因此同一我的的照片的標籤都同樣。咱們對下載的ORL數據庫進行標識,能夠獲取到以下結果:

./at/s1/1.pgm;0
./at/s1/2.pgm;0
...
./at/s2/1.pgm;1
./at/s2/2.pgm;1
...
./at/s40/1.pgm;39
./at/s40/2.pgm;39

想象我已經把圖像解壓縮在D:/data/at下面,而CSV文件在D:/data/at.txt。下面你根據本身的狀況修改替換便可。一旦你成功創建CSV文件,就能夠像這樣運行示例程序:

facerec_demo.exe D:/data/at.txt

1.3.2 Creating the CSV File

你不須要手工來建立一個CSV文件,我已經寫了一個Python程序來作這事。

[gm:說一個我實現的方法

若是你會cmd命令,或者稱DOS命令,那麼你打開命令控制檯。假設咱們的圖片放在J:下的Faces文件夾下,能夠輸入以下語句:

J:\Faces\ORL>dir /b/s *.bmp > at.txt

而後你打開at.txt文件可能看到以下內容(後面的0,1..標籤是本身加的):

。。。。
J:\Faces\ORL\s1\1.bmp;0
J:\Faces\ORL\s1\10.bmp;0
J:\Faces\ORL\s1\2.bmp;0
J:\Faces\ORL\s1\3.bmp;0
J:\Faces\ORL\s1\4.bmp;0
J:\Faces\ORL\s1\5.bmp;0
J:\Faces\ORL\s1\6.bmp;0
J:\Faces\ORL\s1\7.bmp;0
J:\Faces\ORL\s1\8.bmp;0
J:\Faces\ORL\s1\9.bmp;0
J:\Faces\ORL\s10\1.bmp;1
J:\Faces\ORL\s10\10.bmp;1
J:\Faces\ORL\s10\2.bmp;1
J:\Faces\ORL\s10\3.bmp;1
J:\Faces\ORL\s10\4.bmp;1
J:\Faces\ORL\s10\5.bmp;1
J:\Faces\ORL\s10\6.bmp;1
。。。。

天然還有c++編程等方法能夠作得更好,看這篇文章反響,若是不少人須要,我就把這部分的代碼寫出來。(遍歷多個文件夾,標上標籤)

]

特徵臉Eigenfaces

         咱們講過,圖像表示的問題是他的高維問題。二維灰度圖像p*q大小,是一個m=qp維的向量空間,因此一個100*100像素大小的圖像就是10,000維的圖像空間。問題是,是否是全部的維數空間對咱們來講都有用?咱們能夠作一個決定,若是數據有任何差別,咱們能夠經過尋找主元來知道主要信息。主成分分析(Principal Component Analysis,PCA)是KarlPearson (1901)獨立發表的,而 Harold Hotelling (1933)把一些可能相關的變量轉換成一個更小的不相關的子集。想法是,一個高維數據集常常被相關變量表示,所以只有一些的維上數據纔是有意義的,包含最多的信息。PCA方法尋找數據中擁有最大方差的方向,被稱爲主成分。

令 2  表示一個隨機特徵,其中 3 .

  1. 計算均值向量 4
                              5

 

  1. 計算協方差矩陣 S
                                 6

 

  1. 計算 的特徵值7    和對應的特徵向量   8              9

 

  1. 對特徵值進行遞減排序,特徵向量和它順序一致. K個主成分也就是k個最大的特徵值對應的特徵向量。

x的K個主成份:

        10

 

其中11  .

PCA基的重構:

                  12

 

其中 13 .

而後特徵臉經過下面的方式進行人臉識別:

A.  把全部的訓練數據投影到PCA子空間

B.  把待識別圖像投影到PCA子空間

C.  找到訓練數據投影后的向量和待識別圖像投影后的向量最近的那個。

還有一個問題有待解決。好比咱們有400張圖片,每張100*100像素大小,那麼PCA須要解決協方差矩陣 14的求解,而X的大小是10000*400,那麼咱們會獲得10000*10000大小的矩陣,這須要大概0.8GB的內存。解決這個問題不容易,因此咱們須要另外一個計策。就是轉置一下再求,特徵向量不變化。文獻 [Duda01]中有描述。

[gm:這個PCA仍是本身搜着看吧,這裏的講的不清楚,不適合初學者看]

 

OpenCV中使用特徵臉Eigenfaces in OpenCV

給出示例程序源代碼

#include "opencv2/core/core.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/highgui/highgui.hpp"
 
#include <iostream>
#include <fstream>
#include <sstream>
 
usingnamespace cv;
usingnamespace std;
 
static Mat norm_0_255(InputArray _src) {
    Mat src = _src.getMat();
    // 建立和返回一個歸一化後的圖像矩陣:
    Mat dst;
    switch(src.channels()) {
    case1:
        cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC1);
        break;
    case3:
        cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC3);
        break;
    default:
        src.copyTo(dst);
        break;
    }
    return dst;
}
//使用CSV文件去讀圖像和標籤,主要使用stringstream和getline方法
staticvoid read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator =';') {
    std::ifstream file(filename.c_str(), ifstream::in);
    if (!file) {
        string error_message ="No valid input file was given, please check the given filename.";
        CV_Error(CV_StsBadArg, error_message);
    }
    string line, path, classlabel;
    while (getline(file, line)) {
        stringstream liness(line);
        getline(liness, path, separator);
        getline(liness, classlabel);
        if(!path.empty()&&!classlabel.empty()) {
            images.push_back(imread(path, 0));
            labels.push_back(atoi(classlabel.c_str()));
        }
    }
}
 
int main(int argc, constchar*argv[]) {
    // 檢測合法的命令,顯示用法
    // 若是沒有參數輸入則退出!.
    if (argc <2) {
        cout <<"usage: "<< argv[0]<<" <csv.ext> <output_folder> "<< endl;
        exit(1);
    }
    string output_folder;
    if (argc ==3) {
        output_folder = string(argv[2]);
    }
    //讀取你的CSV文件路徑.
    string fn_csv = string(argv[1]);
    // 2個容器來存放圖像數據和對應的標籤
    vector<Mat> images;
    vector<int> labels;
    // 讀取數據. 若是文件不合法就會出錯
    // 輸入的文件名已經有了.
    try {
        read_csv(fn_csv, images, labels);
    } catch (cv::Exception& e) {
        cerr <<"Error opening file \""<< fn_csv <<"\". Reason: "<< e.msg << endl;
        // 文件有問題,咱們啥也作不了了,退出了
        exit(1);
    }
    // 若是沒有讀取到足夠圖片,咱們也得退出.
    if(images.size()<=1) {
        string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
        CV_Error(CV_StsError, error_message);
    }
    // 獲得第一張照片的高度. 在下面對圖像
    // 變形到他們原始大小時須要
    int height = images[0].rows;
    // 下面的幾行代碼僅僅是從你的數據集中移除最後一張圖片
    //[gm:天然這裏須要根據本身的須要修改,他這裏簡化了不少問題]
    Mat testSample = images[images.size() -1];
    int testLabel = labels[labels.size() -1];
    images.pop_back();
    labels.pop_back();
    // 下面幾行建立了一個特徵臉模型用於人臉識別,
    // 經過CSV文件讀取的圖像和標籤訓練它。
    // T這裏是一個完整的PCA變換
    //若是你只想保留10個主成分,使用以下代碼
    //      cv::createEigenFaceRecognizer(10);
    //
    // 若是你還但願使用置信度閾值來初始化,使用如下語句:
    //      cv::createEigenFaceRecognizer(10, 123.0);
    //
    // 若是你使用全部特徵而且使用一個閾值,使用如下語句:
    //      cv::createEigenFaceRecognizer(0, 123.0);
    //
    Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
    model->train(images, labels);
    // 下面對測試圖像進行預測,predictedLabel是預測標籤結果
    int predictedLabel = model->predict(testSample);
    //
    // 還有一種調用方式,能夠獲取結果同時獲得閾值:
    //      int predictedLabel = -1;
    //      double confidence = 0.0;
    //      model->predict(testSample, predictedLabel, confidence);
    //
    string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
    cout << result_message << endl;
    // 這裏是如何獲取特徵臉模型的特徵值的例子,使用了getMat方法:
    Mat eigenvalues = model->getMat("eigenvalues");
    // 一樣能夠獲取特徵向量:
    Mat W = model->getMat("eigenvectors");
    // 獲得訓練圖像的均值向量
    Mat mean = model->getMat("mean");
    // 現實仍是保存:
    if(argc==2) {
        imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)));
    } else {
        imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows)));
    }
    // 現實仍是保存特徵臉:
    for (int i =0; i < min(10, W.cols); i++) {
        string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
        cout << msg << endl;
        // 獲得第 #i個特徵
        Mat ev = W.col(i).clone();
        //把它變成原始大小,爲了把數據顯示歸一化到0~255.
        Mat grayscale = norm_0_255(ev.reshape(1, height));
        // 使用僞彩色來顯示結果,爲了更好的感覺.
        Mat cgrayscale;
        applyColorMap(grayscale, cgrayscale, COLORMAP_JET);
        // 顯示或者保存:
        if(argc==2) {
            imshow(format("eigenface_%d", i), cgrayscale);
        } else {
            imwrite(format("%s/eigenface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale));
        }
    }
    // 在一些預測過程當中,顯示仍是保存重建後的圖像:
    for(int num_components =10; num_components <300; num_components+=15) {
        // 從模型中的特徵向量截取一部分
        Mat evs = Mat(W, Range::all(), Range(0, num_components));
        Mat projection = subspaceProject(evs, mean, images[0].reshape(1,1));
        Mat reconstruction = subspaceReconstruct(evs, mean, projection);
        // 歸一化結果,爲了顯示:
        reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
        // 顯示或者保存:
        if(argc==2) {
            imshow(format("eigenface_reconstruction_%d", num_components), reconstruction);
        } else {
            imwrite(format("%s/eigenface_reconstruction_%d.png", output_folder.c_str(), num_components), reconstruction);
        }
    }
    // 若是咱們不是存放到文件中,就顯示他,這裏使用了暫定等待鍵盤輸入:
    if(argc==2) {
        waitKey(0);
    }
    return0;
}

         我使用了僞彩色圖像,因此你能夠看到在特徵臉中灰度值是如何分佈的。你能夠看到特徵臉不但對人臉特徵進行編碼,還對這些圖像中的光照進行編碼。(看第四張圖像是左側的光照,而第五張是右側的光照)[gm:PCA對光照變化圖像識別效果不好,天然有一些改進方法,有後再談]

 

15

咱們已經看到了,咱們能夠利用低維近似來重構人臉,咱們看看對於一個好的重構,須要多少特徵臉。我將依次畫出10,30,。。310張特徵臉時的效果。

for(int num_components =10; num_components <300; num_components+=15) {
    Mat evs = Mat(W, Range::all(), Range(0, num_components));
    Mat projection = subspaceProject(evs, mean, images[0].reshape(1,1));
    Mat reconstruction = subspaceReconstruct(evs, mean, projection);
    reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
    if(argc==2) {
        imshow(format("eigenface_reconstruction_%d", num_components), reconstruction);
    } else {
        imwrite(format("%s/eigenface_reconstruction_%d.png", output_folder.c_str(), num_components), reconstruction);
    }
}

 

顯然10個特徵向量[gm:1個特徵向量能夠變造成一個特徵臉,這裏特徵向量和特徵臉概念有些近似]是不夠的,50個特徵向量能夠有效的編碼出重要的人臉特徵。在ORL數據庫中,當使用300個特徵向量時,你將獲取一個比較好的和重構結果。有定理指出重構須要選擇多少特徵臉才合適,但它嚴重依賴於人臉數據庫。[gm:也就是沒啥討論意義,針對現實狀況作出考慮吧]。文獻[Zhao03]是一個好的開始研究起點。

 

 16

         主成分分析是一種基於特徵臉的方法,找到使數據中最大方差的特徵線性組合。這是一個表現數據的強大方法,但它沒有考慮類別信息,而且在扔掉主元時,同時許多有鑑別的信息都被扔掉。假設你數據庫中的變化主要是光照變化,那麼PCA此時幾乎失效了。[gm:把光照狀況相似的照片認爲同樣,而無論人臉其餘細節]能夠看去http://www.bytefish.de/wiki/pca_lda_with_gnu_octave 看下例子。

         線性鑑別分析在降維的同時考慮類別信息,由統計學家 Sir R. A. Fisher發明。在他1936年的文獻中,他成功對花進行了分類:The useof multiple measurements in taxonomic problems [Fisher36]。爲了找到一種特徵組合方式,達到最大的類間離散度和最小的類內離散度。這個想法很簡單:在低維表示下,相同的類應該牢牢的聚在一塊兒,而不一樣的類別儘可能距離越遠。 這也被BelhumeurHespanha 和 Kriegman所認同,因此他們把鑑別分析引入到人臉識別問題中[BHK97]

令x是一個來自c個類中的隨機向量,

                    17

 

散度矩陣  18 和S_{W}以下計算:

                   19

 

, 其中 20  是所有數據的均值     21:

               

 

22  是某個類的均值23  :

                              24

 

Fisher的分類算法能夠看出一個投影矩陣25  , 使得類的可分性最大:

                   26

 

接下來 [BHK97], 一個解決這個普通特徵值優化問題的方法被提出:

                    27

 

         還有一個問題未解決, Sw的排列最多隻有 (N-c),  N 個樣本和c個類別。在模式識別中,樣本數據個數N的大小通常小於輸入數據的維數。 [gm:好比說以前的圖片,N=400,而10000就是數據維數]那麼,散度矩陣Sw就是奇異的(能夠看文獻[RJ91])。在文獻[BHK97]中,使用PCA把數據投影到(N-c)維的子空間,而後再使用線性鑑別分析,由於Sw不是奇異矩陣了(可逆矩陣)。

而後優化問題能夠寫成:

          28

 

投影矩陣W,能夠把樣本投影到(c-1)維的空間上,能夠表示爲

                 29

 

#include "opencv2/core/core.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/highgui/highgui.hpp"
 
#include <iostream>
#include <fstream>
#include <sstream>
 
usingnamespace cv;
usingnamespace std;
 
static Mat norm_0_255(InputArray _src) {
    Mat src = _src.getMat();
    // 建立和返回歸一化的圖像:
    Mat dst;
    switch(src.channels()) {
    case1:
        cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC1);
        break;
    case3:
        cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC3);
        break;
    default:
        src.copyTo(dst);
        break;
    }
    return dst;
}
 
staticvoid read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator =';') {
    std::ifstream file(filename.c_str(), ifstream::in);
    if (!file) {
        string error_message ="No valid input file was given, please check the given filename.";
        CV_Error(CV_StsBadArg, error_message);
    }
    string line, path, classlabel;
    while (getline(file, line)) {
        stringstream liness(line);
        getline(liness, path, separator);
        getline(liness, classlabel);
        if(!path.empty()&&!classlabel.empty()) {
            images.push_back(imread(path, 0));
            labels.push_back(atoi(classlabel.c_str()));
        }
    }
}
 
int main(int argc, constchar*argv[]) {
    // 判斷輸入命令是否有效,輸出用法
    // 若是沒有輸入參數.
    if (argc <2) {
        cout <<"usage: "<< argv[0]<<" <csv.ext> <output_folder> "<< endl;
        exit(1);
    }
    string output_folder;
    if (argc ==3) {
        output_folder = string(argv[2]);
    }
    // 獲取CSV文件的路徑.
    string fn_csv = string(argv[1]);
    // 這些容器存放圖片和標籤.
    vector<Mat> images;
    vector<int> labels;
    // 載入數據.若是不合理,會出錯
    // 輸入文件名fn_csv已經有了.
    try {
        read_csv(fn_csv, images, labels);
    } catch (cv::Exception& e) {
        cerr <<"Error opening file \""<< fn_csv <<"\". Reason: "<< e.msg << endl;
        // 什麼也不能作了
        exit(1);
    }
    // 若是沒有足夠圖像就退出掉.
    if(images.size()<=1) {
        string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
        CV_Error(CV_StsError, error_message);
    }
    int height = images[0].rows;
 
    Mat testSample = images[images.size() -1];
    int testLabel = labels[labels.size() -1];
    images.pop_back();
    labels.pop_back();
    // 若是想保存10個fisherfaces
    //      cv::createFisherFaceRecognizer(10);
    //
    // 若是要以123.0做爲置信閾值
    //      cv::createFisherFaceRecognizer(0, 123.0);
    //
    Ptr<FaceRecognizer> model = createFisherFaceRecognizer();
    model->train(images, labels);
    int predictedLabel = model->predict(testSample);
    //
    //      model->predict(testSample, predictedLabel, confidence);
    //
    string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
    cout << result_message << endl;
    Mat eigenvalues = model->getMat("eigenvalues");
    Mat W = model->getMat("eigenvectors");
    Mat mean = model->getMat("mean");
    if(argc==2) {
        imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)));
    } else {
        imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows)));
    }
    //顯示仍是保存, 最多16 Fisherfaces:
    for (int i =0; i < min(16, W.cols); i++) {
        string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
        cout << msg << endl;
        Mat ev = W.col(i).clone();
        Mat grayscale = norm_0_255(ev.reshape(1, height));
        // 使用Bone僞彩色圖像來顯示.
        Mat cgrayscale;
        applyColorMap(grayscale, cgrayscale, COLORMAP_BONE);
        if(argc==2) {
            imshow(format("fisherface_%d", i), cgrayscale);
        } else {
            imwrite(format("%s/fisherface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale));
        }
    }
    for(int num_component =0; num_component < min(16, W.cols); num_component++) {
        Mat ev = W.col(num_component);
        Mat projection = subspaceProject(ev, mean, images[0].reshape(1,1));
        Mat reconstruction = subspaceReconstruct(ev, mean, projection);
        reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
        if(argc==2) {
            imshow(format("fisherface_reconstruction_%d", num_component), reconstruction);
        } else {
            imwrite(format("%s/fisherface_reconstruction_%d.png", output_folder.c_str(), num_component), reconstruction);
        }
    }
    if(argc==2) {
        waitKey(0);
    }
    return0;
}

在這個例子中,我使用YaleA人臉數據庫,僅僅由於顯示更好些。每個Fisherface都和原始圖像有一樣長度,所以它能夠被顯示成圖像。下面顯示了16張Fisherfaces圖像。

30

         Fisherfaces方法學習一個正對標籤的轉換矩陣,所依它不會如特徵臉那樣那麼注重光照。鑑別分析是尋找能夠區分人的面部特徵。須要說明的是,Fisherfaces的性能也很依賴於輸入數據。實際上,若是你對光照好的圖片上學習Fisherfaces,而想對很差的光照圖片進行識別,那麼他可能會找到錯誤的主元,由於在很差光照圖片上,這些特徵不優越。這彷佛是符合邏輯的,由於這個方法沒有機會去學習光照。[gm:那麼採集圖像時就要考慮光照變化,訓練時考慮全部光照狀況,數據庫multi-pie就考慮不少種光照]

         Fisherfaces容許對投影圖像進行重建,就行特徵臉同樣。可是因爲咱們僅僅使用這些特徵來區分不一樣的類別,所以你沒法期待對原圖像有一個好的重建效果。[gm:也就是特徵臉把每一個圖片當作一個個體,重建時效果也有保證,而Fisherfaces把一我的的照片當作一個總體,那麼重建時重建的效果則不是很好]。對於Fisherfaces方法咱們將把樣本圖像逐個投影到Fisherfaces上。所以你能夠得到一個好的可視效果,每一個Fisherfaces特徵能夠被描述爲

for(int num_component =0; num_component < min(16, W.cols); num_component++) {
    Mat ev = W.col(num_component);
    Mat projection = subspaceProject(ev, mean, images[0].reshape(1,1));
    Mat reconstruction = subspaceReconstruct(ev, mean, projection);
    reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
    if(argc==2) {
        imshow(format("fisherface_reconstruction_%d", num_component), reconstruction);
    } else {
        imwrite(format("%s/fisherface_reconstruction_%d.png", output_folder.c_str(), num_component), reconstruction);
    }
}

對於人類眼睛來講,差別比較微妙,但你仍是能夠看到一些差別的。

31

局部二值模式直方圖Local Binary Patterns Histograms

         Eigenfaces和Fisherfaces使用總體方法來進行人臉識別[gm:直接使用全部的像素]。你把你的數據看成圖像空間的高維向量。咱們都知道高維數據是糟糕的,因此一個低維子空間被肯定,對於信息保存可能很好。Eigenfaces是最大化總的散度,這樣可能致使,當方差由外部條件產生時,最大方差的主成分不適合用來分類。因此爲使用一些鑑別分析,咱們使用了LDA方法來優化。Fisherfaces方法能夠很好的運做,至少在咱們假設的模型的有限狀況下。

         現實生活是不完美的。你沒法保證在你的圖像中光照條件是完美的,或者說1我的的10張照片。因此,若是每人僅僅只有一張照片呢?咱們的子空間的協方差估計方法可能徹底錯誤,因此識別也可能錯誤。是否記得Eigenfaces在AT&T數據庫上達到了96%的識別率?對於這樣有效的估計,咱們須要多少張訓練圖像呢?下圖是Eigenfaces和Fisherfaces方法在AT&T數據庫上的首選識別率,這是一個簡單的數據庫:

32

 

         所以,若你想獲得好的識別率,你大約須要每一個人有8(7~9)張圖像,而Fisherfaces在這裏並無好的幫助。以上的實驗是10個圖像的交叉驗證結果,使用了facerec框架: https://github.com/bytefish/facerec。這不是一個刊物,因此我不會用高深的數學分析來證實這個圖像。 當遇到小的訓練數據集時,能夠看一下文獻[KM01],瞭解二種方法的細節分析。

         一些研究專一於圖像局部特徵的提取。主意是咱們不把整個圖像當作一個高維向量,僅僅用局部特徵來描述一個物體。經過這種方式提取特徵,你將得到一個低維隱式。一個好主意!可是你很快發現這種圖像表示方法不只僅遭受光照變化。你想一想圖像中的尺度變化、形變、旋轉—咱們的局部表示方式起碼對這些狀況比較穩健。正如SIFT,LBP方法在2D紋理分析中舉足輕重。LBP的基本思想是對圖像的像素和它局部周圍像素進行對比後的結果進行求和。把這個像素做爲中心,對相鄰像素進行閾值比較。若是中心像素的亮度大於等於他的相鄰像素,把他標記爲1,不然標記爲0。你會用二進制數字來表示每一個像素,好比11001111。所以,因爲周圍相鄰8個像素,你最終可能獲取2^8個可能組合,被稱爲局部二值模式,有時被稱爲LBP碼。第一個在文獻中描述的LBP算子實際使用的是3*3的鄰域。

33

         一個更加正式的LBP操做能夠被定義爲

                     34

 

其中35 是中心像素,亮度是36 ;而 37則是相鄰像素的亮度。s是一個符號函數:

 

        38

這種描述方法使得你能夠很好的捕捉到圖像中的細節。實際上,研究者們能夠用它在紋理分類上獲得最早進的水平。正如剛纔描述的方法被提出後,固定的近鄰區域對於尺度變化的編碼失效。因此,使用一個變量的擴展方法,在文獻[AHP04]中有描述。主意是使用可變半徑的圓對近鄰像素進行編碼,這樣能夠捕捉到以下的近鄰:

            39

對一個給定的點40   ,他的近鄰點 41 能夠由以下計算:

        42

其中,R是圓的半徑,而P是樣本點的個數。

這個操做是對原始LBP算子的擴展,因此有時被稱爲擴展LBP(又稱爲圓形LBP)。若是一個在圓上的點不在圖像座標上,咱們使用他的內插點。計算機科學有一堆聰明的插值方法,而OpenCV使用雙線性插值。

         43

LBP算子,對於灰度的單調變化很穩健。咱們能夠看到手工改變後的圖像的LBP圖像(你能夠看到LBP圖像是什麼樣子的!)

            44

 

         那麼剩下來的就是如何合併空間信息用於人臉識別模型。Ahonenet. Al在文獻 [AHP04]中提出表示方法,對LBP圖像成m個塊,每一個塊提取直方圖。經過鏈接局部特直方圖(而不是合併)而後就能獲得空間加強的特徵向量。這些直方圖被稱爲局部二值模式直方圖。

OpenCV中的局部二值模式直方圖Local Binary Patterns Histograms inOpenCV

#include "opencv2/core/core.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/highgui/highgui.hpp"
 
#include <iostream>
#include <fstream>
#include <sstream>
 
usingnamespace cv;
usingnamespace std;
 
staticvoid read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator =';') {
    std::ifstream file(filename.c_str(), ifstream::in);
    if (!file) {
        string error_message ="No valid input file was given, please check the given filename.";
        CV_Error(CV_StsBadArg, error_message);
    }
    string line, path, classlabel;
    while (getline(file, line)) {
        stringstream liness(line);
        getline(liness, path, separator);
        getline(liness, classlabel);
        if(!path.empty()&&!classlabel.empty()) {
            images.push_back(imread(path, 0));
            labels.push_back(atoi(classlabel.c_str()));
        }
    }
}
 
int main(int argc, constchar*argv[]) {
    if (argc !=2) {
        cout <<"usage: "<< argv[0]<<" <csv.ext>"<< endl;
        exit(1);
    }
    string fn_csv = string(argv[1]);
    vector<Mat> images;
    vector<int> labels;
    try {
        read_csv(fn_csv, images, labels);
    } catch (cv::Exception& e) {
        cerr <<"Error opening file \""<< fn_csv <<"\". Reason: "<< e.msg << endl;
        // nothing more we can do
        exit(1);
    }
    if(images.size()<=1) {
        string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
        CV_Error(CV_StsError, error_message);
    }
    int height = images[0].rows;
    Mat testSample = images[images.size() -1];
    int testLabel = labels[labels.size() -1];
    images.pop_back();
    labels.pop_back();
    // TLBPHFaceRecognizer 使用了擴展的LBP
    // 在其餘的算子中他可能很容易被擴展
    // 下面是默認參數
    //      radius = 1
    //      neighbors = 8
    //      grid_x = 8
    //      grid_y = 8
    //
    // 若是你要建立 LBPH FaceRecognizer 半徑是2,16個鄰域
    //      cv::createLBPHFaceRecognizer(2, 16);
    //
    // 若是你須要一個閾值,而且使用默認參數:
    //      cv::createLBPHFaceRecognizer(1,8,8,8,123.0)
    //
    Ptr<FaceRecognizer> model = createLBPHFaceRecognizer();
    model->train(images, labels);
    int predictedLabel = model->predict(testSample);
    //      int predictedLabel = -1;
    //      double confidence = 0.0;
    //      model->predict(testSample, predictedLabel, confidence);
    //
    string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
    cout << result_message << endl;
    // 有時你須要設置或者獲取內部數據模型,
    // 他不能被暴露在 cv::FaceRecognizer類中.
    //
    // 首先咱們對FaceRecognizer的閾值設置到0.0,而不是重寫訓練模型
    // 當你從新估計模型時很重要 
    //
    model->set("threshold",0.0);
    predictedLabel = model->predict(testSample);
    cout <<"Predicted class = "<< predictedLabel << endl;
    // 因爲確保高效率,LBP圖沒有被存儲在模型裏面。D
    cout <<"Model Information:"<< endl;
    string model_info = format("\tLBPH(radius=%i, neighbors=%i, grid_x=%i, grid_y=%i, threshold=%.2f)",
            model->getInt("radius"),
            model->getInt("neighbors"),
            model->getInt("grid_x"),
            model->getInt("grid_y"),
            model->getDouble("threshold"));
    cout << model_info << endl;
    // 咱們能夠獲取樣本的直方圖:
    vector<Mat> histograms = model->getMatVector("histograms");
    // 我須要現實它嗎? 或許它的長度纔是咱們感興趣的:
    cout <<"Size of the histograms: "<< histograms[0].total()<< endl;
    return0;
}

總結Conclusion

你已經學會如何在真實應用下,使用新的FaceRecognizer類。讀完算法,可能到你進行實驗的時候了,使用它們,改進它們,讓OpenCV社區參與其中!

 

文獻Literature

[AHP04]

(123) Ahonen, T., Hadid, A., and Pietikainen, M. Face Recognition with Local Binary Patterns. Computer Vision - ECCV 2004 (2004), 469–481.

 

[BHK97]

(12345) Belhumeur, P. N., Hespanha, J., and Kriegman, D. Eigenfaces vs. Fisherfaces: Recognition Using Class Specific Linear Projection. IEEE Transactions on Pattern Analysis and Machine Intelligence 19, 7 (1997), 711–720.

 

[Bru92]

Brunelli, R., Poggio, T. Face Recognition through Geometrical Features. European Conference on Computer Vision (ECCV) 1992, S. 792–800.

 

[Duda01]

Duda, Richard O. and Hart, Peter E. and Stork, David G., Pattern Classification (2nd Edition) 2001.

 

[Fisher36]

Fisher, R. A. The use of multiple measurements in taxonomic problems. Annals Eugen. 7 (1936), 179–188.

 

[GBK01]

Georghiades, A.S. and Belhumeur, P.N. and Kriegman, D.J., From Few to Many: Illumination Cone Models for Face Recognition under Variable Lighting and Pose IEEE Transactions on Pattern Analysis and Machine Intelligence 23, 6 (2001), 643-660.

 

[Kanade73]

Kanade, T. Picture processing system by computer complex and recognition of human faces. PhD thesis, Kyoto University, November 1973

 

[KM01]

Martinez, A and Kak, A. PCA versus LDA IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. 23, No.2, pp. 228-233, 2001.

 

[Lee05]

Lee, K., Ho, J., Kriegman, D. Acquiring Linear Subspaces for Face Recognition under Variable Lighting. In: IEEE Transactions on Pattern Analysis and Machine Intelligence (PAMI) 27 (2005), Nr. 5

 

[Messer06]

Messer, K. et al. Performance Characterisation of Face Recognition Algorithms and Their Sensitivity to Severe Illumination Changes. In: In: ICB, 2006, S. 1–11.

 

[RJ91]

  1. Raudys and A.K. Jain. Small sample size effects in statistical pattern recognition: Recommendations for practitioneers. - IEEE Transactions on Pattern Analysis and Machine Intelligence 13, 3 (1991), 252-264.

 

[Tan10]

Tan, X., and Triggs, B. Enhanced local texture feature sets for face recognition under difficult lighting conditions. IEEE Transactions on Image Processing 19 (2010), 1635–650.

 

[TP91]

Turk, M., and Pentland, A. Eigenfaces for recognition. Journal of Cognitive Neuroscience 3 (1991), 71–86.

 

[Tu06]

Chiara Turati, Viola Macchi Cassia, F. S., and Leo, I. Newborns face recognition: Role of inner and outer facial features. Child Development 77, 2 (2006), 297–311.

 

[Wiskott97]

Wiskott, L., Fellous, J., Krüger, N., Malsburg, C. Face Recognition By Elastic Bunch Graph Matching.IEEE Transactions on Pattern Analysis and Machine Intelligence 19 (1997), S. 775–779

 

[Zhao03]

Zhao, W., Chellappa, R., Phillips, P., and Rosenfeld, A. Face recognition: A literature survey. ACM Computing Surveys (CSUR) 35, 4 (2003), 399–458.

人臉對齊Aligning Face Images

         對於圖像數據的對其很重要,特別遇到情感檢測這類任務,你須要越多的細節越好。相信我,你不會要本身動手作吧。我給你提供了一個Python代碼。

#  CropFace(image, eye_left, eye_right, offset_pct, dest_sz)
# eye_left is the position of the left eye
# eye_right is the position of the right eye
# offset_pct is the percent of the image you want to keep next to the eyes (horizontal, vertical direction)
# dest_sz is the size of the output image
#
importsys,math,Image
 
defDistance(p1,p2):
  dx = p2[0]- p1[0]
  dy = p2[1]- p1[1]
  return math.sqrt(dx*dx+dy*dy)
 
defScaleRotateTranslate(image, angle, center =None, new_center =None, scale =None, resample=Image.BICUBIC):
  if (scale isNone)and (center isNone):
    return image.rotate(angle=angle, resample=resample)
  nx,ny = x,y = center
  sx=sy=1.0
  if new_center:
    (nx,ny) = new_center
  if scale:
    (sx,sy) = (scale, scale)
  cosine = math.cos(angle)
  sine = math.sin(angle)
  a = cosine/sx
  b = sine/sx
  c = x-nx*a-ny*b
  d =-sine/sy
  e = cosine/sy
  f = y-nx*d-ny*e
  return image.transform(image.size, Image.AFFINE, (a,b,c,d,e,f), resample=resample)
 
defCropFace(image, eye_left=(0,0), eye_right=(0,0), offset_pct=(0.2,0.2), dest_sz = (70,70)):
  # calculate offsets in original image
  offset_h = math.floor(float(offset_pct[0])*dest_sz[0])
  offset_v = math.floor(float(offset_pct[1])*dest_sz[1])
  # get the direction
  eye_direction = (eye_right[0]- eye_left[0], eye_right[1]- eye_left[1])
  # calc rotation angle in radians
  rotation =-math.atan2(float(eye_direction[1]),float(eye_direction[0]))
  # distance between them
  dist = Distance(eye_left, eye_right)
  # calculate the reference eye-width
  reference = dest_sz[0]-2.0*offset_h
  # scale factor
  scale =float(dist)/float(reference)
  # rotate original around the left eye
  image = ScaleRotateTranslate(image, center=eye_left, angle=rotation)
  # crop the rotated image
  crop_xy = (eye_left[0]- scale*offset_h, eye_left[1]- scale*offset_v)
  crop_size = (dest_sz[0]*scale, dest_sz[1]*scale)
  image = image.crop((int(crop_xy[0]),int(crop_xy[1]),int(crop_xy[0]+crop_size[0]),int(crop_xy[1]+crop_size[1])))
  # resize it
  image = image.resize(dest_sz, Image.ANTIALIAS)
  return image
  
if __name__ =="__main__":
  image =  Image.open("arnie.jpg")
  CropFace(image, eye_left=(252,364), eye_right=(420,366), offset_pct=(0.1,0.1), dest_sz=(200,200)).save("arnie_10_10_200_200.jpg")
  CropFace(image, eye_left=(252,364), eye_right=(420,366), offset_pct=(0.2,0.2), dest_sz=(200,200)).save("arnie_20_20_200_200.jpg")
  CropFace(image, eye_left=(252,364), eye_right=(420,366), offset_pct=(0.3,0.3), dest_sz=(200,200)).save("arnie_30_30_200_200.jpg")
  CropFace(image, eye_left=(252,364), eye_right=(420,366), offset_pct=(0.2,0.2)).save("arnie_20_20_70_70.jpg")

設想咱們有一張施瓦辛格的照片 thisphoto of Arnold Schwarzenegger,人眼座標是(252,364)和(420,366)。參數是水平偏移、垂直偏移和你縮放後的圖像大小。[gm:我建議使用最小的那張圖片]

 

Configuration

Cropped, Scaled, Rotated Face

0.1 (10%), 0.1 (10%), (200,200)

45

0.2 (20%), 0.2 (20%), (200,200)

46

0.3 (30%), 0.3 (30%), (200,200)

47

0.2 (20%), 0.2 (20%), (70,70)

48

 

 

 

 

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
/home/philipp/facerec/data/at/s13/2.pgm;12
/home/philipp/facerec/data/at/s13/7.pgm;12
/home/philipp/facerec/data/at/s13/6.pgm;12
/home/philipp/facerec/data/at/s13/9.pgm;12
/home/philipp/facerec/data/at/s13/5.pgm;12
/home/philipp/facerec/data/at/s13/3.pgm;12
/home/philipp/facerec/data/at/s13/4.pgm;12
/home/philipp/facerec/data/at/s13/10.pgm;12
/home/philipp/facerec/data/at/s13/8.pgm;12
/home/philipp/facerec/data/at/s13/1.pgm;12
/home/philipp/facerec/data/at/s17/2.pgm;16
/home/philipp/facerec/data/at/s17/7.pgm;16
/home/philipp/facerec/data/at/s17/6.pgm;16
/home/philipp/facerec/data/at/s17/9.pgm;16
/home/philipp/facerec/data/at/s17/5.pgm;16
/home/philipp/facerec/data/at/s17/3.pgm;16
/home/philipp/facerec/data/at/s17/4.pgm;16
/home/philipp/facerec/data/at/s17/10.pgm;16
/home/philipp/facerec/data/at/s17/8.pgm;16
/home/philipp/facerec/data/at/s17/1.pgm;16
/home/philipp/facerec/data/at/s32/2.pgm;31
/home/philipp/facerec/data/at/s32/7.pgm;31
/home/philipp/facerec/data/at/s32/6.pgm;31
/home/philipp/facerec/data/at/s32/9.pgm;31
/home/philipp/facerec/data/at/s32/5.pgm;31
/home/philipp/facerec/data/at/s32/3.pgm;31
/home/philipp/facerec/data/at/s32/4.pgm;31
/home/philipp/facerec/data/at/s32/10.pgm;31
/home/philipp/facerec/data/at/s32/8.pgm;31
/home/philipp/facerec/data/at/s32/1.pgm;31
/home/philipp/facerec/data/at/s10/2.pgm;9
/home/philipp/facerec/data/at/s10/7.pgm;9
/home/philipp/facerec/data/at/s10/6.pgm;9
/home/philipp/facerec/data/at/s10/9.pgm;9
/home/philipp/facerec/data/at/s10/5.pgm;9
/home/philipp/facerec/data/at/s10/3.pgm;9
/home/philipp/facerec/data/at/s10/4.pgm;9
/home/philipp/facerec/data/at/s10/10.pgm;9
/home/philipp/facerec/data/at/s10/8.pgm;9
/home/philipp/facerec/data/at/s10/1.pgm;9
/home/philipp/facerec/data/at/s27/2.pgm;26
/home/philipp/facerec/data/at/s27/7.pgm;26
/home/philipp/facerec/data/at/s27/6.pgm;26
/home/philipp/facerec/data/at/s27/9.pgm;26
/home/philipp/facerec/data/at/s27/5.pgm;26
/home/philipp/facerec/data/at/s27/3.pgm;26
/home/philipp/facerec/data/at/s27/4.pgm;26
/home/philipp/facerec/data/at/s27/10.pgm;26
/home/philipp/facerec/data/at/s27/8.pgm;26
/home/philipp/facerec/data/at/s27/1.pgm;26
/home/philipp/facerec/data/at/s5/2.pgm;4
/home/philipp/facerec/data/at/s5/7.pgm;4
/home/philipp/facerec/data/at/s5/6.pgm;4
/home/philipp/facerec/data/at/s5/9.pgm;4
/home/philipp/facerec/data/at/s5/5.pgm;4
/home/philipp/facerec/data/at/s5/3.pgm;4
/home/philipp/facerec/data/at/s5/4.pgm;4
/home/philipp/facerec/data/at/s5/10.pgm;4
/home/philipp/facerec/data/at/s5/8.pgm;4
/home/philipp/facerec/data/at/s5/1.pgm;4
/home/philipp/facerec/data/at/s20/2.pgm;19
/home/philipp/facerec/data/at/s20/7.pgm;19
/home/philipp/facerec/data/at/s20/6.pgm;19
/home/philipp/facerec/data/at/s20/9.pgm;19
/home/philipp/facerec/data/at/s20/5.pgm;19
/home/philipp/facerec/data/at/s20/3.pgm;19
/home/philipp/facerec/data/at/s20/4.pgm;19
/home/philipp/facerec/data/at/s20/10.pgm;19
/home/philipp/facerec/data/at/s20/8.pgm;19
/home/philipp/facerec/data/at/s20/1.pgm;19
/home/philipp/facerec/data/at/s30/2.pgm;29
/home/philipp/facerec/data/at/s30/7.pgm;29
/home/philipp/facerec/data/at/s30/6.pgm;29
/home/philipp/facerec/data/at/s30/9.pgm;29
/home/philipp/facerec/data/at/s30/5.pgm;29
/home/philipp/facerec/data/at/s30/3.pgm;29
/home/philipp/facerec/data/at/s30/4.pgm;29
/home/philipp/facerec/data/at/s30/10.pgm;29
/home/philipp/facerec/data/at/s30/8.pgm;29
/home/philipp/facerec/data/at/s30/1.pgm;29
/home/philipp/facerec/data/at/s39/2.pgm;38
/home/philipp/facerec/data/at/s39/7.pgm;38
/home/philipp/facerec/data/at/s39/6.pgm;38
/home/philipp/facerec/data/at/s39/9.pgm;38
/home/philipp/facerec/data/at/s39/5.pgm;38
/home/philipp/facerec/data/at/s39/3.pgm;38
/home/philipp/facerec/data/at/s39/4.pgm;38
/home/philipp/facerec/data/at/s39/10.pgm;38
/home/philipp/facerec/data/at/s39/8.pgm;38
/home/philipp/facerec/data/at/s39/1.pgm;38
/home/philipp/facerec/data/at/s35/2.pgm;34
/home/philipp/facerec/data/at/s35/7.pgm;34
/home/philipp/facerec/data/at/s35/6.pgm;34
/home/philipp/facerec/data/at/s35/9.pgm;34
/home/philipp/facerec/data/at/s35/5.pgm;34
/home/philipp/facerec/data/at/s35/3.pgm;34
/home/philipp/facerec/data/at/s35/4.pgm;34
/home/philipp/facerec/data/at/s35/10.pgm;34
/home/philipp/facerec/data/at/s35/8.pgm;34
/home/philipp/facerec/data/at/s35/1.pgm;34
/home/philipp/facerec/data/at/s23/2.pgm;22
/home/philipp/facerec/data/at/s23/7.pgm;22
/home/philipp/facerec/data/at/s23/6.pgm;22
/home/philipp/facerec/data/at/s23/9.pgm;22
/home/philipp/facerec/data/at/s23/5.pgm;22
/home/philipp/facerec/data/at/s23/3.pgm;22
/home/philipp/facerec/data/at/s23/4.pgm;22
/home/philipp/facerec/data/at/s23/10.pgm;22
/home/philipp/facerec/data/at/s23/8.pgm;22
/home/philipp/facerec/data/at/s23/1.pgm;22
/home/philipp/facerec/data/at/s4/2.pgm;3
/home/philipp/facerec/data/at/s4/7.pgm;3
/home/philipp/facerec/data/at/s4/6.pgm;3
/home/philipp/facerec/data/at/s4/9.pgm;3
/home/philipp/facerec/data/at/s4/5.pgm;3
/home/philipp/facerec/data/at/s4/3.pgm;3
/home/philipp/facerec/data/at/s4/4.pgm;3
/home/philipp/facerec/data/at/s4/10.pgm;3
/home/philipp/facerec/data/at/s4/8.pgm;3
/home/philipp/facerec/data/at/s4/1.pgm;3
/home/philipp/facerec/data/at/s9/2.pgm;8
/home/philipp/facerec/data/at/s9/7.pgm;8
/home/philipp/facerec/data/at/s9/6.pgm;8
/home/philipp/facerec/data/at/s9/9.pgm;8
/home/philipp/facerec/data/at/s9/5.pgm;8
/home/philipp/facerec/data/at/s9/3.pgm;8
/home/philipp/facerec/data/at/s9/4.pgm;8
/home/philipp/facerec/data/at/s9/10.pgm;8
/home/philipp/facerec/data/at/s9/8.pgm;8
/home/philipp/facerec/data/at/s9/1.pgm;8
/home/philipp/facerec/data/at/s37/2.pgm;36
/home/philipp/facerec/data/at/s37/7.pgm;36
/home/philipp/facerec/data/at/s37/6.pgm;36
/home/philipp/facerec/data/at/s37/9.pgm;36
/home/philipp/facerec/data/at/s37/5.pgm;36
/home/philipp/facerec/data/at/s37/3.pgm;36
/home/philipp/facerec/data/at/s37/4.pgm;36
/home/philipp/facerec/data/at/s37/10.pgm;36
/home/philipp/facerec/data/at/s37/8.pgm;36
/home/philipp/facerec/data/at/s37/1.pgm;36
/home/philipp/facerec/data/at/s24/2.pgm;23
/home/philipp/facerec/data/at/s24/7.pgm;23
/home/philipp/facerec/data/at/s24/6.pgm;23
/home/philipp/facerec/data/at/s24/9.pgm;23
/home/philipp/facerec/data/at/s24/5.pgm;23
/home/philipp/facerec/data/at/s24/3.pgm;23
/home/philipp/facerec/data/at/s24/4.pgm;23
/home/philipp/facerec/data/at/s24/10.pgm;23
/home/philipp/facerec/data/at/s24/8.pgm;23
/home/philipp/facerec/data/at/s24/1.pgm;23
/home/philipp/facerec/data/at/s19/2.pgm;18
/home/philipp/facerec/data/at/s19/7.pgm;18
/home/philipp/facerec/data/at/s19/6.pgm;18
/home/philipp/facerec/data/at/s19/9.pgm;18
/home/philipp/facerec/data/at/s19/5.pgm;18
/home/philipp/facerec/data/at/s19/3.pgm;18
/home/philipp/facerec/data/at/s19/4.pgm;18
/home/philipp/facerec/data/at/s19/10.pgm;18
/home/philipp/facerec/data/at/s19/8.pgm;18
/home/philipp/facerec/data/at/s19/1.pgm;18
/home/philipp/facerec/data/at/s8/2.pgm;7
/home/philipp/facerec/data/at/s8/7.pgm;7
/home/philipp/facerec/data/at/s8/6.pgm;7
/home/philipp/facerec/data/at/s8/9.pgm;7
/home/philipp/facerec/data/at/s8/5.pgm;7
/home/philipp/facerec/data/at/s8/3.pgm;7
/home/philipp/facerec/data/at/s8/4.pgm;7
/home/philipp/facerec/data/at/s8/10.pgm;7
/home/philipp/facerec/data/at/s8/8.pgm;7
/home/philipp/facerec/data/at/s8/1.pgm;7
/home/philipp/facerec/data/at/s21/2.pgm;20
/home/philipp/facerec/data/at/s21/7.pgm;20
/home/philipp/facerec/data/at/s21/6.pgm;20
/home/philipp/facerec/data/at/s21/9.pgm;20
/home/philipp/facerec/data/at/s21/5.pgm;20
/home/philipp/facerec/data/at/s21/3.pgm;20
/home/philipp/facerec/data/at/s21/4.pgm;20
/home/philipp/facerec/data/at/s21/10.pgm;20
/home/philipp/facerec/data/at/s21/8.pgm;20
/home/philipp/facerec/data/at/s21/1.pgm;20
/home/philipp/facerec/data/at/s1/2.pgm;0
/home/philipp/facerec/data/at/s1/7.pgm;0
/home/philipp/facerec/data/at/s1/6.pgm;0
/home/philipp/facerec/data/at/s1/9.pgm;0
/home/philipp/facerec/data/at/s1/5.pgm;0
/home/philipp/facerec/data/at/s1/3.pgm;0
/home/philipp/facerec/data/at/s1/4.pgm;0
/home/philipp/facerec/data/at/s1/10.pgm;0
/home/philipp/facerec/data/at/s1/8.pgm;0
/home/philipp/facerec/data/at/s1/1.pgm;0
/home/philipp/facerec/data/at/s7/2.pgm;6
/home/philipp/facerec/data/at/s7/7.pgm;6
/home/philipp/facerec/data/at/s7/6.pgm;6
/home/philipp/facerec/data/at/s7/9.pgm;6
/home/philipp/facerec/data/at/s7/5.pgm;6
/home/philipp/facerec/data/at/s7/3.pgm;6
/home/philipp/facerec/data/at/s7/4.pgm;6
/home/philipp/facerec/data/at/s7/10.pgm;6
/home/philipp/facerec/data/at/s7/8.pgm;6
/home/philipp/facerec/data/at/s7/1.pgm;6
/home/philipp/facerec/data/at/s16/2.pgm;15
/home/philipp/facerec/data/at/s16/7.pgm;15
/home/philipp/facerec/data/at/s16/6.pgm;15
/home/philipp/facerec/data/at/s16/9.pgm;15
/home/philipp/facerec/data/at/s16/5.pgm;15
/home/philipp/facerec/data/at/s16/3.pgm;15
/home/philipp/facerec/data/at/s16/4.pgm;15
/home/philipp/facerec/data/at/s16/10.pgm;15
/home/philipp/facerec/data/at/s16/8.pgm;15
/home/philipp/facerec/data/at/s16/1.pgm;15
/home/philipp/facerec/data/at/s36/2.pgm;35
/home/philipp/facerec/data/at/s36/7.pgm;35
/home/philipp/facerec/data/at/s36/6.pgm;35
/home/philipp/facerec/data/at/s36/9.pgm;35
/home/philipp/facerec/data/at/s36/5.pgm;35
/home/philipp/facerec/data/at/s36/3.pgm;35
/home/philipp/facerec/data/at/s36/4.pgm;35
/home/philipp/facerec/data/at/s36/10.pgm;35
/home/philipp/facerec/data/at/s36/8.pgm;35
/home/philipp/facerec/data/at/s36/1.pgm;35
/home/philipp/facerec/data/at/s25/2.pgm;24
/home/philipp/facerec/data/at/s25/7.pgm;24
/home/philipp/facerec/data/at/s25/6.pgm;24
/home/philipp/facerec/data/at/s25/9.pgm;24
/home/philipp/facerec/data/at/s25/5.pgm;24
/home/philipp/facerec/data/at/s25/3.pgm;24
/home/philipp/facerec/data/at/s25/4.pgm;24
/home/philipp/facerec/data/at/s25/10.pgm;24
/home/philipp/facerec/data/at/s25/8.pgm;24
/home/philipp/facerec/data/at/s25/1.pgm;24
/home/philipp/facerec/data/at/s14/2.pgm;13
/home/philipp/facerec/data/at/s14/7.pgm;13
/home/philipp/facerec/data/at/s14/6.pgm;13
/home/philipp/facerec/data/at/s14/9.pgm;13
/home/philipp/facerec/data/at/s14/5.pgm;13
/home/philipp/facerec/data/at/s14/3.pgm;13
/home/philipp/facerec/data/at/s14/4.pgm;13
/home/philipp/facerec/data/at/s14/10.pgm;13
/home/philipp/facerec/data/at/s14/8.pgm;13
/home/philipp/facerec/data/at/s14/1.pgm;13
/home/philipp/facerec/data/at/s34/2.pgm;33
/home/philipp/facerec/data/at/s34/7.pgm;33
/home/philipp/facerec/data/at/s34/6.pgm;33
/home/philipp/facerec/data/at/s34/9.pgm;33
/home/philipp/facerec/data/at/s34/5.pgm;33
/home/philipp/facerec/data/at/s34/3.pgm;33
/home/philipp/facerec/data/at/s34/4.pgm;33
/home/philipp/facerec/data/at/s34/10.pgm;33
/home/philipp/facerec/data/at/s34/8.pgm;33
/home/philipp/facerec/data/at/s34/1.pgm;33
/home/philipp/facerec/data/at/s11/2.pgm;10
/home/philipp/facerec/data/at/s11/7.pgm;10
/home/philipp/facerec/data/at/s11/6.pgm;10
/home/philipp/facerec/data/at/s11/9.pgm;10
/home/philipp/facerec/data/at/s11/5.pgm;10
/home/philipp/facerec/data/at/s11/3.pgm;10
/home/philipp/facerec/data/at/s11/4.pgm;10
/home/philipp/facerec/data/at/s11/10.pgm;10
/home/philipp/facerec/data/at/s11/8.pgm;10
/home/philipp/facerec/data/at/s11/1.pgm;10
/home/philipp/facerec/data/at/s26/2.pgm;25
/home/philipp/facerec/data/at/s26/7.pgm;25
/home/philipp/facerec/data/at/s26/6.pgm;25
/home/philipp/facerec/data/at/s26/9.pgm;25
/home/philipp/facerec/data/at/s26/5.pgm;25
/home/philipp/facerec/data/at/s26/3.pgm;25
/home/philipp/facerec/data/at/s26/4.pgm;25
/home/philipp/facerec/data/at/s26/10.pgm;25
/home/philipp/facerec/data/at/s26/8.pgm;25
/home/philipp/facerec/data/at/s26/1.pgm;25
/home/philipp/facerec/data/at/s18/2.pgm;17
/home/philipp/facerec/data/at/s18/7.pgm;17
/home/philipp/facerec/data/at/s18/6.pgm;17
/home/philipp/facerec/data/at/s18/9.pgm;17
/home/philipp/facerec/data/at/s18/5.pgm;17
/home/philipp/facerec/data/at/s18/3.pgm;17
/home/philipp/facerec/data/at/s18/4.pgm;17
/home/philipp/facerec/data/at/s18/10.pgm;17
/home/philipp/facerec/data/at/s18/8.pgm;17
/home/philipp/facerec/data/at/s18/1.pgm;17
/home/philipp/facerec/data/at/s29/2.pgm;28
/home/philipp/facerec/data/at/s29/7.pgm;28
/home/philipp/facerec/data/at/s29/6.pgm;28
/home/philipp/facerec/data/at/s29/9.pgm;28
/home/philipp/facerec/data/at/s29/5.pgm;28
/home/philipp/facerec/data/at/s29/3.pgm;28
/home/philipp/facerec/data/at/s29/4.pgm;28
/home/philipp/facerec/data/at/s29/10.pgm;28
/home/philipp/facerec/data/at/s29/8.pgm;28
/home/philipp/facerec/data/at/s29/1.pgm;28
/home/philipp/facerec/data/at/s33/2.pgm;32
/home/philipp/facerec/data/at/s33/7.pgm;32
/home/philipp/facerec/data/at/s33/6.pgm;32
/home/philipp/facerec/data/at/s33/9.pgm;32
/home/philipp/facerec/data/at/s33/5.pgm;32
/home/philipp/facerec/data/at/s33/3.pgm;32
/home/philipp/facerec/data/at/s33/4.pgm;32
/home/philipp/facerec/data/at/s33/10.pgm;32
/home/philipp/facerec/data/at/s33/8.pgm;32
/home/philipp/facerec/data/at/s33/1.pgm;32
/home/philipp/facerec/data/at/s12/2.pgm;11
/home/philipp/facerec/data/at/s12/7.pgm;11
/home/philipp/facerec/data/at/s12/6.pgm;11
/home/philipp/facerec/data/at/s12/9.pgm;11
/home/philipp/facerec/data/at/s12/5.pgm;11
/home/philipp/facerec/data/at/s12/3.pgm;11
/home/philipp/facerec/data/at/s12/4.pgm;11
/home/philipp/facerec/data/at/s12/10.pgm;11
/home/philipp/facerec/data/at/s12/8.pgm;11
/home/philipp/facerec/data/at/s12/1.pgm;11
/home/philipp/facerec/data/at/s6/2.pgm;5
/home/philipp/facerec/data/at/s6/7.pgm;5
/home/philipp/facerec/data/at/s6/6.pgm;5
/home/philipp/facerec/data/at/s6/9.pgm;5
/home/philipp/facerec/data/at/s6/5.pgm;5
/home/philipp/facerec/data/at/s6/3.pgm;5
/home/philipp/facerec/data/at/s6/4.pgm;5
/home/philipp/facerec/data/at/s6/10.pgm;5
/home/philipp/facerec/data/at/s6/8.pgm;5
/home/philipp/facerec/data/at/s6/1.pgm;5
/home/philipp/facerec/data/at/s22/2.pgm;21
/home/philipp/facerec/data/at/s22/7.pgm;21
/home/philipp/facerec/data/at/s22/6.pgm;21
/home/philipp/facerec/data/at/s22/9.pgm;21
/home/philipp/facerec/data/at/s22/5.pgm;21
/home/philipp/facerec/data/at/s22/3.pgm;21
/home/philipp/facerec/data/at/s22/4.pgm;21
/home/philipp/facerec/data/at/s22/10.pgm;21
/home/philipp/facerec/data/at/s22/8.pgm;21
/home/philipp/facerec/data/at/s22/1.pgm;21
/home/philipp/facerec/data/at/s15/2.pgm;14
/home/philipp/facerec/data/at/s15/7.pgm;14
/home/philipp/facerec/data/at/s15/6.pgm;14
/home/philipp/facerec/data/at/s15/9.pgm;14
/home/philipp/facerec/data/at/s15/5.pgm;14
/home/philipp/facerec/data/at/s15/3.pgm;14
/home/philipp/facerec/data/at/s15/4.pgm;14
/home/philipp/facerec/data/at/s15/10.pgm;14
/home/philipp/facerec/data/at/s15/8.pgm;14
/home/philipp/facerec/data/at/s15/1.pgm;14
/home/philipp/facerec/data/at/s2/2.pgm;1
/home/philipp/facerec/data/at/s2/7.pgm;1
/home/philipp/facerec/data/at/s2/6.pgm;1
/home/philipp/facerec/data/at/s2/9.pgm;1
/home/philipp/facerec/data/at/s2/5.pgm;1
/home/philipp/facerec/data/at/s2/3.pgm;1
/home/philipp/facerec/data/at/s2/4.pgm;1
/home/philipp/facerec/data/at/s2/10.pgm;1
/home/philipp/facerec/data/at/s2/8.pgm;1
/home/philipp/facerec/data/at/s2/1.pgm;1
/home/philipp/facerec/data/at/s31/2.pgm;30
/home/philipp/facerec/data/at/s31/7.pgm;30
/home/philipp/facerec/data/at/s31/6.pgm;30
/home/philipp/facerec/data/at/s31/9.pgm;30
/home/philipp/facerec/data/at/s31/5.pgm;30
/home/philipp/facerec/data/at/s31/3.pgm;30
/home/philipp/facerec/data/at/s31/4.pgm;30
/home/philipp/facerec/data/at/s31/10.pgm;30
/home/philipp/facerec/data/at/s31/8.pgm;30
/home/philipp/facerec/data/at/s31/1.pgm;30
/home/philipp/facerec/data/at/s28/2.pgm;27
/home/philipp/facerec/data/at/s28/7.pgm;27
/home/philipp/facerec/data/at/s28/6.pgm;27
/home/philipp/facerec/data/at/s28/9.pgm;27
/home/philipp/facerec/data/at/s28/5.pgm;27
/home/philipp/facerec/data/at/s28/3.pgm;27
/home/philipp/facerec/data/at/s28/4.pgm;27
/home/philipp/facerec/data/at/s28/10.pgm;27
/home/philipp/facerec/data/at/s28/8.pgm;27
/home/philipp/facerec/data/at/s28/1.pgm;27
/home/philipp/facerec/data/at/s40/2.pgm;39
/home/philipp/facerec/data/at/s40/7.pgm;39
/home/philipp/facerec/data/at/s40/6.pgm;39
/home/philipp/facerec/data/at/s40/9.pgm;39
/home/philipp/facerec/data/at/s40/5.pgm;39
/home/philipp/facerec/data/at/s40/3.pgm;39
/home/philipp/facerec/data/at/s40/4.pgm;39
/home/philipp/facerec/data/at/s40/10.pgm;39
/home/philipp/facerec/data/at/s40/8.pgm;39
/home/philipp/facerec/data/at/s40/1.pgm;39
/home/philipp/facerec/data/at/s3/2.pgm;2
/home/philipp/facerec/data/at/s3/7.pgm;2
/home/philipp/facerec/data/at/s3/6.pgm;2
/home/philipp/facerec/data/at/s3/9.pgm;2
/home/philipp/facerec/data/at/s3/5.pgm;2
/home/philipp/facerec/data/at/s3/3.pgm;2
/home/philipp/facerec/data/at/s3/4.pgm;2
/home/philipp/facerec/data/at/s3/10.pgm;2
/home/philipp/facerec/data/at/s3/8.pgm;2
/home/philipp/facerec/data/at/s3/1.pgm;2
/home/philipp/facerec/data/at/s38/2.pgm;37
/home/philipp/facerec/data/at/s38/7.pgm;37
/home/philipp/facerec/data/at/s38/6.pgm;37
/home/philipp/facerec/data/at/s38/9.pgm;37
/home/philipp/facerec/data/at/s38/5.pgm;37
/home/philipp/facerec/data/at/s38/3.pgm;37
/home/philipp/facerec/data/at/s38/4.pgm;37
/home/philipp/facerec/data/at/s38/10.pgm;37
/home/philipp/facerec/data/at/s38/8.pgm;37
/home/philipp/facerec/data/at/s38/1.pgm;37

 

C#版的人臉識別(只實現了特徵臉)EMGU Multiple Face Recognition using PCA and Parallel Optimisatioin:

 http://www.codeproject.com/Articles/261550/EMGU-Multiple-Face-Recognition-using-PCA-and-Paral?msg=4377858

 

 

 

出處:https://www.cnblogs.com/guoming0000/archive/2012/09/27/2706019.html

相關文章
相關標籤/搜索