閱讀69 返回首頁    go 魔獸


【原】訓練自己haar-like特征分類器並識別物體(1)

本係列文章旨在學習如何在opencv中基於haar-like特征訓練自己的分類器,並且用該分類器用於模式識別。該過程大致可以分為一下幾個大步驟:

1.準備訓練樣本圖片,包括正例及反例樣本

2.生成樣本描述文件

3.訓練樣本

4.目標識別

=================

本文主要對步驟1、步驟2進行說明。

1.準備訓練樣本圖片,包括正例及反例樣本

1)正樣本的采集

  所謂正樣本,是指隻包含待識別的物體的圖片,一般是一些局部的圖片,且最好能轉化為灰度圖。比如,若你想識別人臉,則正樣本應盡可能隻包含人臉,可以留一點周邊的背景但不要過多。在正樣本的采集上,我們有兩種圖形標定工具可以使用:(1)opencv的imageClipper (2)objectMarker。這兩個工具都支持傻瓜式地對圖片中的物體進行矩形標定,可以自動生成樣本說明文件,自動逐幀讀取文件夾內的下一幀。我用的是objectMarker。如果你找不到這個軟件,可以留下郵箱,我發給你。
  在標定的時候盡量保持長寬比例一致,也就是盡量用接近正方形的矩形去標定待識別的物體,至於正方形的大小影響並不大。盡管OpenCV推薦訓練樣本的最佳尺寸是20x20,但是在下一步生成樣本描述文件時可以輕鬆地將其它尺寸縮放到20x20。標定完成後生成的樣本說明文件info.txt內容舉例如下:

 

1
2
3
4
5
rawdata/   (1).bmp 1 118 26 81 72
rawdata/   (10).bmp 2 125 72 48 46 0 70 35 43
rawdata/   (11).bmp 1 105 87 43 42
rawdata/   (12).bmp 2 1 70 34 38 105 87 41 44
...

 

其中rawdata文件夾存放了所有待標定的大圖,objectMarker.exe與rawdata文件夾同級。這個描述文件的格式已經很接近opencv所要求的了。

2)負樣本的采集:

  所謂負樣本,是指不包含待識別物體的任何圖片,因此你可以將天空、海灘、大山等所有東西都拿來當負樣本。但是,很多時候你這樣做是事倍功半的。大多數模式識別問題都是用在視頻監控領域,攝像機的角度跟高度都相對固定。如果你知道你的項目中攝像機一般都在拍什麼,那負樣本可以非常有針對性地選取,而且可以事半功倍。舉個例子,你現在想做火車站廣場的異常行為檢測,在這個課題中行人檢測是必須要做的。而視頻幀的背景基本都是廣場的地板、建築物等。那你可以在人空曠的時候選擇取一張圖,不同光照不同時段下各取一張圖,然後在這些圖上隨機取圖像塊,每個塊20x20,每個塊就是一個負樣本。這幾張圖就能纏上數以千計數以萬計的負樣本!而且針對性強。因為海洋、大山等東西對你的識別一點幫助也沒有,還會增加訓練的時間,吃力不討好的事還是少做為好。我寫了一段小程序,功能是根據背景圖片自動隨機生成指定數量指定尺寸的負樣本:

複製代碼
 1 #include "stdafx.h"
 2 #include "cv.h"
 3 #include "highgui.h"
 4 #include <iostream>
 5 #include <string>
 6 
 7 using namespace std;
 8 using namespace cv;
 9 
10 //從背景圖片中隨機抽取圖像塊,多用於生成負樣本
11 #define kImageBlockWidth                40        //圖像塊大小
12 #define kImageBlockHeight                40        
13 #define kLoopTimes                        1000    //期望樣本數
14 
15 int _tmain(int argc, _TCHAR* argv[])
16 {
17     int originX = 0, originY = 0;
18     int width_limited = 0, height_limited = 0;
19     int width = 0, height = 0;
20     IplImage *bgImage = cvLoadImage("neg\\bg1.bmp");
21     IplImage *blockImage = cvCreateImage(cvSize(kImageBlockWidth, kImageBlockHeight), bgImage->depth, bgImage->nChannels);
22     width = bgImage->width;
23     height = bgImage->height;
24     width_limited = width - kImageBlockWidth;
25     height_limited = height - kImageBlockHeight;
26     cout<<width_limited<<"   "<<height_limited;
27     for (int i = 0; i < kLoopTimes; i++)
28     {
29         originX = rand() % width_limited;
30         originY = rand() % height_limited;
31         cvZero(blockImage);
32         CvPoint2D32f center_block = cvPoint2D32f(originX + kImageBlockWidth / 2, originY + kImageBlockHeight / 2);
33         cvGetRectSubPix(bgImage, blockImage, center_block);
34         char saveFileName[100] = {'\0'};
35         sprintf(saveFileName, "neg\\(%d).bmp", i + 1);
36         cvSaveImage(saveFileName, blockImage);
37     }
38 
39     cvReleaseImage(&bgImage);
40     cvReleaseImage(&blockImage);
41     system("pause");
42     return 0;
43 }
複製代碼

