1. 程式人生 > >C#人臉識別、人臉68特徵點識別

C#人臉識別、人臉68特徵點識別

  幾年前我接觸的計算機視覺學習庫emgucv、aforge.net因為識別率低誤差大,加上我沒有時間去訓練模型因此關於人臉識別領域被我擱置了很久,

直到今年我接觸了dlib,從效果演示來看讓我非常滿意特別是它可以匹配出人臉的68個特徵點(包括眼睛、眉毛、鼻子、嘴巴等)於是我就想將它用到C#

上(早前我封裝過C++),大約花費了兩週時間從編譯官方demo到移植成功,中間遇到各種坑(C++各種指標、對應C#型別轉換、編譯環境配置等等),

中間無數次想過放棄但是出於對於這項技術的需要我還是堅持了下來,今天終於成功將dlib運用到了C#上提取了68個特徵點並繪製出來效果還是讓人滿意的,

本文將簡述下實現移植的大概步驟希望能幫助需要的人。

工具準備:

視覺學習庫:opencv、emgucv、dlib

編譯工具:visual studio 2017 、CMake

作業系統:Win10 64位

環境配置:

請參考我這篇dlib、opencv的文章 http://www.cnblogs.com/dongzhaosheng/p/8568163.html

跨語言相容方案:

      dlib提供了兩種語言一個是C++庫 ,另一個是python庫(為此我還特意去學了幾天python),首先我想到了用python封裝,但是結果我失敗了聽說python是膠水語言實質上它是把其它語言沾到自己身上,要是想把python

融合到其它語言上恐怕你還得下功夫想想怎麼才能粘的沒有縫。這裡提供一個目前C#引用python的方案InronPython,我嘗試了用它去呼叫python裡的方法很遺憾現在python都已經3.0了 該容器還是2.x的解決方案,因此

第三方庫我根本掉不到也沒法封裝,因此該方案被我pass了。當然你可以用python來寫你自己的專案如果不要是要求即時輸出的話可以將資料儲存到目錄再讀回來。

     第二種方案就是用C++來封裝dll給C#呼叫畢竟是自己平臺的東西所以相容方面肯定沒問題,封裝C++方案一共3種:DllImport、利用CLI 編寫的C++要符合CLS規範(雖然是C++專案裡編寫但是用到的幾乎沒有C++的型別)、

利用Component Object Model (COM元件物件模型)的方式包裝這也是windows底層大部分外掛的構成方式。

①DllImport 最簡單跟呼叫系統API一樣就可以完成封裝好的方法,但是缺點是隻能是靜態方法,難以對內部物件直接進行控制(不好做前期的初始化或者釋放)

[DllImport(“user32.dll”,CharSet = CharSet.Unicode)]
public  static  extern  int MessageBox(IntPtr hWnd,String text,String caption,uint type);

②CLI 編寫dll 但是要用CLS規範的型別來寫,優點是可以做到無縫銜接只要成功編寫到C#中就可以像平時操作其它類的方式來操作,但是對於不熟悉C++的C#工程師或者不熟悉面向物件的C++工程師都是一種煎熬,並且對於呼叫第三方庫並不是很友好我經過

多番嘗試無法編譯後(需要相容太多寫法)只好放棄。

③最後我選擇的方案也是CLI,可是微軟幫我們提供了一種非常便捷的包裝方式,它不需要你搭建非常複雜的介面轉換隻需要利用ATL嚮導即可輕鬆完成一個方法或者物件的建立,然後你只要在繼承介面的方法中寫實現過程即可,但是你要滿足輸出輸入格式因為com為相容語言

型別是中間型別(關於C#跟C++ATL的型別轉換可自行查閱)。

實現思路:

   因為人臉識別與特徵識別都不是我實現的,我只是利用dlib機器學習庫的現成函式拼湊的功能,但是從C++移植到C#的大致方式我還是要說下因為現在網上還沒有看到比較完整的解決方案。首先就是型別轉換字元型沒什麼好說的BSTR在C#裡對應的就是string,到了

c++中有現成的轉換函式_com_util::ConvertBSTRToString,然後是人臉識別傳入的影象資料首先我想到的就是將影象指標直接傳入然後到C++中完成影象初始化,經過多方資料查閱後我查到原來C#的emgucv裡的影象指標可以直接到C++的opencv裡轉成需要的Mat型別

因為他們都符合IplImage規範,指標的傳遞可以用LRESULT來完成C#裡看到的是一個long型資料。

   關於輸出結果很多人傾向於在C++裡完成影象操作然後直接將影象返回到C#,但是如果我只想取得人類資料結構呢?我這裡使用的可以序列號與反序列化的json,在c++裡將得到的人臉模型轉成json格式再到C#裡反序列化拿到例項即可,C++沒有C#那麼方便的Json轉換工具只有一個rapidjson庫(一個臺灣同胞寫的第三方庫)。

rapidjson::Document jsonDoc;
rapidjson::Document::AllocatorType &allocator = jsonDoc.GetAllocator(); //獲取分配器
jsonDoc.SetArray();
/////
插入資料過程
////
rapidjson::StringBuffer buffer;
        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
        jsonDoc.Accept(writer);

        std::string strJson = buffer.GetString();

封裝好後就可以直接在C#裡進行呼叫了

NaughtyKidATLLib.NaughtyKidDlibClass dlib = new NaughtyKidDlibClass();

//初始化資料檔案
  var a = dlib.InitialDat($"{System.IO.Directory.GetCurrentDirectory()}\\shape_predictor_68_face_landmarks.dat");

//返回特徵點
 System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            Image<Bgr, Byte> img3 = new Image<Bgr, Byte>(System.IO.Directory.GetCurrentDirectory() + "\\temp.jpg");

            watch.Start();//開始計時
            var b = dlib.GetFaceModel((long)img3.Ptr);
            var models = NaughtyKid.MyTools.SerializationHelper.ScriptDeserialize<List<Face>>(b);
            
            watch.Stop();//停止計時

COM下載與註冊:

連結: https://pan.baidu.com/s/1hWHOStcZtSHJdTsFdQ_Qag 提取碼: jwkx 

註冊環境:Microsoft Visual C++ Redistributable for Visual Studio 2017 最新版本14.13 或以上

註冊方法:該dll為64為dll 進入cmd(管理員方式執行)進入c:\Windows\SysWOW64\下  通過regsvr32  dll所在路徑(NaughtyATL.dll不是opencv那個但是兩者必須位於同一目錄下)

註冊成功後方可在C#引用中COM裡找到NaughtyATL