人臉識別之人臉檢測(二)--人臉識別樣本製作及訓練測試
閒得沒事,折騰下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 *)" (
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?
- " [-info <collection_file_name>]\n"
- " [-img <image_file_name>]\n"
- " [-vec <vec_file_name>]\n"
- " [-bg <background_file_name>]\n [-num <number_of_samples = %d>]\n"
- " [-bgcolor <background_color = %d>]\n"
- " [-inv] [-randinv] [-bgthresh <background_color_threshold = %d>]\n"
- " [-maxidev <max_intensity_deviation = %d>]\n"
- " [-maxxangle <max_x_rotation_angle = %f>]\n"
- " [-maxyangle <max_y_rotation_angle = %f>]\n"
- " [-maxzangle <max_z_rotation_angle = %f>]\n"
- " [-show [<scale = %f>]]\n"
- " [-w <sample_width = %d>]\n [-h <sample_height = %d>]\n"//預設24*24
-
" [-info <collection_file_name>]\n"
-
" [-img <image_file_name>]\n"
-
" [-vec <vec_file_name>]\n"
-
" [-bg <background_file_name>]\n [-num <number_of_samples = %d>]\n"
-
" [-bgcolor <background_color = %d>]\n"
-
" [-inv] [-randinv] [-bgthresh <background_color_threshold = %d>]\n"
-
" [-maxidev <max_intensity_deviation = %d>]\n"
-
" [-maxxangle <max_x_rotation_angle = %f>]\n"
-
" [-maxyangle <max_y_rotation_angle = %f>]\n"
-
" [-maxzangle <max_z_rotation_angle = %f>]\n"
-
" [-show [<scale = %f>]]\n"
-
" [-w <sample_width = %d>]\n [-h <sample_height = %d>]\n"//預設24*24
以下1)~4)是按順序判斷,且有且僅有一個
1)提供imagename 和vecname時,呼叫以下操作
[cpp] view plain copy print?
- /*
- * cvCreateTrainingSamples
- *
- * Create training samples applying random distortions to sample image and
- * store them in .vec file
- *
- * filename - .vec file name
- * imgfilename - sample image file name
- * bgcolor - background color for sample image
- * bgthreshold - background color threshold. Pixels those colors are in range
- * [bgcolor-bgthreshold, bgcolor+bgthreshold] are considered as transparent
- * bgfilename - background description file name. If not NULL samples
- * will be put on arbitrary background
- * count - desired number of samples
- * invert - if not 0 sample foreground pixels will be inverted
- * if invert == CV_RANDOM_INVERT then samples will be inverted randomly
- * maxintensitydev - desired max intensity deviation of foreground samples pixels
- * maxxangle - max rotation angles
- * maxyangle
- * maxzangle
- * showsamples - if not 0 samples will be shown
- * winwidth - desired samples width
- * winheight - desired samples height
- */
-
/*
-
* cvCreateTrainingSamples
-
*
-
* Create training samples applying random distortions to sample image and
-
* store them in .vec file
-
*
-
* filename - .vec file name
-
* imgfilename - sample image file name
-
* bgcolor - background color for sample image
-
* bgthreshold - background color threshold. Pixels those colors are in range
-
* [bgcolor-bgthreshold, bgcolor+bgthreshold] are considered as transparent
-
* bgfilename - background description file name. If not NULL samples
-
* will be put on arbitrary background
-
* count - desired number of samples
-
* invert - if not 0 sample foreground pixels will be inverted
-
* if invert == CV_RANDOM_INVERT then samples will be inverted randomly
-
* maxintensitydev - desired max intensity deviation of foreground samples pixels
-
* maxxangle - max rotation angles
-
* maxyangle
-
* maxzangle
-
* showsamples - if not 0 samples will be shown
-
* winwidth - desired samples width
-
* winheight - desired samples height
-
*/
2)提供imagename、bgfilename和infoname時
與1)類似
3)提供 infoname和 vecname時,呼叫以下操作(這裡是我們訓練需要的)
[cpp] view plain copy print?
- /*
- * cvCreateTrainingSamplesFromInfo
- *
- * Create training samples from a set of marked up images and store them into .vec file
- * infoname - file in which marked up image descriptions are stored
- * num - desired number of samples
- * showsamples - if not 0 samples will be shown
- * winwidth - sample width
- * winheight - sample height
- *
- * Return number of successfully created samples
- */
- int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,
- int num,
- int showsamples,
- int winwidth, int winheight )
-
/*
-
* cvCreateTrainingSamplesFromInfo
-
*
-
* Create training samples from a set of marked up images and store them into .vec file
-
* infoname - file in which marked up image descriptions are stored
-
* num - desired number of samples
-
* showsamples - if not 0 samples will be shown
-
* winwidth - sample width
-
* winheight - sample height
-
*
-
* Return number of successfully created samples
-
*/
-
int cvCreateTrainingSamplesFromInfo( const char* infoname, const char* vecfilename,
-
int num,
-
int showsamples,
-
int winwidth, int winheight )
函式內容:讀取當前圖中所有標記的sample(x,y,w,h),並將其縮放到winwidth、winheight大小,故在這之前的人為縮放操作不需要
(可以看到,僅需要num、w、h引數)
4)僅vecname時,可以將vec裡面的所有縮放後的samples都顯示出來
[cpp] view plain copy print?
- /*
- * cvShowVecSamples
- *
- * Shows samples stored in .vec file
- *
- * filename
- * .vec file name
- * winwidth
- * sample width
- * winheight
- * sample height
- * scale
- * the scale each sample is adjusted to(這個scale與3中的縮放不是一回事,這裡僅為了顯示而再次縮放)
- */
- void cvShowVecSamples( const char* filename, int winwidth, int winheight, double scale );
-
/*
-
* cvShowVecSamples
-
*
-
* Shows samples stored in .vec file
-
*
-
* filename
-
* .vec file name
-
* winwidth
-
* sample width
-
* winheight
-
* sample height
-
* scale
-
* the scale each sample is adjusted to(這個scale與3中的縮放不是一回事,這裡僅為了顯示而再次縮放)
-
*/
-
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?
- " -data <dir_name>\n"
- " -vec <vec_file_name>\n"
- " -bg <background_file_name>\n"
- " [-bg-vecfile]\n"
- " [-npos <number_of_positive_samples = %d>]\n"
- " [-nneg <number_of_negative_samples = %d>]\n"
- " [-nstages <number_of_stages = %d>]\n"
- " [-nsplits <number_of_splits = %d>]\n"
- " [-mem <memory_in_MB = %d>]\n"
- " [-sym (default)] [-nonsym]\n"
- " [-minhitrate <min_hit_rate = %f>]\n"
- " [-maxfalsealarm <max_false_alarm_rate = %f>]\n"
- " [-weighttrimming <weight_trimming = %f>]\n"
- " [-eqw]\n"
- " [-mode <BASIC (default) | CORE | ALL>]\n"
- " [-w <sample_width = %d>]\n"
- " [-h <sample_height = %d>]\n"
- " [-bt <DAB | RAB | LB | GAB (default)>]\n"
- " [-err <misclass (default) | gini | entropy>]\n"
- " [-maxtreesplits <max_number_of_splits_in_tree_cascade = %d>]\n"
- " [-minpos <min_number_of_positive_samples_per_cluster = %d>]\n"
-
" -data <dir_name>\n"
-
" -vec <vec_file_name>\n"
-
" -bg <background_file_name>\n"
-
" [-bg-vecfile]\n"
-
" [-npos <number_of_positive_samples = %d>]\n"
-
" [-nneg <number_of_negative_samples = %d>]\n"
-
" [-nstages <number_of_stages = %d>]\n"
-
" [-nsplits <number_of_splits = %d>]\n"
-
" [-mem <memory_in_MB = %d>]\n"
-
" [-sym (default)] [-nonsym]\n"
-
" [-minhitrate <min_hit_rate = %f>]\n"
-
" [-maxfalsealarm <max_false_alarm_rate = %f>]\n"
-
" [-weighttrimming <weight_trimming = %f>]\n"
-
" [-eqw]\n"
-
" [-mode <BASIC (default) | CORE | ALL>]\n"
-
" [-w <sample_width = %d>]\n"
-
" [-h <sample_height = %d>]\n"
-
" [-bt <DAB | RAB | LB | GAB (default)>]\n"
-
" [-err <misclass (default) | gini | entropy>]\n"
-
" [-maxtreesplits <max_number_of_splits_in_tree_cascade = %d>]\n"
-
" [-minpos <min_number_of_positive_samples_per_cluster = %d>]\n"
-
" -data <dir_name>\n"
-
" -vec <vec_file_name>\n"
-
" -bg <background_file_name>\n"
-
" [-bg-vecfile]\n"
-
" [-npos <number_of_positive_samples = %d>]\n"
-
" [-nneg <number_of_negative_samples = %d>]\n"
-
" [-nstages <number_of_stages = %d>]\n"
-
" [-nsplits <number_of_splits = %d>]\n"
-
" [-mem <memory_in_MB = %d>]\n"
-
" [-sym (default)] [-nonsym]\n"
-
" [-minhitrate <min_hit_rate = %f>]\n"
-
" [-maxfalsealarm <max_false_alarm_rate = %f>]\n"
-
" [-weighttrimming <weight_trimming = %f>]\n"
-
" [-eqw]\n"
-
" [-mode <BASIC (default) | CORE | ALL>]\n"
-
" [-w <sample_width = %d>]\n"
-
" [-h <sample_height = %d>]\n"
-
" [-bt <DAB | RAB | LB | GAB (default)>]\n"
-
" [-err <misclass (default) | gini | entropy>]\n"
-
" [-maxtreesplits <max_number_of_splits_in_tree_cascade = %d>]\n"
-
" [-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. 檢測人臉
使用心得: