如何訓練一個貓臉偵測器

本文介紹如何製作及訓練自己的Cascade Classifier,並且撰寫成工具程式來方便且快速的訓練。

What is Cascade Classifier?

Opencv使用的Object detection技術稱為Cascade Classifier for Object Detection ,屬於一種boosted cascade of weak classifiers的方法,也就是將數個弱分類器串聯起來再得出最佳的分類結果。最早整合到Opencv並支援的分類特徵是哈爾特徵(Haar-like features),後來加入了 LBP ( Local Binary Pattern)以及 HOG( Histogram Of Gradient),不過可惜的是HOG在3.x之後由於某些技術問題被取消無法使用。

Boosting的中心思想在於三個臭皮匠勝過一個諸葛亮,將大量的弱分類器(分類效果僅比隨機好一點)逐步訓練成一個較強的分類器,方式是針對每個弱分類器所分類錯誤部份再持續投入學習,最後形成一個超強的分類器。舉例來說,我們熟知的Spam mails檢測,其實它就是一種Boosting概念,拆開,每一條spam check rule都是弱分類器,僅能針對一小部份垃圾郵件有效,但是把所有數以百計的rules串連起來,就能打造一個滴水不漏的垃圾郵件防堵系統,這不是Boosting和Cascade的最好說明嗎?

在機器學習中,有很多分類器憑應用了Boosting的方法,例如:AdaBoost (Adaptive Boosting)、Gradient Tree Boosting、XGBoost…等, Opencv所內建的Cascade Classifier for Object Detection,就是應用了AdaBoost。

新版OpenCV對於Cascade Classifier的支援

比較可惜的是OpenCV 4.X版開始不再支援Cascade Classifier的訓練,因此,在4.X版的OpenCV程式碼中已經找不到諸如opencv_createsamples、opencv_traincascade等程式,官方的說法是近幾年流行的ML、DL效果更佳,鑒於使用者日少所以原始碼中不再包入相關的訓練程式。不過,事實上目前還是有相當多的使用者對於cascade classifier有強烈需求,至少對於某些人來說,它的優點如使用方便及偵測速度快,可讓人包容誤報率高訓練複雜的缺點。因此,聽說在下一版本OpenCV官方可能會再度支援。

訓練貓臉偵測器

我撰寫了一套工具程式https://github.com/ch-tseng/cascade_opencv_train.git 可快速方便的進行Cascade Classifier的訓練,以下以貓臉偵測示範如何使用這工具製作自己的cascade classifier。

  • 搜集相片及標記

先從網路上下載一些貓的相片,本例中我下載了126張。

  1. 使用labelImg進行標記。由於貓臉區域不像人臉那麼明確,因此,在框選時我選擇從兩眼外側(不包含耳朵)開始直到下巴的區域。
  • 準備dataset

此步驟將產生訓練時需要的positives(正向圖片檔,即標記的貓臉)以及negatives(負向圖片檔,即沒有貓臉的圖片)。

  1. Step1: 所有相片及標記好的label檔分別於置於images及labels資料夾中。

voc_dataset        — images

                                — labels

  1. Step2: 執行1_labels_to_pos_neg_imgs.py

此程式目的是將所有相片中的標記框取出另外存到一個folder下,這些圖片稱為positives,圖片中不含標記框的其它區域則存到neg_bg資料夾中,這些與貓臉無關的圖片稱為negatives。

1_labels_to_pos_neg_imgs.py的參數如下,您只要修改參數的內容即可。

#標記檔的path

xmlFolder = “H:\\working\\cascade_cat_face\\voc_dataset\\labels"

#圖片檔的path

imgFolder = “H:\\working\\cascade_cat_face\\voc_dataset\\images"

#要取出的標記名稱(class name)

labelName = “catface"

#專案目錄,所有產生的檔案或目錄皆會存於此

projFolder = “H:\\working\\cascade_cat_face\\cascade_training"

#訓練的圖片大小(建議不要太大)

outputSize = (54, 45)

#產生的訓練圖片類型

imageKeepType = “jpg"

#去除標記區域的圖片,是否要作為negative圖片?

generateNegativeSource = True

                執行成功後,會產生下列兩個目錄:

                positives:正向圖片,所有標記的貓臉。

neg_bg:不含貓臉標記的圖片,將用於負向圖片。我把有貓臉的區域以黑色取代,剩下區域則可作為負面圖片來使用。

  1. Step3: 執行2_generate-negatives.py

本程式功能為使用sliding window方式,把neg_bg資料夾下的相片切裁為指定大小的negatives圖片,並產生一個negatives.info檔案。

#專案目錄,所有產生的檔案或目錄皆會存於此

projFolder = “H:\\working\\cascade_cat_face\\cascade_training"

#sliding window移動距離

movePixels = 80

#sliding window時圖片依次的縮小比例

resizeScale = 0.5