這裏的負樣本尺寸我設定為40x40,是因為在我的應用環境下待識別的物體差不多是這個尺寸的。具體可以分析一下你的info.txt文件。生成文件後,開cmd.exe cd到該目錄,然後運行“dir /b > neg_sample.dat”,打開.dat,用editplus替換bmp為bmp 1 0 0 40 40。這樣負樣本說明文件就產生了。

  對於負樣本,我還有一點要說明:負樣本圖像的大小隻要不小於正樣本就可以。opencv在使用你提供的一張負樣本圖片時會自動從其中摳出一塊與正樣本同樣大小的圖像作為負樣本,具體的函數可見opencv係統函數cvGetNextFromBackgroundData()。

 

2.生成樣本描述文件

  樣本描述文件也即.vec文件,裏麵存放二進製數據,是為opencv訓練做準備的。隻有正樣本需要生成.vec文件,負樣本不用,負樣本用.dat文件就夠。在生成描述文件過程中,我們需要用到opencv自帶的opencv_createsamples.exe可執行文件。這個文件一般存放在opencv安裝目錄的/bin文件夾下(請善用ctrl+F搜索)。如果沒有,可以自己編譯一遍也很快。這裏提供懶人版:https://en.pudn.com/downloads204/sourcecode/graph/texture_mapping/detail958471_en.html 這是別人編譯出來的opencv工程,在bin底下可以找到該exe文件。要注意,該exe依賴於cv200.dll、cxcore200.dll、highgui200.dll這三個動態庫,要保持這四個文件在同個目錄下。

 

現在我們開始生成描述文件。新建文件夾pos、neg分別存放正樣本及負樣本圖片,此處是指沒標定的大圖。

1)修改樣本說明文件的格式:

在第1步中我們用objectMarker完成標定後會自動生成info.txt,現在我們需要對其格式做一定的微調,通過editplus或者ultraedit將路徑信息rawdata都替換掉,並命名為sample_pos.dat,也可自定義名字。

1
2
3
4
5
6
(1).bmp 1 118 26 81 72
(10).bmp 2 125 72 48 46 0 70 35 43
(11).bmp 1 105 87 43 42
(12).bmp 2 1 70 34 38 105 87 41 44
(13).bmp 1 102 93 43 41
(14).bmp 1 104 86 45 47

2)使用opencv_createsamples.exe創建樣本描述文件:

  打開cmd.exe,cd到opencv_createsamples.exe所在的目錄,執行命令:

1
opencv_createsamples.exe -info ./pos/sample_pos.dat -vec ./pos/sample_pos.vec -num 17 -w 20 -h 20 -show YES

 參數說明:-info,指樣本說明文件

      -vec,樣本描述文件的名字及路徑

      -num,總共幾個樣本,要注意,這裏的樣本數是指標定後的20x20的樣本數,而不是大圖的數目,其實就是樣本說明文件第2列的所有數字累加         和。

      -w -h 指明想讓樣本縮放到什麼尺寸。這裏的奧妙在於你不必另外去處理第1步中被矩形框出的圖片的尺寸,因為這個參數幫你統一縮放!

      -show 是否顯示每個樣本。樣本少可以設為YES,要是樣本多的話最好設為NO,或者不要顯式地設置,因為關窗口會關到你哭

 

done表示創建成功,若創建不成功會報錯,大部分會提示你sample.dat pars error,一般是說明文件格式有錯,或者num設置過大

1
2
Create training samples from images collection...
Done. Created 17 samples

 

總結

總結並延伸以上內容:

1.樣本圖片最好使用灰度圖,且最好能根據實際情況做一定的預處理

2.樣本選擇的原則是:數量越多越好,盡量高於1000;樣本間差異性越大越好

3.正負樣本比例為1:3最佳,尺寸為20x20最佳

 

That`s all。

==================

附上參考資料,看這些就夠,網上資料太多容易讓人看花眼!

https://blog.csdn.net/think_embed/article/details/9959569

https://www.docin.com/p-80649093.html

https://jingyan.baidu.com/article/4dc40848f50689c8d946f197.html

https://blog.csdn.net/carson2005/article/details/8171571



【原】訓練自己haar-like特征分類器並識別物體(1)



最後更新:2017-04-03 05:40:06

  上一篇:go 【haartraining】正樣本 隻框頭部 (I)
  下一篇:go Android.mk中添加宏定義