HOG Detector ~ Training OLTbinaries

http://lego.twgg.org/?p=852

最近糊里糊塗的完成了 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环境中,步骤如下:

  1. 下载release版的程序:OLTbinaries.zip
  2. 下载样本:INRIAPerson.tar
  3. 在目录OLTbinaries/下建立两个文件夹test, train. 将INRIAperson/Test/neg拷贝到test/下,INRIAperson/Train/neg拷贝到train/下;将INRIAperson/test_64x128_H96拷贝到test/下重命名为pos,将INRIAperson/train_64x128_H96拷贝到train/下重命名为pos;
  4. 将test/neg , test/pos各自文件夹中的所有图片文件名分别输出到neg.list, pos.list, 并放置在test/下; 同样地操作在train/。<pre class="brush: shell; gutter: true">amadeuzou@ubuntu:~/Projects/opencv/OLTbinaries/test$ ls ./neg &gt; neg.list amadeuzou@ubuntu:~/Projects/opencv/OLTbinaries/test$ ls ./pos &gt; pos.list
  5. 到这里,样本数据便准备好了,那么,只要修改OLTbinaries/runall.sh相关参数然后这些此脚本,一小时左右的时间,便会在OLTbinaries/HOG/下产生一个model_4BiSVMLight.alt文件,你的模型数据便保存在这里面。到这里,你便成功trainning了一个model。

注意事项:

  • runall.sh中第5行,按你的正负样本数目修改:
    1
    HardOption=" --poscases 2416 --negcases 1218 "
  • runall.sh中第21行,按你的样本文件夹所在(InDir)及输出文件所在(OutDir)修改:
    1
    2
    3
    4
    OutDir=./HOG
    InDir=./
    OutFile=$OutDir/record
    CMDLINE=$OutDir/record
  • trainning过程中会产生两个G左右的临时文件在OutDir(=./HOG)中,所以要确保硬盘空间足够,结束时删除,只留model_4BiSVMLight.alt。
  • 整个trainning过程分4步,有4条屏幕输出信息,最可能出现的错误是样本文件路径不对,可在pos.list neg.list 中用图像文件的绝对路径。
    1
    2
    3
    4
    First iteration complete
    Hard examples created
    Doing second learning
    Second iteration complete
  • 如果你用的是自己的样本,注意修改其他参数(待究),如正样本的大小:
    1
    2
    WIDTH=64; export WIDTH
    HEIGHT=128; export HEIGHT

有了模型,怎么去做目标检测呢?你可以做以下的试验:

  1. 使用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

    结果:

  2. 使用lib在OLTbinaries/lib/中:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    /*
    * =============================================
    *
    *       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 image
        Imlib_Image image = imlib_load_image(imgf);
        // if the load was successful
        if (image)
        {// set the image we loaded as the current context image to work on
            imlib_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 detections
        windetect.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 computation
        std::list<DetectedRegion> detections;
        detections = detector(argv[1], windetect, classifier);
        //draw region in image
        IplImage* 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 detections
        std::copy(detections.begin(), detections.end(), std::ostream_iterator<DetectedRegion>(std::cout, "\n"));
        return 0;
    }

    编译:

    1
    g++ `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

    结果:

    1
    2
    3
    4
    amadeuzou@ubuntu:~/Projects/opencv/OLTbinaries/lib$ ./lib-detector person-1.jpg   model_4BiSVMLight.alt  result.jpg
       298    215    145    290    2.2674 1.10256009e-01
        13      9    237    475   3.71704 1.31164089e-01
       234     -7    230    460   3.59693 1.35627717e-01
  3. 使用源码在learcode/app/中classify_rhog.cpp:配置及使用见learcode/README

 

你可能感兴趣的:(image,ubuntu,Parameters,compiler,Descriptor,Training)