#裁切出的圖片大小

negSize = (54, 45)

#載切後儲存的圖片格式

imageKeepType = “jpg"

#neg_bg folder下的圖片要不要先縮小為指定尺寸? 0–> keep the same

resize_org_w = 0

#要產生多少負向的圖片?

imagesCount = 8000

                negatives資料夾內容:

negatives.info檔案內容:

H:\working\cascade_cat_face\cascade_training\negatives\1580366317.81161742.jpg

H:\working\cascade_cat_face\cascade_training\negatives\1580366317.81961253.jpg

H:\working\cascade_cat_face\cascade_training\negatives\1580366317.83462724.jpg

H:\working\cascade_cat_face\cascade_training\negatives\1580366317.84162245.jpg

H:\working\cascade_cat_face\cascade_training\negatives\1580366317.8586116.jpg

H:\working\cascade_cat_face\cascade_training\negatives\1580366317.86569797.jpg

  1. Step4: 執行3_augmentation.py

本程式使用augmentation強化資料方式產生更多正向圖片,新增加的圖片放置於aug_positives資料夾下。

#專案目錄,所有產生的檔案或目錄皆會存於此

projFolder = “H:\\working\\cascade_cat_face\\cascade_training"

#產生的正向圖片大小

outputSize = (54, 45)

#產生的圖片格式

imageKeepType = “jpg"

#每一個正向圖片要產生出幾張新圖片?

numAugment = 3

#Augmentation的設定

aug_whitening = False

aug_rotation = 16

aug_w_shift = 0.1

aug_h_shift = 0.1

aug_shear = 0.1

aug_zoom = 0.05

aug_h_flip = True

aug_v_flip = False

aug_fillmode = “nearest"

                產生的圖片如下,原本僅有243張,,透過augmentation增加了929張。

  1. Step5:執 行4_add_aug_positives_to_list.py

將前一步所產生的圖片放到positives.info檔案,其內容截錄如下。

positives/aug__0_4419.jpg  1  0 0 54 45

positives/aug__0_584.jpg  1  0 0 54 45

positives/aug__0_5614.jpg  1  0 0 54 45

positives/aug__0_402.jpg  1  0 0 54 45

positives/aug__0_7285.jpg  1  0 0 54 45

positives/aug__0_710.jpg  1  0 0 54 45

positives/aug__0_4390.jpg  1  0 0 54 45

        最終待訓練用的資料夾及其下檔案如下:

  • 產生訓練用的VEC檔

Cascade Classifier不能直接讀取圖片檔,我們必須轉為VEC檔案才能開始訓練。

  1. 進入專案目錄:H:\working\cascade_cat_face\cascade_training

cd H:\working\cascade_cat_face\cascade_training

  1. 執行opencv_createsamples.exe

H:\opencv\build\x64\vc15\bin\opencv_createsamples.exe -info positives.info -vec samples.vec -w 54 -h 45 -num 1790

若出現如下方的error message,表示某個圖檔有問題,建議直接從positives.info列表中刪除該檔案,例如下方為第229行的圖檔有問題,直接刪除該行。

再執行一次opencv_createsamples.exe便可成功轉換後,最後是如下畫面:

  • 開始訓練

  1. 進入專案目錄:H:\working\cascade_cat_face\cascade_training

cd H:\working\cascade_cat_face\cascade_training

  1. 執行下方的指令:

H:\opencv\build\x64\vc15\bin\opencv_traincascade.exe  -data H:\working\cascade_cat_face\cascade_training -vec samples.vec -bg negatives.info -numPos 1700 -numNeg 7000 -numStages 8 -minHitRate 0.995 -maxFalseAlarmRate 0.3 -w 54 -h 45 -featureType LBP

  1. 重點:
  • 訓練stange的數目由-numStages指定。
  • HR(Hit Rate, 偵測到物件)、FA(False Alarm, 錯誤的偵測到物件,即誤判)此兩個值分別由-minHitRate和-maxFalseAlarmRate指定,訓練結果滿足兩個值該Stage結束。
  • -featureType可指定為HAAR或LBP,目前較流行的是LBP,訓練速度較快且偵測效果不亞於HAAR。
  • 由上圖中可看到訓練的時間相當的長,如果將-featureType改為HAAR,則訓練時間會比LBP要多出好幾倍。

訓練結果(LBP)

  • 這次測試,我們總共標記了126張相片,約有241張貓臉正樣本,再透過資料強化擴增到1,794張,        搭配7,059張負樣本進行OpenCV Cascade Classifier的LBP訓練。
  • Total訓練了7 stages,總訓練時間為5小時36分41秒

我另外找了11張相片作為test圖片,使用訓練完成所產生的cascade xml測試其效果如下,若能繼續增加更多的貓臉正樣本,應可提高辨識的效果。

效果還不錯的

只偵測出部份的

Bounding box大小位置有待加強的

False Alarm