基於深度學習的人臉識別系統系列(Caffe+OpenCV+Dlib)——【六】設計人臉識別的識別類

ChenJoya發表於2016-10-01

前言

基於深度學習的人臉識別系統,一共用到了5個開源庫:OpenCV(計算機視覺庫)、Caffe(深度學習庫)、Dlib(機器學習庫)、libfacedetection(人臉檢測庫)、cudnn(gpu加速庫)。
用到了一個開源的深度學習模型:VGG model。
最終的效果是很讚的,識別一張人臉的速度是0.039秒,而且最重要的是:精度高啊!!!
CPU:intel i5-4590
GPU:GTX 980
系統:Win 10
OpenCV版本:3.1(這個無所謂)
Caffe版本:Microsoft caffe (微軟編譯的Caffe,安裝方便,在這裡安利一波)
Dlib版本:19.0(也無所謂
CUDA版本:7.5
cudnn版本:4
libfacedetection:6月份之後的(這個有所謂,6月後出了64位版本的)
這個系列純C++構成,有問題的各位朋同學可以直接在部落格下留言,我們互相交流學習。
====================================================================

本篇是該系列的第六篇部落格,介紹如何設計一個識別類來用於具體的分類任務。

思路

現在我們希望能夠有一個識別的介面來實現輸入一張圖片,便可以分辨出他是哪個人。我們需要提前:
1、定義一個人臉空間;
2、將一些人臉的圖片放到這個人臉空間中;
3、將n個人臉圖片提取特徵為n個向量,並且合併為一個矩陣;
4、將n個人臉圖片的標註(label)合併為一個向量,與矩陣形成對應;
5、將其序列化並儲存起來,等待識別時進行讀取。

在前五篇部落格中,我們已經可以很方便的來完成這些事情了。程式碼如下:

vector<Mat> imgArray;
    vector<string> labelArray;
    for ( int i = 0; i < 5; i++)//讀入5張圖片
    {
        string img_file = "img/" + Int_String(i) + ".jpg";
        Mat img = imread(img_file);
        imgArray.push_back(img);
        labelArray.push_back(img_file);
    }
    Register Train;

    for (int j = 0; j < 5; j++)
        Train.JoinFaceSpace(imgArray[j], "MySpace", labelArray[j]);

人臉空間的名字為:MySpace;每一個人臉的名稱都用它們的檔案路徑直接來代替。
我們來看看這五張人臉:
這裡寫圖片描述
我們來看看儲存後的結果:
這裡寫圖片描述

程式碼

設計一個類,希望其具有讀入訓練檔案,讀入新圖片,進行匹配的功能。
Register.h:

class Recognition
{
public:

    vector<string> NameVector;

    //vector
    void LoadVector(string FaceSpace);//讀入資料,儲存的名稱為FaceSpace_FaceVector/FaceSpace_FaceName
    void LoadRecognitionModel(vector<vector<float>> FaceMatrix, vector<string> NameVector);//建立識別模型,需要輸入FaceMarix,NameVector.
    string Predict(Mat LoadGetFace);//預測
    //用法: Recognition test; test.LoadRecognitionModel();cout<<test->predict(Mat) ; test.update()
    void clear();
    void update(vector<vector<float>> FaceMatrix, vector<string> NameVector);//change .
    vector<vector<float>> FaceMat;

private:
    vector <vector<float>> ReadVector (string FaceSpace);//input FaceSpace ,read to get vector <vector<float>>
};

函式的具體程式碼:
Register.cpp:

void Recognition::LoadVector(string FaceSpace) // save the people's  face vector
{
    string FaceVectorRoad = "data/" + FaceSpace + "_FaceMatrix.xml";
    string NameVectorRoad = "data/" + FaceSpace + "_NameVector.txt";
    vector<vector<float> >  FaceVector;
    FaceVector = LoadFaceMatrix(FaceVectorRoad);
    NameVector=LoadNameVector(NameVector, NameVectorRoad);
    if (!FaceVector.empty() && !NameVector.empty())
    {
        FaceMat = FaceVector;
        NameVector = NameVector;
        cout << "Sucessfully read the FaceSpace:" + FaceSpace + "'s data!" << endl;
    }
    else { cout << "There is no data in this FaceSpace:" + FaceSpace + ",Please input ." << endl; }
}

string Recognition::Predict(Mat LoadGetFace)//可優化,using CUDA TO COMPUTE
{
    if (!LoadGetFace.empty())
    {
        vector<float> v = ExtractFeature(FaceDetect(LoadGetFace));
        if (!v.empty())
        {
            int ID = -1;
            float MaxCos = 0;
            for (int i = 0; i < NameVector.size(); i++)
            {
                float t_cos = cosine(v, FaceMat[i]);
                if (t_cos > MaxCos)
                {
                    ID = i;
                    MaxCos = t_cos;//update the coff
                }
            }
            return NameVector[ID];
        }
        else
        {
            cout << "The Picture does not have people's Face,Please try again." << endl;
        }
    }
    else cout << "The picture is empty.Please Check it and make sure." << endl; 

}

void Recognition::LoadRecognitionModel(vector<vector<float>> FaceMatrix, vector<string> NameVector_)//建立識別模型,需要輸入FaceMarix,NameVector.
{
    if (!FaceMatrix.empty() &&!NameVector_.empty())
    {
        FaceMat = FaceMatrix;
        NameVector = NameVector_;
    }
    else
    {
        cout << "Please check your FaceMatrix and NameVector.It may be empty." << endl;
    }
}

void Recognition::clear()
{
    FaceMatrix_ = NULL;
    NameVector.clear();
}

void Recognition::update(vector<vector<float>> FaceMatrix, vector<string> NameVector)
{
    clear_();
    LoadRecognitionModel(FaceMat, NameVector);
}

得益於前幾篇裡我們已經建立好的介面,那麼在主函式裡,就只需幾行即可。

Recognition Val;

    Val.LoadVector("MySpace");
    Val.LoadRecognitionModel(Val.FaceMat, Val.NameVector);
    Mat test = imread("test.jpg");
    cout << "圖片對應的訓練樣本為: ";
    cout<<Val.Predict(test)<<endl;
    imshow("Face Recognition", test);
    waitKey(0);

執行看看結果:
這裡寫圖片描述
匹配是完全正確的。(可以看看註冊時候的幾張圖片,對比一下)

至此,實現一個人臉識別任務的主要手段已經都完成了。接下來的幾篇將從如何美化程式介面,如何加速人臉匹配速度來入手。如果可能的話,後面還可以寫一下怎麼微調這個神經網路讓其在自己的資料集上來進行更高精度的識別。

=================================================================

基於深度學習的人臉識別系統系列(Caffe+OpenCV+Dlib)——【六】設計人臉識別的識別類 完結,如果在程式碼過程中出現了任何問題,直接在部落格下留言即可,共同交流學習。

相關文章