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 的方法,例如 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 中再度支持。
訓練貓臉偵測器
特意編寫了一套工具程序可快速方便地進行 Cascade Classifier 的訓練,以下以貓臉偵測示範如何使用這個工具製作自己的 Cascade Classifier。
蒐集照片和標記
1. 先從網絡上下載一些貓的照片,本例中下載了 126 張。
2. 使用 labelImg 進行標記:由於貓臉區域不像人臉那麼明確,因此在框選時選擇從兩眼外側(不包含耳朵)開始直到下巴的區域。
準備 dataset
此步驟將產生訓練時需要的positives(正向圖片,即標記的貓臉)以及 negatives(負向圖片,即沒有貓臉的圖片)。
1. 所有相片及標記好的 label 分別置於 images 及 labels 的文件夾中。
2. 執行 1_labels_to_pos_neg_imgs.py:此程序的目的是將所有相片中的標記框取出,另外存到一個folder 下,這些圖片稱為 positives,圖片中不含標記框的其它區域則存到 neg_bg 資料夾中,這些與貓臉無關的圖片稱為 negatives。1_labels_to_pos_neg_imgs.py 的參數如下,您只要修改參數的內容即可:
<code>#標記檔的pathxmlFolder = “H:\\\\working\\\\cascade_cat_face\\\\voc_dataset\\\\labels”#圖片檔的pathimgFolder = “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/<code>
執行成功後,會產生以下兩個目錄:positives(正向圖片),含有貓臉標記的圖片;neg_bg(負向圖片),不含貓臉標記的圖片(我把有貓臉的區域以黑色色塊取代,就能作為負面圖片來使用)。
3. 執行 2_generate-negatives.py:本程序使用 sliding window 的方式,將 neg_bg 文件夾下的相片切裁為指定大小的 negatives 圖片,併產生一個 negatives.info 文件。
<code>#項目目錄,所有產生的檔案或目錄皆會存於此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 sameresize_org_w = 0#要產生多少負向的圖片?imagesCount = 8000/<code>
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
4. 執行 3_augmentation.py:本程序使用 augmentation 強化資料的方式產生更多正向圖片,新增加的圖片將放置於 aug_positives 文件夾下。
<code>#項目目錄,所有產生的文檔或目錄皆會存於此projFolder = “H:\\\\working\\\\cascade_cat_face\\\\cascade_training”#產生的正向圖片大小outputSize = (54, 45)#產生的圖片格式imageKeepType = “jpg”#每一個正向圖片要產生出幾張新圖片?numAugment = 3#Augmentation的設定aug_whitening = Falseaug_rotation = 16aug_w_shift = 0.1aug_h_shift = 0.1aug_shear = 0.1aug_zoom = 0.05aug_h_flip = Trueaug_v_flip = Falseaug_fillmode = “nearest”/<code>
產生的圖片如下,原本僅有 243 張,但通過 augmentation 增加了 929 張。
5. 執行 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
2. 執行 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
2. 執行下方的指令:
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
3. 執行重點
(1)訓練 stange 的數目由 -numStages 指定。
(2)HR(Hit Rate,偵測到物件)、FA(False Alarm,錯誤偵測到物件,即誤判)此兩個值分別由 -minHitRate 和 -maxFalseAlarmRate 指定,訓練結果滿足這兩個值表示該 Stage 結束。
(3)-featureType可指定為HAAR 或 LBP,目前比較流行的是 LBP,訓練速度較快且偵測效果不亞於 HAAR。
上圖中可看出訓練時間相當長,但如果將 -featureType 改為 HAAR,則訓練時間會比 LBP 要多出好幾倍!
訓練結果(LBP)
這次測試總共標記了 126 張相片(約有 241 張貓臉正樣本),另外通過資料強化擴增到 1,794 張,再搭配 7,059 張負樣本進行了 OpenCV Cascade Classifier 的 LBP 訓練,最後訓練了 7 個階段,總訓練時間為 5 小時 36 分 41 秒。
另外找了 11 張相片作為 test 圖片,使用訓練完成所產生的 cascade xml 測試其效果如下,若能繼續增加更多的貓臉正樣本,應該可提高識別的效果。
效果還不錯
只偵測出部分
Bounding box 大小位置有待加強
False Alarm
閱讀更多 AI智慧 的文章