1. 程式人生 > >人臉識別之人臉檢測(二)--人臉識別樣本製作及訓練測試

人臉識別之人臉檢測(二)--人臉識別樣本製作及訓練測試

閒得沒事,折騰下opencv 人臉識別,從樣本製作到評估。

1.直接copy opencv裡的原始碼,建立工程,新增opencv庫,可以直接cmake原始碼,但我之所以自己建立工程,是想多學習,並且降低與原始碼框架的耦合度。

這裡如果出現_imp__CreateToolbarEx 符號無法解析(error LNK2019: unresolved external symbol __imp__[email protected] referenced in function "int __cdecl icvCreateTrackbar(char const *,char const *,int *,int,void (__cdecl*)(int),void (__cdecl*)(int,void *),void *)" (

[email protected]@[email protected]@[email protected]))。則新增comctl32.lib 和vfw32.lib 即可。親測。安裝配置如下:

2.編譯生成haartarining的lib和其他相關exe(如opencv_createsamples.exe)後,即可debug。

正樣本製作:

對於正樣本,通常的做法是先把所有正樣本裁切好,並對尺寸做規整(即縮放至指定大小),由於HaarTraining訓練時輸入的正樣本是vec檔案,所以需要使用OpenCV自帶的CreateSamples程式(在你所按照的opencv\bin下,如果沒有需要編譯opencv\apps\HaarTraining\make下的.dsw檔案,注意要編譯release版的)將準備好的正樣本轉換為vec檔案。轉換的步驟如下:

1) 製作一個正樣本描述檔案,用於描述正樣本檔名(包括絕對路徑或相對路徑),正樣本數目以及各正樣本在圖片中的位置和大小。典型的正樣本描述檔案如下:

posdata/1(10).bmp 1 1 1 23 23
posdata/1(11).bmp 1 1 1 23 23
posdata/1(12).bmp 1 1 1 23 23

不過你可以把描述檔案放在你的posdata路徑(即正樣本路徑)下,這樣你就不需要加前面的相對路徑了。同樣它的生成方式可以用負樣本描述檔案的生成方法,最後用txt的替換工具將“bmp”全部替換成“bmp 1 1 1 23 23
”就可以了,如果你的樣本圖片多,用txt替換會導致程式未響應,你可以將內容拷到word下替換,然後再拷回來。bmp後面那五個數字分別表示圖片個數,目標的起始位置及其寬高。這樣就生成了正樣本描述檔案posdata.dat。

2) 執行CreateSamples程式。如果直接在VC環境下執行,可以在Project\Settings\Debug屬性頁的Program arguments欄設定執行引數。下面是一個執行引數示例:
-info D:\face\posdata\posdata.dat -vec D:\face\pos.vec -num 50 -w 20 -h 20
表示有50個樣本,樣本寬20,高20,正樣本描述檔案為posdata.dat,結果輸出到pos.vec。

或者在dos下輸入:

"D:\Program Files\OpenCV\bin\createsamples.exe" -info "posdata\posdata.dat" -vec data\pos.vec -num 50 -w 20 -h 20
執行完了會d:\face\data下生成一個*.vec的檔案。該檔案包含正樣本數目,寬高以及所有樣本影象資料。

Createsamples程式的命令列引數:
命令列引數:
-vec <vec_file_name>
訓練好的正樣本的輸出檔名。
-img<image_file_name>
源目標圖片(例如:一個公司圖示)
-bg<background_file_name>
背景描述檔案。
-num<number_of_samples>
要產生的正樣本的數量,和正樣本圖片數目相同。
-bgcolor<background_color>
背景色(假定當前圖片為灰度圖)。背景色制定了透明色。對於壓縮圖片,顏色方差量由bgthresh引數來指定。則在bgcolor-bgthresh和bgcolor+bgthresh中間的畫素被認為是透明的。
-bgthresh<background_color_threshold>
-inv
如果指定,顏色會反色
-randinv
如果指定,顏色會任意反色
-maxidev<max_intensity_deviation>
背景色最大的偏離度。
-maxangel<max_x_rotation_angle>
-maxangle<max_y_rotation_angle>,
-maxzangle<max_x_rotation_angle>
最大旋轉角度,以弧度為單位。
-show
如果指定,每個樣本會被顯示出來,按下"esc"會關閉這一開關,即不顯示樣本圖片,而建立過程繼續。這是個有用的debug選項。
-w<sample_width>
輸出樣本的寬度(以畫素為單位)
-h《sample_height》
輸出樣本的高度,以畫素為單位。

