最近糊里糊塗的完成了 HOG Detector 對於輪胎偵測的訓練(效果挺優 !!),
都要感謝此網站的達人:http://blog.baifaces.com/baifaces/blog/work/opencv-hog-peopledetector-trainning.html
在此也記錄一下,我實作時的疑難雜症吧!!
實作平台是:Ubuntu 11.04
釋出訓練程式的網站:http://pascal.inrialpes.fr/soft/olt/ (載點) (樣本檔)
樣本檔容量很大,如果只是要單純訓練自己的樣本的話,大可不用抓。
步驟紀錄如下:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
[lego@lego HOG]$ wget http:
//pascal
.inrialpes.fr
/soft/olt/OLTbinaries
.zip
[lego@lego HOG]$ unzip OLTbinaries.zip
[lego@lego HOG]$
cd
OLTbinaries
//
建立樣本資料夾 train 與
test
[lego@lego OLTbinaries]$
mkdir
train
test
//
把你的正樣本 copy 到 train 與
test
目錄中 (pos為你放正樣本圖片的資料夾)
[lego@lego OLTbinaries]$
cp
-r pos train/
[lego@lego OLTbinaries]$
cp
-r pos
test
/
//
把你的負樣本 copy 到 train 與
test
目錄中 (neg為你放負樣本圖片的資料夾)
[lego@lego OLTbinaries]$
cp
-r neg train/
[lego@lego OLTbinaries]$
cp
-r neg
test
/
//
建立正負樣本的 list
[lego@lego OLTbinaries]$
find
train
/pos
> train
/pos
.lst
[lego@lego OLTbinaries]$
find
test
/pos
>
test
/pos
.lst
[lego@lego OLTbinaries]$
find
train
/neg
> train
/neg
.lst
[lego@lego OLTbinaries]$
find
test
/neg
>
test
/neg
.lst
//
做完上述指令後,需要把上面的每一個 lst 檔的第一行 刪掉
//
修改 runall.sh 把其中的 WIDTH 與 HEIGHT 改成你自己的正樣本大小
[lego@lego OLTbinaries]$
vi
runall.sh
WIDTH=64;
export
WIDTH
HEIGHT=128;
export
HEIGHT
//
接下來就開始訓練了 !!! (我訓練的正樣本有 1133 張 size 50 x 50,負樣本有 680 張 size 512x384)
//
跟 AdaBoost 比起來,HOG Detector 的訓練時間算是很快!!
[lego@lego OLTbinaries]$ sh runall.sh
//
等待 runall.sh 跑完後,便可看到 OLTbinaries
/HOG
目錄下,產生了一個 model
file
//
此即為我們訓練好的檔案。
[lego@lego OLTbinaries]$
ls
HOG
/model_4BiSVMLight
.alt
HOG
/model_4BiSVMLight
.alt
|
以上為訓練過程,以下備註一下注意事項:
1. 訓練的正、負圖片可以是 png 或 jpg ( 我用 bmp 時,會出錯 ),還有就是副檔名要小寫。
2. 若要改變訓練完的 model 檔名稱與位置,可在 runall.sh 中修改。
做完訓練,接下來就是測試訓練檔好不好用啦!!
在此它有提供 runonimage.sh 讓我們測試,用法如下:
## 使用前記得先修改 runonimage.sh 內的正樣本圖片長、寬(與你訓練的正樣本長、寬要一樣),不然會出錯。
WIDTH=64; export WIDTH
HEIGHT=128; export HEIGHT
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
# runonimage.sh {image name/image directory/list file} {out text file} {out image file/out image dir}
//
總共有三個參數
參數1: 可直接指定預測試的圖片檔名 (ex: photo.jpg ),或者是一個存放圖片清單的檔案
( ex: 存放所有你要測試圖片清單的檔案 image.lst 內容如:
test
/photo1
.jpg )
參數2: 測試過程中,可能會有一些測試結果的資訊, 這些資訊會存入該參數指定的檔案
參數3: 測試完畢後,該程式會將偵測物件的結果資訊,畫在圖片上,因此該參數便是指定這張被繪製偵測結果資訊的圖片的位置,
如果你指定的是圖片檔名,則會以該檔名進行儲存;
如果你指定的是一個目錄,則會以原始測試的檔名,儲存在你指定的目錄中。
//
實際指令下法
# 1 測試單張圖片
[lego@lego OLTbinaries]$ sh runonimage.sh photo.jpg result.txt result.jpg
# 2 測試大量圖片
[lego@lego OLTbinaries]$ sh runonimage.sh image.lst result.txt result_folder/
|
測試的圖片,還是盡量使用 jpg 或 png 且輸出的附檔名一定要是小寫,不然有時候跑起來程式會一直出錯,挺麻煩的。
在此SHOW三張偵測結果圖吧 (效果不賴):
當然 ~ 有時候難免有誤判 。
以後有空再把它整進 Android 手機中試看看好了 !!! 先
为了验证这一想法的正确性和可行性,笔者做了些实验,在Ubuntu10.4 g++4.4.5环境中,步骤如下:
- 下载release版的程序:OLTbinaries.zip
- 下载样本:INRIAPerson.tar
- 在目录OLTbinaries/下建立两个文件夹test, train. 将INRIAperson/Test/neg拷贝到test/下,INRIAperson/Train/neg拷贝到train/下;将INRIAperson/test_64x128_H96拷贝到test/下重命名为pos,将INRIAperson/train_64x128_H96拷贝到train/下重命名为pos;
- 将test/neg , test/pos各自文件夹中的所有图片文件名分别输出到neg.list, pos.list, 并放置在test/下; 同样地操作在train/。<pre class="brush: shell; gutter: true">amadeuzou@ubuntu:~/Projects/opencv/OLTbinaries/test$ ls ./neg > neg.list amadeuzou@ubuntu:~/Projects/opencv/OLTbinaries/test$ ls ./pos > pos.list
- 到这里,样本数据便准备好了,那么,只要修改OLTbinaries/runall.sh相关参数然后这些此脚本,一小时左右的时间,便会在OLTbinaries/HOG/下产生一个model_4BiSVMLight.alt文件,你的模型数据便保存在这里面。到这里,你便成功trainning了一个model。
注意事项:
- runall.sh中第5行,按你的正负样本数目修改:
1HardOption=" --poscases 2416 --negcases 1218 "
- runall.sh中第21行,按你的样本文件夹所在(InDir)及输出文件所在(OutDir)修改:
1234OutDir=./HOGInDir=./OutFile=$OutDir/recordCMDLINE=$OutDir/record
- trainning过程中会产生两个G左右的临时文件在OutDir(=./HOG)中,所以要确保硬盘空间足够,结束时删除,只留model_4BiSVMLight.alt。
- 整个trainning过程分4步,有4条屏幕输出信息,最可能出现的错误是样本文件路径不对,可在pos.list neg.list 中用图像文件的绝对路径。
1234First iteration completeHard examples createdDoing second learningSecond iteration complete
- 如果你用的是自己的样本,注意修改其他参数(待究),如正样本的大小:
12WIDTH=64; export WIDTHHEIGHT=128; export HEIGHT
有了模型,怎么去做目标检测呢?你可以做以下的试验:
- 使用bin在OLTbinaries/bin/中classify_rhog: classify_rhog [待检测图片] [目标位置数据结果保存的文本文件] [模型文件] -i [位置画在图像文件]amadeuzou@ubuntu:~/Projects/opencv/OLTbinaries/bin$ ./classify_rhog person-1.jpg result.txt model_4BiSVMLight.alt -i result.jpg
- 使用lib在OLTbinaries/lib/中:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798/** =============================================** Filename: lib-detector.cpp** Description: Code to detect object** Compiler: gcc** Author: Amadeu zou* URL: www.baifaces.com** =============================================*/#include <cv.h>#include <highgui.h>#include <string>#include <iostream>#include <algorithm>#include <iterator>#include <X11/Xlib.h>#include <Imlib2.h>#include <lear/interface/windetect.h>// change this path as appropriate.using namespace std;std::list<DetectedRegion> detector(char* imgf, WinDetectClassify windetect, LinearClassify* classifier){std::list<DetectedRegion> detections;// read imageImlib_Image image = imlib_load_image(imgf);// if the load was successfulif (image){// set the image we loaded as the current context image to work onimlib_context_set_image(image);} else {//std::cerr << "Unable to read image: " << argv[1] << std::endl;return detections;}int width = imlib_image_get_width(),height = imlib_image_get_height();typedef unsigned char uchar;DATA32* data = imlib_image_get_data_for_reading_only();uchar* imagedata = new uchar[3*width*height*sizeof(uchar)];for (int j= 0; j< height; ++j)for (int i= 0; i< width; ++i) {uchar* pixel = imagedata+(i+j*width)*3;int argb = data[i+j*width];pixel[0] = static_cast<uchar>((argb & 0x00FF0000)>>16);pixel[1] = static_cast<uchar>((argb & 0x0000FF00)>> 8);pixel[2] = static_cast<uchar>((argb & 0x000000FF) );}imlib_free_image();// now get detectionswindetect.test(*classifier, detections, imagedata, width, height);delete[] imagedata;return detections;}int main(int argc, char** argv) {if (argc != 4) {std::cout << "Error" << std::endl;return 0;}char modelpath[256];strcpy(modelpath,argv[2]);string model_file(modelpath) ;// initialize the person detector. All default parameters are set for person detector.WinDetectClassify windetect;// use default person detector.RHOGDenseParam desc;LinearClassify* classifier = NULL;// initialize it to 64x128 person detector.classifier = new LinearClassify(model_file, 0);windetect.init(&desc); // initialize the descriptor computationstd::list<DetectedRegion> detections;detections = detector(argv[1], windetect, classifier);//draw region in imageIplImage* img = cvLoadImage(argv[1],1);for(list<DetectedRegion>::iterator itor=detections.begin();itor!=detections.end();++itor){cvRectangle(img,cvPoint(itor->x,itor->y),cvPoint(itor->x+itor->width,itor->y+itor->height),cvScalar(0,0,255),2);}cvSaveImage(argv[3],img);cvReleaseImage(&img);//print detectionsstd::copy(detections.begin(), detections.end(), std::ostream_iterator<DetectedRegion>(std::cout, "\n"));return 0;}
编译:
1g++ `pkg-config --cflags --libs opencv` -O3 -o lib-detector lib-detector.cpp -I. -I/usr/include -L. -lcmdline -lcvip -lclassifier -llearutil -lboost_filesystem-gcc -lblitz -L/usr/lib -lImlib2 -lfreetype -lz -L/usr/X11R6/lib -lX11 -lXext -ldl -lm结果:
1234amadeuzou@ubuntu:~/Projects/opencv/OLTbinaries/lib$ ./lib-detector person-1.jpg model_4BiSVMLight.alt result.jpg298 215 145 290 2.2674 1.10256009e-0113 9 237 475 3.71704 1.31164089e-01234 -7 230 460 3.59693 1.35627717e-01 - 使用源码在learcode/app/中classify_rhog.cpp:配置及使用见learcode/README