利用opencv訓練基於Haar特徵、LBP特徵、Hog特徵的分類器cascade.xml
author@jason_ql
http://blog.csdn.net/lql0716
1 利用opencv訓練基於Haar特徵、LBP特徵、Hog特徵的分類器cascade.xml
該訓練是基於adaboost算法訓練的。
工具:
1、opencv_createsamples.exe
2、opencv_traincascade.exe這兩個exe執行程序的路徑爲:
C:\opencv\build\x64\vc12\bin
或
C:\opencv\build\x86\vc12\bin
在opencv安裝目錄下查找即可找到
1.1 訓練步驟
1、蒐集正樣本、負樣本
正樣本
:只含有目標的局部圖(若是全圖,則需要把目標截取出來,比如訓練人臉,則把人臉從含有人臉的圖片中截取出來,尺寸要一致),且背景不要太過複雜,灰度圖正樣本大小
:20*20(一般用於Haar特徵),24*24(LBP特徵)正樣本數量
:一般大於等於2000負樣本
:不含目標的任何圖片,灰度圖負樣本大小
:60*60負樣本數量
:一般大於等於5000注
:正樣本尺寸越小,訓練的時間越短,但正樣本的尺寸要保證小於負樣本的尺寸2、在路徑
C:\opencv\build\x64\vc12\bin
下新建3個文件夾:pos、neg、xmlpos文件夾:存放正樣本
neg文件夾:存放負樣本
xml文件夾:存放訓練的xml格式文件
注
:若使用的是路徑C:\opencv\build\x86\vc12\bin
,可能會提示錯誤“Training parameters are loaded from the parameter file in data folder! Please empty the data folder if you want to use your own set of parameters”,若不提示錯誤,使用x86路徑或x64路徑均可。3、將正樣本、負樣本分別複製到pos文件夾、neg文件夾
4、cmd打開dos命令窗口,進入pos路徑下
- 輸入以下命令,生成pos.txt
dir/b >pos.txt
- 生成pos.txt後,將png替換爲:
png 1 0 0 24 24 - 刪除最後一行的pos.txt
- 輸入以下命令,生成pos.txt
5、同樣進入neg路徑下
- 輸入以下命令,生成neg.txt
dir/b >neg.txt
- 生成neg.txt後,將neg.txt中的圖片名字前面加入路徑:
neg/ - 刪除最後一行的neg.txt
- 輸入以下命令,生成neg.txt
6、進入路徑
C:\opencv\build\x64\vc12\bin
,即pos、neg、xml所在的路徑,輸入以下命令,生成pos.vec
opencv_createsamples.exe -info pos\pos.txt -vec pos.vec -bg neg\neg.txt -num 2000 -w 24 -h 24
- 7、輸入以下命令開始訓練
opencv_traincascade.exe -data xml -vec pos.vec -bg neg\neg.txt
-numPos 1800 -numNeg 4000 -numStages 20 -featureType LBP -w 24 -h 24
-numStages
的參數一般默認爲20,最好大於等於20,級數太小的話,訓練的效果較差
- 1、錯誤提示:
“Traincascade Error:Bad argument(Can not get new positive sample.The most possible reason is insufficient count of samples in given vec-file.”
出現這個提示,可能是正樣本參數太接近總的正樣本數導致。- 2、錯誤提示:
“Required leaf false alarm rate achieved. Branch training terminated – it’s impossible to build classifier with good false alarm on this negative images. Check your negative images are really negative”
出現這個提示,可能是因爲負樣本中有類似正樣本的圖片,把這些圖片篩掉
- 8、訓練結束後,
xml
文件夾下的cascade.xml
文件就是訓練好的分類器
1.2 批量調整樣本圖片尺寸的方法
使用python可以很方便的批量調整圖片的尺寸(也可以用C++,但是代碼寫起來比較麻煩),方法如下。
- 1、視頻逐幀讀取爲圖片
逐幀讀取圖片,並按從1開始對圖片進行編號
import numpy as np
import cv2
cap = cv2.VideoCapture('C:/Users/vid.mp4') #讀取視頻
c = 1
while (cap.isOpened()):
ret, frame = cap.read()
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imshow('frame', gray)
cv2.imwrite('C:/Users/photo/' + '%s'%c + '.jpg', frame) #圖片寫入相應的路徑
c = c + 1
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
- 2、批量調整圖片尺寸
c = 1
for i in range(1, 2000):
img = cv2.imread('D:/test/' + str(i) + '.jpg') #按序號讀取圖片
if img==None: #如果圖片不存在,則跳過本次循環
continue
dst1 = img[:120, :120] #截取120*120的圖片
dst2 = cv2.resize(dst1, (60,60), 0, 0, cv2.INTER_LINEAR) #調整圖片大小,即縮放,其中60爲圖片尺寸
dst3 = cv2.resize(img, (60,60), 0, 0, cv2.INTER_LINEAR) #該操作是直接對原圖進行縮放,這樣會使得圖片變形,故最好先截取爲等寬等長的圖片,再進行縮放
cv2.imwrite('D:/test/photo/'+str(c)+'.png', dst2)
c = c + 1
print 'its over'
1.3 訓練步驟中的參數詳解
無論是Haar特徵訓練,還是LBP特徵訓練或Hog特徵訓練,其圖片尺寸都不要太大
一般,訓練Haar所需的正樣本圖片爲:20*20,訓練LBP所需的正樣本圖片爲:24*24,訓練HOG所需的正樣本圖片爲:60*60,負樣本圖片要大於等於正樣本圖片
- 1、生成pos.vec的命令:
opencv_createsamples.exe -info pos\pos.txt -vec pos.vec -bg neg\neg.txt -num 2000 -w 24 -h 24
2、生成pos.vec的參數:
-info
輸入正樣本描述文件,默認NULL-img
輸入圖像文件名,默認NULL-bg
負樣本描述文件,文件中包含一系列的被隨機選作物體背景的圖像文件名,默認NULL-num
生成正樣本的數目,默認1000-bgcolor
背景顏色,表示透明顏色,默認0-bgthresh
顏色容差,所有處於bgcolor-bgthresh和bgcolor+bgthresh之間的像素被置爲透明像素,也就是將白噪聲加到前景圖像上,默認80-inv
前景圖像顏色翻轉標誌,如果指定顏色翻轉,默認0(不翻轉)-randinv
如果指定顏色將隨機翻轉,默認0-maxidev
前景圖像中像素的亮度梯度最大值,默認40-maxxangle
X軸最大旋轉角度,以弧度爲單位,默認1.1-maxyangle
Y軸最大旋轉角度,以弧度爲單位,默認1.1-maxzangle
Z軸最大旋轉角度,以弧度爲單位,默認0.5
輸入圖像沿着三個軸進行旋轉,旋轉角度由上述3個值限定。-show
如果指定,每個樣本都將被顯示,按下Esc鍵,程序將繼續創建樣本而不在顯示,默認爲0(不顯示)-scale
顯示圖像的縮放比例,默認4.0-w
輸出樣本寬度,默認24-h
輸出樣本高度,默認24-vec
輸出用於訓練的.vec文件,默認NULL3、訓練命令:
opencv_traincascade.exe -data xml -vec pos.vec -bg neg\neg.txt
-numPos 1800 -numNeg 4000 -numStages 20 -featureType LBP -w 24 -h 24
- 4、訓練參數:
-data
目錄名xml,存放訓練好的分類器,如果不存在訓練程序自行創建
-vec
pos.vec文件,由opencv_createsamples生成
-bg
負樣本描述文件, neg\neg.txt
-numPos
每級分類器訓練時所用到的正樣本數目
-numNeg
每級分類器訓練時所用到的負樣本數目,可以大於-bg指定的圖片數目
-numStages
訓練分類器的級數,默認20級,一般在14-25層之間均可。
如果層數過多,分類器的fals alarm就更小,但是產生級聯分類器的時間更長,分類器的hitrate就更小,檢測速度就慢。如果正負樣本較少,層數沒必要設置很多。
-precalcValBufSize
緩存大小,用於存儲預先計算的特徵值,單位MB
-precalcIdxBufSize
緩存大小,用於存儲預先計算的特徵索引,單位M幣
-baseFormatSave
僅在使用Haar特徵時有效,如果指定,級聯分類器將以老格式存儲
5、級聯參數cascadeParams:
-stageType
級聯類型,staticconst char* stageTypes[] = { CC_BOOST };-featureType
特徵類型,staticconst char* featureTypes[] = { CC_HAAR, CC_LBP, CC_HOG };-w
-h
訓練樣本的尺寸,必須跟使用opencv_createsamples創建的訓練樣本尺寸保持一致6、Boosted分類器參數stageParams:
-bt
Boosted分類器類型
DAB-discrete Adaboost, RAB-RealAdaboost, LB-LogiBoost, GAB-Gentle Adaboost-minHitRate
分類器的每一級希望得到的最小檢測率,總的最大檢測率大約爲min_hit_rate^number_of_stages-maxFalseAlarmRate
分類器的每一級希望得到的最大誤檢率,總的誤檢率大約爲max_false_rate^number_of_stages-weightTrimRate
Specifies whether trimming should beused and its weight. 一個還不錯的數值是0.95-maxDepth
弱分類器的最大深度,一個不錯數值是1,二叉樹-maxWeightCount
每一級中弱分類器的最大數目7、Haar特徵參數featureParams
-mode
訓練過程使用的Haar特徵類型,CORE-Allupright ALL-All Features BASIC-Viola
1.4 測試分類器的效果
以下測試效果爲opencv自帶的人臉分類器測試效果代碼。對於自己訓練的分類器,只需將分類器文件及路徑在以下代碼中替換一下就可以了。
1.4.1 視頻中識別目標
- 1、C++代碼
#include <opencv2\objdetect\objdetect.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(){
cv::Mat img, gray;
std::vector<Rect> face;
CascadeClassifier face_cascade;
if (!face_cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml")){ printf("--(!)Error loading face\n"); return -1; };
cv::VideoCapture cap(0);
if (!cap.isOpened()){
return -1;
}
cv::namedWindow("Video", 1);
while (1){
char key = cv::waitKey(1);
if (key == 'q'){
cv::destroyWindow("Video");
break;
}
cap >> img;
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
face_cascade.detectMultiScale(gray, face, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
for (size_t i = 0; i < face.size(); i++){
cv::Point center(face[i].x + face[i].width*0.5, face[i].y + face[i].height*0.5);
cv::ellipse(img, center, Size(face[i].width*0.5, face[i].height*0.5), 0, 0, 360, Scalar(255, 0, 0), 4, 8, 0);
}
cv::imshow("Video", img);
}
cap.release();
return 0;
}
- 2、python代碼
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 21 17:37:53 2017
@author: User
"""
##******************************************************************************
## 利用opencv的分類器,檢測視頻中的人臉
##******************************************************************************
import cv2
face_haar = cv2.CascadeClassifier("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml") #讀取人臉分類器,可在opencv的相應路徑下找到
path = 'D:/test/test.avi' #視頻
cam = cv2.VideoCapture(0) #讀取攝像頭
if cam==False: #如果未發現攝像頭,則讀取視頻
cam = cv2.VideoCapture(path)
while True:
_, img = cam.read()
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_haar.detectMultiScale(gray_img, 1.3, 5) #檢測人臉
for face_x,face_y,face_w,face_h in faces:
cv2.rectangle(img, (face_x, face_y), (face_x+face_w, face_y+face_h), (0,255,0), 2)
cv2.imshow('img', img)
if cv2.waitKey(1) & 0xFF == ord('q'):
cv2.destroyAllWindows()
break
cam.release()
cv2.waitKey(0)
cv2.destroyAllWindows()
1.4.2 圖片中識別目標
- 1、C++代碼
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main(){
cv::Mat img, gray;
std::vector<Rect> face;
CascadeClassifier face_cascade;
if (!face_cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml")){
printf("--(!)Error loading face\n");
return -1;
};
img = cv::imread("d:/photo/08.jpg");
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY);
//cv::GaussianBlur(gray, gray, Size(5, 5), 0, 0, 4); //高斯濾波
face_cascade.detectMultiScale(gray, face, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30));
for (size_t i = 0; i < face.size(); i++){
cv::Point center(face[i].x + face[i].width*0.5, face[i].y + face[i].height*0.5);
cv::ellipse(img, center, Size(face[i].width*0.5, face[i].height*0.5), 0, 0, 360, Scalar(255, 0, 0), 4, 8, 0);
}
cv::imwrite("d:/photo/08_1.jpg", img);
cv::namedWindow("img", cv::WINDOW_NORMAL);
cv::imshow("img", img);
cv::waitKey(0);
return 0;
}
原圖:
效果圖:
效果圖中出現了誤識別,所以opencv所帶的分類器準確率並不是很高,但也可以通過調整函數detectMultiScale()
的參數來提高識別率,或者檢測之前進行高斯濾波。
- 2、python代碼
# -*- coding: utf-8 -*-
"""
Created on Fri Apr 21 17:37:53 2017
@author: User
"""
#******************************************************************************
# 利用opencv的分類器,檢測單張圖片的人臉
#******************************************************************************
import cv2
img = cv2.imread('D:/photo/08.jpg')
# 加載分類器
face_haar = cv2.CascadeClassifier("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml")
# 把圖像轉爲黑白圖像
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#gray_img = cv2.GaussianBlur(gray_img, (5,5), 0, 0) #高斯濾波
# 檢測圖像中的所有臉
faces = face_haar.detectMultiScale(gray_img, 1.1, 4)
for face_x,face_y,face_w,face_h in faces:
cv2.rectangle(img, (face_x, face_y), (face_x+face_w, face_y+face_h), (0,255,0), 2)
#cv2.imwrite('d:/photo/08_3.jpg', img)
cv2.namedWindow('img', cv2.WINDOW_NORMAL)
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
效果圖:
先高斯濾波再檢測人臉的效果圖:
1.4.3 detectMultiScale()函數參數
Detects objects of different sizes in the input image. The detected objects are returned as a list of rectangles.
C++: void CascadeClassifier::detectMultiScale(const Mat& image, vector<Rect>& objects, double scaleFactor=1.1, int minNeighbors=3, int flags=0, Size minSize=Size(), Size maxSize=Size())
Python: cv2.CascadeClassifier.detectMultiScale(image[, scaleFactor[, minNeighbors[, flags[, minSize[, maxSize]]]]]) → objects
Python: cv2.CascadeClassifier.detectMultiScale(image, rejectLevels, levelWeights[, scaleFactor[, minNeighbors[, flags[, minSize[, maxSize[, outputRejectLevels]]]]]]) → objects
Parameters:
cascade
– Haar classifier cascade (OpenCV 1.x API only). It can be loaded from XML or YAML file using Load(). When the cascade is not needed anymore, release it using cvReleaseHaarClassifierCascade(&cascade). 傳入生成的cascade.xml分類器文件image
– Matrix of the type CV_8U containing an image where objects are detected. 灰度圖objects
– Vector of rectangles where each rectangle contains the detected object.scaleFactor
– Parameter specifying how much the image size is reduced at each image scale. 圖像尺度參數,默認1.1minNeighbors
– Parameter specifying how many neighbors each candidate rectangle should have to retain it. 爲每一個級聯矩形應該保留的臨近個數,默認爲3,即至少有3次檢測到目標,才認爲是目標。flags
– Parameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade.- CV_HAAR_DO_CANNY_PRUNING,利用邊緣檢測來排除一些邊緣很少或者很多的圖像區域
- CV_HAAR_SCALE_IMAGE,按正常比例檢測
- CV_HAAR_FIND_GIGGEST_OBJECT,只檢測最大的物體
- CV_HAAR_DO_ROUGH_SEARCH,只做粗略檢測,默認值爲0
minSize
– Minimum possible object size. Objects smaller than that are ignored.maxSize
– Maximum possible object size. Objects larger than that are ignored.
參考資料
相關文章
1、用opencv自帶的traincascade.exe訓練給予haar特徵和LBP特徵的分類器《link》
2、採用opencv_cascadetrain進行訓練的步驟及注意事項《link》
3、正式使用opencv裏的訓練和檢測 - opencv_createsamples、opencv_traincascade-2.4.11版本《link》
4、使用opencv_traincascade訓練Haar、HOG、LBP Adaboost分類器《link》
5、LBP特徵的實現及LBP+SVM分類《link》
6、HandGestureDetection《link》
7、用opencv 裏面的traincascade.exe訓練時,出現錯誤解決方法《link》
8、opencv之利用opencv_traincascade級聯分類器訓練.xml文件《link》
9、第四十一篇:opencv中相關的訓練的問題解答(經典)《link》
10、《FAQ:OpenCV Haartraining》——使用OpenCV訓練Haar like+Adaboost分類器的常見問題《link》