opencv_createsamples.exe的引數

(createsamples.cpp)

[cpp] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片

  1. "  [-info <collection_file_name>]\n"  
  2. "  [-img <image_file_name>]\n"  
  3. "  [-vec <vec_file_name>]\n"  
  4. "  [-bg <background_file_name>]\n  [-num <number_of_samples = %d>]\n"  
  5. "  [-bgcolor <background_color = %d>]\n"  
  6. "  [-inv] [-randinv] [-bgthresh <background_color_threshold = %d>]\n"  
  7. "  [-maxidev <max_intensity_deviation = %d>]\n"  
  8. "  [-maxxangle <max_x_rotation_angle = %f>]\n"  
  9. "  [-maxyangle <max_y_rotation_angle = %f>]\n"  
  10. "  [-maxzangle <max_z_rotation_angle = %f>]\n"  
  11. "  [-show [<scale = %f>]]\n"  
  12. "  [-w <sample_width = %d>]\n  [-h <sample_height = %d>]\n"//預設24*24  
  1. " [-info <collection_file_name>]\n"

  2. " [-img <image_file_name>]\n"

  3. " [-vec <vec_file_name>]\n"

  4. " [-bg <background_file_name>]\n [-num <number_of_samples = %d>]\n"

  5. " [-bgcolor <background_color = %d>]\n"

  6. " [-inv] [-randinv] [-bgthresh <background_color_threshold = %d>]\n"

  7. " [-maxidev <max_intensity_deviation = %d>]\n"

  8. " [-maxxangle <max_x_rotation_angle = %f>]\n"

  9. " [-maxyangle <max_y_rotation_angle = %f>]\n"

  10. " [-maxzangle <max_z_rotation_angle = %f>]\n"

  11. " [-show [<scale = %f>]]\n"

  12. " [-w <sample_width = %d>]\n [-h <sample_height = %d>]\n"//預設24*24

以下1)~4)是按順序判斷,且有且僅有一個

1)提供imagename 和vecname時,呼叫以下操作

[cpp] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片

  1. /* 
  2.  * cvCreateTrainingSamples 
  3.  * 
  4.  * Create training samples applying random distortions to sample image and 
  5.  * store them in .vec file 
  6.  * 
  7.  * filename        - .vec file name 
  8.  * imgfilename     - sample image file name 
  9.  * bgcolor         - background color for sample image 
  10.  * bgthreshold     - background color threshold. Pixels those colors are in range 
  11.  *   [bgcolor-bgthreshold, bgcolor+bgthreshold] are considered as transparent 
  12.  * bgfilename      - background description file name. If not NULL samples 
  13.  *   will be put on arbitrary background 
  14.  * count           - desired number of samples 
  15.  * invert          - if not 0 sample foreground pixels will be inverted 
  16.  *   if invert == CV_RANDOM_INVERT then samples will be inverted randomly 
  17.  * maxintensitydev - desired max intensity deviation of foreground samples pixels 
  18.  * maxxangle       - max rotation angles 
  19.  * maxyangle 
  20.  * maxzangle 
  21.  * showsamples     - if not 0 samples will be shown 
  22.  * winwidth        - desired samples width 
  23.  * winheight       - desired samples height 
  24.  */  
  1. /*

  2. * cvCreateTrainingSamples

  3. *

  4. * Create training samples applying random distortions to sample image and

  5. * store them in .vec file

  6. *

  7. * filename - .vec file name

  8. * imgfilename - sample image file name

  9. * bgcolor - background color for sample image

  10. * bgthreshold - background color threshold. Pixels those colors are in range

  11. * [bgcolor-bgthreshold, bgcolor+bgthreshold] are considered as transparent

  12. * bgfilename - background description file name. If not NULL samples

  13. * will be put on arbitrary background

  14. * count - desired number of samples

  15. * invert - if not 0 sample foreground pixels will be inverted

  16. * if invert == CV_RANDOM_INVERT then samples will be inverted randomly

  17. * maxintensitydev - desired max intensity deviation of foreground samples pixels

  18. * maxxangle - max rotation angles

  19. * maxyangle

  20. * maxzangle

  21. * showsamples - if not 0 samples will be shown

  22. * winwidth - desired samples width

  23. * winheight - desired samples height

  24. */

