[分享] 采用opencv_cascadetrain進行訓練的步驟及注意事項 [復制鏈接]


http://f.dataguru.cn/thread-725364-1-1.html

很有用的一個帖子

轉自:http://blog.csdn.net/xidianzhimeng/article/details/10470839



OpenCV中有兩個程序可以訓練級聯分類器: opencv_haartraining 和opencv_traincascade。opencv_traincascade 是一個新程序,使用OpenCV 2.x API 以C++ 編寫。這二者主要的區別是 opencv_traincascade 支持 Haar、Hog和 LBP(Local Binary Patterns) 三種特征,並易於增加其他的特征。與Haar特征相比,LBP特征是整數特征,因此訓練和檢測過程都會比Haar特征快幾倍。LBP和Haar特征用於檢測的准確率,是依賴訓練過程中的訓練數據的質量和訓練參數。訓練一個與基於Haar特征同樣准確度的LBP的分類器是可能的。
opencv_traincascade and opencv_haartraining 所輸出的分類器文件格式並不相同。注意,新的級聯檢測接口(參考 objdetect 模塊中的 CascadeClassifier 類)支持這兩種格式。 opencv_traincascade 可以舊格式導出訓練好的級聯分類器。但是在訓練過程被中斷后再重啟訓練過程, opencv_traincascade  and opencv_haartraining 不能裝載與中斷前不同的文件格式。
opencv_traincascade 程序使用TBB來處理多線程。如果希望使用多核並行運算加速,請使用TBB來編譯OpenCV。還有一些與訓練相關的輔助程序。
opencv_createsamples 用來准備訓練用的正樣本數據和測試數據。 opencv_createsamples 能夠生成能被 opencv_haartraining 和 opencv_traincascade 程序支持的正樣本數據。它的輸出為以 *.vec 為擴展名的文件,該文件以二進制方式存儲圖像。
opencv_performance 可以用來評估分類器的質量。它讀入一組標注好的圖像,運行分類器並報告性能,如檢測到物體的數目,漏檢的數目,誤檢的數目,以及其他信息。

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/user_guide/ug_traincascade.html

http://blog.csdn.net/delltdk/article/details/9186875

1 建立樣本集pos和neg

pos中存放正樣本的圖像,可以是一張圖像或多張圖像。neg中存放包含負樣本的圖像,可以是任意圖像,但是這些圖像中不能包含待檢測的物體。

注意:

一般需要一個很大的負樣本庫送給訓練程序進行訓練。如果是剛性的物體,如OpenCV的標志,只有一張正樣本圖像,那么可以通過對物體圖像的隨機旋轉、改變標志亮度以及將標志放在任意的背景上而獲得大量的正樣本;如果是人臉,需要幾百甚至幾千個正樣本。在待檢測物體是人臉的情況下,需要考慮所有的人種、年齡、表情甚至胡子的樣式。

2 生成正\負樣本描述文件negdata.txt

(1)   負樣本描述文件negdata.txt
在命令行窗口輸入“cd d:\%....%\pos”路徑切換到neg文件夾下,輸入“dir/b>negdata.txt”就會在neg文件夾下生成描述文件negdata.txt,存放neg中所有圖片的文件名,注意要去掉最后的negdata.txt 。

注意:

如果把negdata.txt保存在neg文件夾外面,需要在每一行外面添加相對路徑或路徑來指出樣本的所在位置。一種方法是將negdata.txt 文件中的內容復制到word中,使用替換功能實現快速修改。neg替換為neg\neg
(2)   正樣本描述文件posdata.txt
與建立negdata.txt一樣建立posdata.txt,只不過在正樣本描述文件中需要指出目標在每個樣本中的數量和位置如pos\1.bmp 1 x1 y1 x2 y2,其中(x1,y1,x2,y2)為目標所在的矩形框,又如pos\1.bmp2 x1 y1 x2 y2 x1’ y1’ x2’ y2’
因為我們准備的正樣本基本都是目標,因此只需在文件名后增加1 0 0 width height即可。

注意:

1若正樣本圖像是不同尺寸的,一方面可以使用ImageResize或matlab將圖像統一成同一尺寸在生成posdata.txt,或程序ImageToTxt直接生成具有不同尺寸圖像的正樣本描述文件。在此階段不歸一化的話,后續生成.vec文件的時候在程序中自動歸一化。
2樣本描述文件與圖像要一致,可以存在圖像但沒有寫在描述文件中,即有多余的圖像,但千萬不要在描述文件中寫不存在的圖像。

問題:

       歸一化尺寸的方法是否對訓練結果有影響? opencv_createsamples 采用何種方法進行歸一化?
sample = cvCreateImage( cvSize(winwidth, winheight ), IPL_DEPTH_8U, 1 );
fscanf( info, "%d %d %d%d", &x, &y, &width, &height )
    cvSetImageROI( src, cvRect( x, y, width,height ) );
cvResize( src, sample,
width >=sample->width && height >= sample->height ? CV_INTER_AREA :CV_INTER_LINEAR );
CV_INTER_NN         最近鄰插值
CV_INTER_LINER      雙線性插值,缺省情況
CV_INTER_AREA      使用像素關系重采樣,當圖像縮小時候可以避免波紋出現,當圖像方法時類似CV_INTER_NN
CV_INTER_CUBIC     立方插值


3 生成.vec文件

生成的正樣本數目以及隨機的程度都可以通過 opencv_createsamples 的命令行參數控制。
使用create.dat調用%Opencv%\vs2008\bin\Release\ opencv_createsamples.exe
在createsamples.cpp中查閱參數設置
-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文件,默認NULL
將正樣本描述文件中的正樣本轉換為灰度圖像並縮放到-w-h尺寸存入vec文件中。
(1)如果設置-img和-vec
調用cvCreateTrainingSamples,采用一張圖像創建訓練樣本
(2)如果設置-img、-bg和-info
調用cvCreateTestSamples,采用一張圖像創建測試樣本。-bg在這里又有什么作用?目的是作為背景創建測試圖像。
(3)如果設置-info和-vec(采用正樣本描述文件中的圖像創建訓練樣本)
調用cvCreateTrainingSamplesFromInfo,在cvCreateTrainingSamplesFromInfo中將讀取樣本,並resize后調用icvWriteVecHeader和icvWriteVecSample創建vec文件。
(4)如果只設置-vec(只顯示vec文件中的樣本)
調用cvShowVecSamples查看和檢查保存在vec文件中正樣本
上述參數在create.dat中設置好,最后有一個pause,等待顯示結果:Done.Created num samples

4 訓練過程

使用train.dat調用%Opencv%\vs2008\bin\Release\ opencv_traincascade.exe
在traincascade.cpp中查閱參數設置
1基本參數
-data                            目錄名,存放訓練好的分類器,如果不存在訓練程序自行創建
-vec                                  正樣本.vec文件,由opencv_createsamples生成
-bg                            負樣本描述文件
-numPos                      每級分類器訓練時所用到的正樣本數目
-numNeg                        每級分類器訓練時所用到的負樣本數目,可以大於-bg指定的圖片數目
-numStages                  訓練分類器的級數
-precalcValBufSize           緩存大小,用於存儲預先計算的特征值,單位MB
-precalcIdxBufSize            緩存大小,用於存儲預先計算的特征索引,單位M幣
-baseFormatSave                 僅在使用Haar特征時有效,如果指定,級聯分類器將以老格式存儲
2級聯參數cascadeParams
-stageType                    級聯類型,staticconst char* stageTypes[] = { CC_BOOST };
-featureType                     特征類型,staticconst char* featureTypes[] = { CC_HAAR, CC_LBP, CC_HOG };
-w            
-h                                訓練樣本的尺寸,必須跟使用opencv_createsamples創建的訓練樣本尺寸保持一致
3Boosted分類器參數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             每一級中弱分類器的較大數目
4Haar特征參數featureParams
-mode                          訓練過程使用的Haar特征類型,CORE-Allupright  ALL-All Features BASIC-Viola
上述參數設置好后調用CvCascadeClassifier::train進行訓練
將上述內容在train.dat中編輯好,運行即可。訓練最終生成一個-data指定級聯分類器的文件夾和一個cascade.xml文件,其余文件都是中間結果,當訓練程序被中斷之后,再重新運行訓練程序將讀入之前的訓練結果,無需從頭重新訓練,訓練結束后可以刪除這些文件。
       在cascade.xml文件中主要有stageType,featureType,width,height,stageParams,featureParams,stageNum,stages和features節點。

 

stages中的stage數目是自己設定的,每個stage又包含多個weakClassifiers,每個weakClassifier又包含一個internalNodes和一個leafValues。internalNodes中四個變量代表一個node,分別為node中的left/right標記,特征池中的ID和threshold。leafValues中兩個變量代表一個node,分別為leftleaf和right leaf值。

 

       features是分類器的特征池,每個Haar特征包含一個矩形rect和要提取的特征序號,每個Hog特征/LBP特征包含一個矩形。



注意:1 包含負樣本的圖像一定不小於在create中設置的尺寸

負樣本圖像可以是不同的尺寸,但是圖像尺寸應該比訓練窗口的尺寸大,在使用負樣本圖像時,OpenCV自動從負樣本圖像中摳出一塊和正樣本同樣大小的區域作為負樣本。具體可查閱icvGetNextFromBackgroundData,具體摳圖過程為:
1)  確定摳圖區域的左上角坐標(Point.x, Point.y)
2)  確定一個最小縮放比例,使得原負樣本圖像縮放后恰好包含選中負樣本區域
3)  對原負樣本圖象按計算好的縮放比例進行縮放
4)  在縮放后的圖像上摳出負樣本。


