2019年6月10日 星期一

Face Detection with EmguCV Haar and DNN


過去在EmguCV (OpenCV)中

人臉偵測是常用且簡單的功能

過去都是使用Haar cascades的方法來實作

但在OpenCV 3.3.1之後,提供了DNN深度學習的人臉偵測方法

來比較看看吧!!



過去常用的Haar cascades方法需要讀入相對應的分類文件

在OpenCV的github中有提供相當多的類型可以下載

除了人臉之外還有相當多種類可以下載回來測試

https://github.com/opencv/opencv/tree/master/data/haarcascades

而人臉偵測中最常用的是:haarcascade_frontalface_alt2.xml


程式碼非常簡單,在EmguCV的Example裡面都有

這裡簡化一下FaceDetection的程式碼如下:


這個方法僅需帶入要偵測人臉的影像image、

Haar cascades的文件檔路徑、以及一個人臉資訊(Rectangle)的集合

程式的邏輯就是先建立一個CascadeClassifier (cascade分類器)

建構式載入Haar cascades的文件檔

接著將影像從RGB轉成Gray (灰階)

原本的Sample這裡會加入一個EqualizeHist的方法,但我實測是不加入的效果比較好

最後呼叫CascadeClassifier的DetectMultiScale的方法

帶入轉換後的灰階影像以及參數 (預設是1.1、3)

接著把所偵測到的人臉的資訊 (Rectangle)存入faces的List中


我們測試網路上抓的40張藝人照片


看是否都能順利抓到人臉的位置

並把抓到人臉的部分另存成jpg方便進行比較

處理的程式碼如下:


DetectFace.Detect這個方法就是上面提供的人臉偵測的方法

把讀取資料夾中的影像傳入,並帶入haarcascade_frontalface_alt2.xml (檔案需放在執行目錄下)

若是偵測的人臉的長寬皆超過60 pixels才進行處理

這裡處理的動作是進行resize到160x160
(未來在解釋為什麼要resize到160x160)

接著另存檔案到result資料夾

然後來看看結果:

看起來是有抓到不少人臉

但是也有很多不是人臉的部分... XDD

這邊建議DetectMultiScale的參數改成帶入1.3、3 試試看

錯誤率降低了不少,來看看結果:

錯誤率是大幅降低了,但人臉偵測出來的結果就少了一些

統計一下執行人臉偵測方法的平均時間,以及抓取率

Haar cascades 1.1偵測方法: 526ms, 人臉抓取率: 33/40, 人臉錯誤率: 17/50

Haar cascades 1.3偵測方法: 327ms, 人臉抓取率: 30/40, 人臉錯誤率: 3/33

抓取率只有75%~82.5%,錯誤率9%~34%

這樣的結果,僅能算是堪用吧...

而且效能也不太好

過去若要提升人臉偵測的效能,需在影像傳入Detect前,先進行resize的動作

即可減少運算時間


而在OpenCV 3.3.1 後導入了深度學習(DNN)的模組,

包含了:tensorflow、caffe、darknet
(你沒看錯,連darknet都有!!)

而tensorflow、keras提供了人臉偵測的方法和模型

模型的下載位置可以參考這裡:
(此專案也有C++跟Python的程式碼可參考)

https://github.com/spmallick/learnopencv/tree/master/FaceDetectionComparison/models

主要下載這四個檔案

紅色圈選的是caffe的模型和參數檔

綠色則是tensorflow的模型和參數檔

執行的程式碼可參考下圖:


程式稍微複雜一點

這份程式,應該是世界上第一篇用EmguCV寫的DNN人臉偵測的範例分享了!
(網路上只找得到C++跟Python ...)

簡單來說,就是先建立Net物件,建立方法使用

DnnInvoke.ReadNetFromTensorflow({模型檔案(.pb)}{參數檔(.pbtxt)})

接著進行影像的轉換,把原先EmguCV的Image.Mat轉換成Net可以處理的Mat

使用方法為

Mat inputBlob = DnnInvoke.BlobFromImage(image, 1.0, new Size(300, 300),
                new MCvScalar(104.0, 117.0, 123.0), true, false);

這裡Size設定為300x300,則是根據DNN model訓練時的影像大小

而剛剛下載的opencv_face_detector_uint8.pb就是使用300x300的大小

網路上很多參數給的都是錯誤的值

所以直接參考我這邊的寫法即可!


接著設定input,執行Forward後取得運算結果detection

這裡的結果會是一個4維陣列[1, 1, {face count}, 7]

我們只要取出第三跟第四維的資料

利用以下方法,把2維資料轉存到一個1維的陣列temp

int resultRows = detection.SizeOfDimemsion[2]; //偵測到的人臉數量
 int resultCols = detection.SizeOfDimemsion[3]; //人臉偵測結果的值(7個)
 float[] temp = new float[resultRows * resultCols];
Marshal.Copy(detection.DataPointer, temp, 0, temp.Length);

接著透過for迴圈,把所有人臉偵測的結果都取出

人臉偵測結果的值共七個[0, 1, 2, 3, 4, 5, 6, 7]

其中第三個值(2的位置):人臉偵測的信任分數,越高表示越像人臉
(越低就可能不是人臉)

float confidence = temp[i * resultCols + 2];

confidence 的閥值可設定在0.6~0.8之間

高過閥值的,再進行人臉位置(rectangle)的擷取

第四~七的值(3,4,5,6的位置)分別代表人臉的左上角x、y,右下角x、y的比例

因此計算方式把值取出後,需要再乘上影像的長或寬,才會是實際的座標值


例如其中一筆的結果如下:

[0, 1, 0.89, 0.51, 0.22, 0.59, 0.30]

紅色0.89就是人臉偵測的信任分數

這張測試照片的影像寬高分別是13642048,因此計算出來的座標會是:

(1364x0.51, 2048x0.22)、(1364x0.59, 2048x0.30) = (696, 467)、(811, 632)

這兩個點所包圍的矩形,就是人臉的位置

一樣透過之前的測試,把人臉偵測的方法改成剛剛DNN的方式

讀取40張藝人的照片並另存人臉的照片出來比較,結果如下:


有沒有看到這驚人的結果!! 幾乎沒有發生抓錯的!!

統計資料如下:

DNN tensorflow偵測方法: 79ms, 人臉抓取率: 39/40, 人臉錯誤率: 0

抓取率: 97.5%,錯誤率是0


若想要改用caffe的方法

就把剛剛tensorflow的程式碼

前面兩段改成:
(注意紅色標記的部分)

net = DnnInvoke.ReadNetFromCaffe(
                  @"model\deploy.prototxt",
                  @"model\res10_300x300_ssd_iter_140000_fp16.caffemodel");

Mat inputBlob = DnnInvoke.BlobFromImage(image, 1.0, new Size(300, 300),
                new MCvScalar(104.0, 117.0, 123.0), false, false);

其他程式都是一樣的

DNN Caffe偵測方法: 78ms, 人臉抓取率: 38/40, 人臉錯誤率: 0

抓取率: 95%,也是非常高!


這個實測的結果真的讓人大吃一驚

採用DNN演算法的方式,偵測的結果比較好可以理解

但連效能竟然還比傳統的Haar cascades 還快!!

在同樣採用i7-8650U CPU的運算

Haar cascades 帶入1.3的參數,平均一張影像處理耗時要300多ms

而DNN演算法僅需70多ms


這真的是非常驚人的進步和成果呀!!

傳統Haar cascades演算法過去為人詬病的偵測率和錯誤率

在DNN深度學習的方法下

完全改進缺點,還提高效率,是不是非常令人驚艷呢!!

4 則留言:

  1. 你好, 我照著你上方的指導, 但我在DNNINVOKE要把.pb那些讀出時,就會出現無法open的問題
    Emgu.CV.Util.CvException: 'OpenCV: FAILED: fs.is_open(). Can't open "model\opencv_face_detector_uint8.pb"'

    請問你也有遇到類似問題或者知道我哪出問題了呢?? 謝謝

    回覆刪除
    回覆
    1. 要不要檢查一下model檔案的路徑,有確定把.pb跟pbtxt放在執行目錄裡面model資料夾中嗎?

      刪除
  2. 你好,看了你的文章有一些設定不太清楚,方便交換mail或是line請教嗎??

    回覆刪除
  3. 你好,我也是看你的文章執行,但還是沒辦法完成,方便交換mail或是line請教嗎??

    回覆刪除