2)提供imagename、bgfilename和infoname時
與1)類似
3)提供 infoname和 vecname時,呼叫以下操作(這裡是我們訓練需要的)

[cpp] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片

  1. /* 
  2.  * cvCreateTrainingSamplesFromInfo 
  3.  * 
  4.  * Create training samples from a set of marked up images and store them into .vec file 
  5.  * infoname    - file in which marked up image descriptions are stored 
  6.  * num         - desired number of samples 
  7.  * showsamples - if not 0 samples will be shown 
  8.  * winwidth    - sample width 
  9.  * winheight   - sample height 
  10.  *  
  11.  * Return number of successfully created samples 
  12.  */  
  13. int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,  
  14.                                      int num,  
  15.                                      int showsamples,  
  16.                                      int winwidth, int winheight )  
  1. /*

  2. * cvCreateTrainingSamplesFromInfo

  3. *

  4. * Create training samples from a set of marked up images and store them into .vec file

  5. * infoname - file in which marked up image descriptions are stored

  6. * num - desired number of samples

  7. * showsamples - if not 0 samples will be shown

  8. * winwidth - sample width

  9. * winheight - sample height

  10. *

  11. * Return number of successfully created samples

  12. */

  13. int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,

  14. int num,

  15. int showsamples,

  16. int winwidth, int winheight )

函式內容:讀取當前圖中所有標記的sample(x,y,w,h),並將其縮放到winwidth、winheight大小,故在這之前的人為縮放操作不需要

(可以看到,僅需要num、w、h引數)
4)僅vecname時,可以將vec裡面的所有縮放後的samples都顯示出來

[cpp] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片

  1. /* 
  2.  * cvShowVecSamples 
  3.  * 
  4.  * Shows samples stored in .vec file 
  5.  * 
  6.  * filename 
  7.  *   .vec file name 
  8.  * winwidth 
  9.  *   sample width 
  10.  * winheight 
  11.  *   sample height 
  12.  * scale 
  13.  *   the scale each sample is adjusted to(這個scale與3中的縮放不是一回事,這裡僅為了顯示而再次縮放) 
  14.  */  
  15. void cvShowVecSamples( const char* filename, int winwidth, int winheight, double scale );
  1. /*

  2. * cvShowVecSamples

  3. *

  4. * Shows samples stored in .vec file

  5. *

  6. * filename

  7. * .vec file name

  8. * winwidth

  9. * sample width

  10. * winheight

  11. * sample height

  12. * scale

  13. * the scale each sample is adjusted to(這個scale與3中的縮放不是一回事,這裡僅為了顯示而再次縮放)

  14. */

  15. void cvShowVecSamples( const char* filename, int winwidth, int winheight, double scale );

訓練樣本分為正例樣本和反例樣本,其中正例樣本是指待檢目標樣本,反例樣本指其它任意圖片。
負樣本
負樣本可以來自於任意的圖片,但這些圖片不能包含目標特徵。負樣本由背景描述檔案來描述。背景描述檔案是一個文字檔案,每一行包含了一個負樣本圖片的檔名(基於描述檔案的相對路徑)。該檔案建立方法如下:

採用Dos命令生成樣本描述檔案。具體方法是在Dos下的進入你的圖片目錄,比如我的圖片放在D:\face\posdata下,則:

按Ctrl+R開啟Windows執行程式,輸入cmd開啟DOS命令視窗,輸入d:回車,再輸入cd D:\face\negdata進入圖片路徑,再次輸入dir /b > negdata.dat,則會圖片路徑下生成一個negdata.dat檔案,開啟該檔案將最後一行的negdata.dat刪除,這樣就生成了負樣本描述檔案。

樣本製作完成,下面訓練。

2、opencv_haartraining.exe的引數

(haartraining.cpp )

[cpp] view plain copy print?在CODE上檢視程式碼片派生到我的程式碼片

  1. "  -data <dir_name>\n"  
  2. "  -vec <vec_file_name>\n"  
  3. "  -bg <background_file_name>\n"  
  4. "  [-bg-vecfile]\n"  
  5. "  [-npos <number_of_positive_samples = %d>]\n"  
  6. "  [-nneg <number_of_negative_samples = %d>]\n"  
  7. "  [-nstages <number_of_stages = %d>]\n"  
  8. "  [-nsplits <number_of_splits = %d>]\n"  
  9. "  [-mem <memory_in_MB = %d>]\n"  
  10. "  [-sym (default)] [-nonsym]\n"  
  11. "  [-minhitrate <min_hit_rate = %f>]\n"  
  12. "  [-maxfalsealarm <max_false_alarm_rate = %f>]\n"  
  13. "  [-weighttrimming <weight_trimming = %f>]\n"  
  14. "  [-eqw]\n"  
  15. "  [-mode <BASIC (default) | CORE | ALL>]\n"  
  16. "  [-w <sample_width = %d>]\n"  
  17. "  [-h <sample_height = %d>]\n"  
  18. "  [-bt <DAB | RAB | LB | GAB (default)>]\n"  
  19. "  [-err <misclass (default) | gini | entropy>]\n"  
  20. "  [-maxtreesplits <max_number_of_splits_in_tree_cascade = %d>]\n"  
  21. "  [-minpos <min_number_of_positive_samples_per_cluster = %d>]\n" 
  1. " -data <dir_name>\n"

  2. " -vec <vec_file_name>\n"

  3. " -bg <background_file_name>\n"

  4. " [-bg-vecfile]\n"

  5. " [-npos <number_of_positive_samples = %d>]\n"

  6. " [-nneg <number_of_negative_samples = %d>]\n"

  7. " [-nstages <number_of_stages = %d>]\n"

  8. " [-nsplits <number_of_splits = %d>]\n"

  9. " [-mem <memory_in_MB = %d>]\n"

  10. " [-sym (default)] [-nonsym]\n"

  11. " [-minhitrate <min_hit_rate = %f>]\n"

  12. " [-maxfalsealarm <max_false_alarm_rate = %f>]\n"

  13. " [-weighttrimming <weight_trimming = %f>]\n"

  14. " [-eqw]\n"

  15. " [-mode <BASIC (default) | CORE | ALL>]\n"

  16. " [-w <sample_width = %d>]\n"

  17. " [-h <sample_height = %d>]\n"

  18. " [-bt <DAB | RAB | LB | GAB (default)>]\n"

  19. " [-err <misclass (default) | gini | entropy>]\n"

  20. " [-maxtreesplits <max_number_of_splits_in_tree_cascade = %d>]\n"

  21. " [-minpos <min_number_of_positive_samples_per_cluster = %d>]\n"

  1. " -data <dir_name>\n"

  2. " -vec <vec_file_name>\n"

  3. " -bg <background_file_name>\n"

  4. " [-bg-vecfile]\n"

  5. " [-npos <number_of_positive_samples = %d>]\n"

  6. " [-nneg <number_of_negative_samples = %d>]\n"

  7. " [-nstages <number_of_stages = %d>]\n"

  8. " [-nsplits <number_of_splits = %d>]\n"

  9. " [-mem <memory_in_MB = %d>]\n"

  10. " [-sym (default)] [-nonsym]\n"

  11. " [-minhitrate <min_hit_rate = %f>]\n"

  12. " [-maxfalsealarm <max_false_alarm_rate = %f>]\n"

  13. " [-weighttrimming <weight_trimming = %f>]\n"

  14. " [-eqw]\n"

  15. " [-mode <BASIC (default) | CORE | ALL>]\n"

  16. " [-w <sample_width = %d>]\n"

  17. " [-h <sample_height = %d>]\n"

  18. " [-bt <DAB | RAB | LB | GAB (default)>]\n"

  19. " [-err <misclass (default) | gini | entropy>]\n"

  20. " [-maxtreesplits <max_number_of_splits_in_tree_cascade = %d>]\n"

  21. " [-minpos <min_number_of_positive_samples_per_cluster = %d>]\n"