2 –numPos一般比實際正樣本數量少200-300,-numNeg是否存在同樣的情況?正負樣本選擇規則?

如果出現:訓練停留在一個分類器長達幾小時沒有相應,問題出現在取負樣本的那個函數 icvGetHaarTrainingDataFromBG中;只有當之前的強分類器對負樣本集內的樣本全部分類正確時才會出現死循環,因為只要有一個樣本會被錯分為正樣本,那么通過count次掃描整個負樣本集就能得到count個負樣本,當然這count個負樣本實際上就是一個負樣本的count個拷貝。為避免這種情況,負樣本集中的樣本數需要足夠多 。
不過此時的分類器已經完全額、可以使用,因為它的誤檢率已經很低,從實用性上時沒有任何問題的。所以我們可以通過設置-nstages 這個參數來限制分類器級數,適當時候停止並生成xml文件。
從CvCascadeBoost::train中去查閱
函數                poscount= icvGetHaarTrainingDataFromVec( training_data, 0, npos,
                    (CvIntHaarClassifier*)tcc, vecfilename, &consumed )負責從正樣本集*.vec 文件中載入 count(npos)個正樣本。在程序第一次運行到此(即訓練第一個分類器之前)時,只要正樣本集中有 count 個樣本,就一定能取出 count 個正樣本。在以后運行到此時,有可能取不到 count 個樣本,因為
必須是用前面的級聯強分類器((CvIntHaarClassifier*) tcc)分類為正樣本(即分類正確的樣本)的樣本才會被取出作為下一個強分類器訓練樣本,具體可參考 icvGetHaarTrainingData和icvEvalTreeCascadeClassifierFilter函數。

 

訓練負樣本,具體可參考icvGetHaarTrainingDataFromBG和icvEvalTreeCascadeClassifierFilter函數。
int icvGetHaarTrainingDataFromBG(CvHaarTrainingData* data, int first, int count,
                                  CvIntHaarClassifier*cascade, double* acceptance_ratio, const char * filename = NULL )
  傳遞返回值的 acceptance_ratio 參數記錄的是實際取出的負樣本數與查詢過的負樣本數(如果通過前面級聯stage強分類器的負樣本數很少時,那么程序會循環重復讀取負樣本,並用thread_consumed_count計數)之比(acceptance_ratio = ((double) count) / consumed_count),也就是虛警率,用於判斷已訓練的級聯分類器是否達到指標,若達到指標,則停止訓練過程。 


  注意函數 icvGetHaarTrainingData中一個主要的 For 循環:
        for( i = first; i < first +count; i++ ) //共讀取 count 個負樣本,當讀取不到
        {                            //這么多負樣本時將出現死循環!

  對上面代碼中的注釋有必要進一步說明一下:只有當之前的強分類器對負樣本集內的樣本全部分類正確時才會出現死循環。因為只要有一個樣本會被錯分為正樣本,那么通過 count次掃描整個負樣本集就能得到 count 個負樣本,當然這 count 個負樣本實際上就是一個負樣本的 count 個拷貝。為避免這些情況的發生,負樣本集中的樣本數需要足夠多。
  在負樣本圖像大小與正樣本大小完全一致時,假設最終的分類器虛警率要求是falsealarm,參加訓練的負樣本要求是 count 個,則需要的負樣本總數可計算如下: TotalCount = count / falsealarm
  以 Rainer Lienhart 的文章中的一些參數為例,falsealarm=0.5^20=9.6e-07, count=3000,
則 TotalCount=3000/(0.5^20)= 3,145,728,000=31 億。
函數 icvGetHaarTrainingDataFromBG ()負責從負樣本集中載入 count 個負樣本。在程序第一次運行到此(即訓練第一個分類器之前)時,只要負樣本集中有 count 個樣本,就一定能取出 count 個負樣本。在以后運行到此時,有可能取不到 count 個樣本,因為必須是用前面的級聯強分類器分類為正樣本的樣本(即分類錯誤的樣本)才會被取出作為下一個強分類器的負樣本輸入。
對於int icvGetHaarTrainingData( CvHaarTrainingData* data,int first, int count,
                            CvIntHaarClassifier*cascade,
                            CvGetHaarTrainingDataCallbackcallback, void* userdata,
                            int*consumed, double* acceptance_ratio )
這個函數的解釋:
這是個對於讀取正負樣本通用的函數,區別在於callback的調用。在這個函數中有個變量thread_getcount,表示將樣本分為正樣本的數目(不論這個樣本是負樣本還是正樣本)。
  傳遞返回值的 Consumed 參數表示為取 count 個正樣本,查詢過的正樣本總數。對於負樣本為空(null),沒有返回值。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM