opencv默認提供了haar特征和lbp特征訓練的人臉分類器,但是效果不太好,所以我們可以用opencv提供的跑opencv_traincascade函數來訓練一個LBP特征的分類器。(由於opencv3中hog與hog文章定義的不同,因此在opencv3 的opencv_traincascade函數中被刪掉了詳情)
LBP特征
按照官方文檔的訓練流程:
1. 准備訓練數據
首先把正例和負例樣本按下面的結構存放:
train
-pos
-- info.dat
-- img
---- 1.jpg
---- 2.jpg
---- ...
-neg
-- info.dat
-- img
---- 1.jpg
---- 2.jpg
---- ...
其中正例的info.dat格式如下:其中路徑為必須為相對路徑,1為圖片中目標的個數,x,y為bounding box左上角的坐標;w,h為bounding box的長和寬
img/1.jpg 1 x y w h
img/2.jpg 1 x y w h
# img/3.jpg 2 100 200 50 50 50 30 25 25 # 如果同一圖片有多個目標
而負例的格式只是文件名,但*必須為全路徑**(opencv坑1):
/path/to/img/1.jpg
/path/to/img/2.jpg
一般來說樣本需要覆蓋多種大小才能使模型比較魯棒,對於負例樣本來說,需要保證圖片尺寸比訓練時候的window size大,而從一張負例圖片中可以截出許多個負例的window進行訓練,因此負例的圖片數量與正例差不多的時候可以在訓練的時候設定比正例超過10倍的數目。
2. 利用opencv_createsamples生成訓練數據集
opencv_createsamples -vec face.vec \ # 輸出的數據集vec文件
-info /startdt_data/face_datasets/opencv_face_dataset/train/pos/info.dat \ # 正例的annotation文件,這里需要用全路徑,避免報錯
-w 112 -h 112 -num 5000 \ # 正例的圖片大小和數量
-maxxangle 20 \ # 數據增強:允許的最大的x方向的偏轉角
-maxyangle 20 \ # 允許的最大的y方向的偏轉角
3. 利用opencv_traincascade訓練檢測器(以xml文件保存)
opencv_traincascade -data data \ # 模型xml文件保存的目錄
-vec face.vec \ # 數據集文件
-bg /startdt_data/face_datasets/opencv_face_dataset/train/neg/info.dat \
-numPos 4200 \ # 這里的數量需要比實際寫入的正例圖片要小,不然可能會報錯
-numNeg 32000 \ # 負例圖片數
-numStages 5 \ # stage數越多,訓練效果越好,但是耗時也越長
-numThreads 6 \
-featureType LBP \ # 官方文檔里面沒有說支持HOG,但是在opencv3.4中,通過命令行可以看到有這個參數 ,雖然可以訓練,但是已經不支持
-w 112 \
-h 112 \
-precalcValBufSize 4096 \ # (in Mb) Size of buffer for precalculated feature values; size larger, training faster
-precalcIdxBufSize 4096
4. 測試
import cv2
face_detector = cv2.CascadeClassifier("cascade.xml")
img = "test.jpg"
frame = cv2.imread(img)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_detector.detectMultiScale(frame, 1.3, 3)
for face in faces:
cv2.rectangle(frame, (face[0], face[1]), (face[0]+face[2],face[1]+face[3]), (0, 0, 255), 2)
cv2.imshow("test", frame)
cv2.waitKey(0)
HOG特征
雖然cascade classifier的HOG特征在3.x版本是不能用了(2.4版本還是可以的),但是可以用opencv samples/cpp/train_HOG.cpp
(或者是這個庫)
首先需要編譯.cpp
文件獲得.o
文件(編譯opencv的sample文件可以看這里):
g++ `pkg-config --cflags --libs opencv` -o train_HOG opencv/samples/cpp/train_HOG.cpp
訓練:
train_HOG --dw=112 \ # 圖像的檢測窗口高度
--dh=112 \ # 圖像的檢測窗口高度(與圖像有關,但是必須為8的整數倍--腳本內划窗方式決定)
-d \ # 訓練2次(提高精度)
--fn=hog_face_detector.xml \ # 輸出訓練模型文件
-f \
--nd=opencv_face_dataset/train_hog/neg \ # 負例文件目錄
--pd=opencv_face_dataset/train_hog/pos \ # 正例文件目錄
--td=opencv_face_dataset/train_hog/val \ # 測試文件目錄
--tv=test.mp4 # 測試視頻文件
測試:
import cv2
hog_face_file = "hog_face_detector.xml"
hog_model = cv2.HOGDescriptor()
hog_model.load(hog_face_file)
win_stride = (8, 8)
padding = (16, 16)
scale = 1.05
cam = cv2.VideoCapture(0)
while cam.isOpened():
ret, frame = cam.read()
if ret:
detect_region = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = hog_model.detectMultiScale(detect_region, winStride=win_stride, padding=padding, scale=scale) # 返回tuple(array of bounding box, array of bounding box confidence)
faces = list(faces[0])
if len(faces):
face = faces[0] # 只取概率最高的一個人臉
cv2.rectangle(frame, (face[0], face[1]), (face[0]+face[2], face[1]+face[3]), (0, 0, 255), 2)
cv2.imshow("test", frame)
if cv2.waitKey(1) == ord("q"):
break
cv2.destroyAllWindows()
具體參數意義可以參考這里
參考:
cascade classifier:
- https://docs.opencv.org/3.3.0/dc/d88/tutorial_traincascade.html
- http://christopher5106.github.io/computer/vision/2015/10/19/create-an-object-detector.html
train_HOG
- https://github.com/opencv/opencv/blob/master/samples/cpp/train_HOG.cpp
- https://github.com/DaHoC/trainHOG
- https://www.learnopencv.com/how-to-compile-opencv-sample-code/
- https://www.pyimagesearch.com/2015/11/16/hog-detectmultiscale-parameters-explained/
- https://www.pyimagesearch.com/2015/11/09/pedestrian-detection-opencv/