樣本建立之後,接下來要訓練分類器,這個過程是由haartraining程式來實現的。該程式原始碼由OpenCV自帶,且可執行程式在OpenCV安裝目錄的bin目錄下。
Haartraining的命令列引數如下:
-data<dir_name>
存放訓練好的分類器的路徑名。
-vec<vec_file_name>
正樣本檔名(由trainingssamples程式或者由其他的方法建立的)
-bg<background_file_name>
背景描述檔案。
-npos<number_of_positive_samples>,
-nneg<number_of_negative_samples>
用來訓練每一個分類器階段的正/負樣本。合理的值是:nPos = 7000;nNeg = 3000
-nstages<number_of_stages>
訓練的階段數。
-nsplits<number_of_splits>
決定用於階段分類器的弱分類器。如果1,則一個簡單的stump classifier被使用。如果是2或者更多,則帶有number_of_splits個內部節點的CART分類器被使用。
-mem<memory_in_MB>
預先計算的以MB為單位的可用記憶體。記憶體越大則訓練的速度越快。
-sym(default)
-nonsym
指定訓練的目標物件是否垂直對稱。垂直對稱提高目標的訓練速度。例如,正面部是垂直對稱的。
-minhitrate《min_hit_rate》
每個階段分類器需要的最小的命中率。總的命中率為min_hit_rate的number_of_stages次方。
-maxfalsealarm<max_false_alarm_rate>
沒有階段分類器的最大錯誤報警率。總的錯誤警告率為max_false_alarm_rate的number_of_stages次方。
-weighttrimming<weight_trimming>
指定是否使用權修正和使用多大的權修正。一個基本的選擇是0.9
-eqw
-mode<basic(default)|core|all>
選擇用來訓練的haar特徵集的種類。basic僅僅使用垂直特徵。all使用垂直和45度角旋轉特徵。
-w《sample_width》
-h《sample_height》
訓練樣本的尺寸,(以畫素為單位)。必須和訓練樣本建立的尺寸相同。
一個訓練分類器的例子:
"D:\Program Files\OpenCV\bin\haartraining.exe"   -data data\cascade -vec data\pos.vec -bg negdata\negdata.dat -npos 49 -nneg 49 -mem 200 -mode ALL -w 20 -h 20

訓練結束後,會在目錄data下生成一些子目錄,即為訓練好的分類器。

這一步需要用到performance.exe,該程式原始碼由OpenCV自帶,且可執行程式在OpenCV安裝目錄的bin目錄下。

performance.exe -data data/cascade -info posdata/test.dat -w 20 -h 20 -rs 30

performance的命令列引數如下:

Usage: ./performance
-data <classifier_directory_name>
-info <collection_file_name>
[-maxSizeDiff <max_size_difference = 1.500000>]
[-maxPosDiff <max_position_difference = 0.300000>]
[-sf <scale_factor = 1.200000>]
[-ni]
[-nos <number_of_stages = -1>]
[-rs <roc_size = 40>]
[-w <sample_width = 24>]
[-h <sample_height = 24>]

也可以用opencv的cvHaarDetectObjects函式進行檢測:

CvSeq* faces = cvHaarDetectObjects( img, cascade, storage,1.1, 2, CV_HAAR_DO_CANNY_PRUNING,cvSize(40, 40) ); //3. 檢測人臉

使用心得: