Haar特征原理与icvCreateIntHaarFeatures方法的具体实现附详细注释—— 人脸识别的尝试系列(二)
帶著強烈的興趣,上周開始人臉識別的嘗試與學習,并且將具體的操作過程記錄了下來
鏈接如下:http://blog.csdn.net/u011583927/article/details/44627493
這周開始了對于算法的深入學習,下面進入正題。
Haar特征的原理是什么?
Haar特征分為三類:邊緣特征、線性特征、中心特征和對角線特征,組合成特征模板。特征模板內有白色和黑色兩種矩形,并定義該模板的特征值為白色矩形像素和減去黑色矩形像素和(在opencv實現中為黑色-白色)。Haar特征值反映了圖像的灰度變化情況。例如:臉部的一些特征能由矩形特征簡單的描述,如:眼睛要比臉頰顏色要深,鼻梁兩側比鼻梁顏色要深,嘴巴比周圍顏色要深等。但矩形特征只對一些簡單的圖形結構,如邊緣、線段較敏感,所以只能描述特定走向(水平、垂直、對角)的結構。(本段文字及下面兩幅圖引用自http://blog.csdn.net/zouxy09/article/details/7929570)
Viola提出的haar特征:
?
Lienhart等牛們提出的Haar-like特征:
?
矩形特征可位于圖像任意位置,大小也可以任意改變,所以矩形特征值是矩形模版類別、矩形位置和矩形大小這三個因素的函數,當然對于新提出的有旋轉角度的haar特征,還要把旋轉的因素考慮進去。
所以一個Haar特征的數據結構應該包含以下內容:?
*haar特征模板類型
*是否有旋轉
*矩陣位置及大小
?
CvIntHaarFeatures是如何構成的?
在Opencv中,我們用CvTHaarFeature和CvFastHaarFeature作為描述單個特征的數據結構,用CvIntHaarFeatures作為一個封裝的類型,通過這個類型中的兩個指針(分別是CvTHaarFeature*和CvFastHaarFeature*指針)可以間接遍尋到存儲的所有的特征。下面來看下它們的具體構造
CvTHaarFeature的數據結構:
//CvTHaarFeature:由(至多三個)矩形表示特征位置
typedef?struct?CvTHaarFeature
{
????char?desc[CV_HAAR_FEATURE_DESC_MAX];?? //描述haar特征模板類型的變量
????int??tilted; //標識是否有旋轉,通過desc字符數組開頭是否為tilted判斷
????struct
????{
????????CvRect?r;
????????float?weight;
????}?rect[CV_HAAR_FEATURE_MAX];??????????? //三個矩形來描述特征位置
}?CvTHaarFeature;
?
?
創建一個CvTHaarFeature特征:
/*例:haarFeature = cvHaarFeature("tilted_haar_y2",
??????????????????????????????????? x, y, dx,2*dy, -1,
??????????????????????????????????? x, y,dx,?? dy, +2 );*/
CV_INLINECvTHaarFeature cvHaarFeature(const char* desc,
??????????????????????????? int x0, int y0, int w0,int h0, float wt0,
??????????????????????????? int x1, int y1, int w1,int h1, float wt1,
??????????????????????????? int x2, int y2, int w2,int h2, float wt2 )
{
??? CvTHaarFeature hf;
?
??? assert( CV_HAAR_FEATURE_MAX >= 3 );
??? assert( strlen( desc ) <CV_HAAR_FEATURE_DESC_MAX );
?
??? strcpy( &(hf.desc[0]), desc );
??? hf.tilted = ( hf.desc[0] == 't' );
?
??? hf.rect[0].r.x = x0;
??? hf.rect[0].r.y = y0;
??? hf.rect[0].r.width? = w0;
??? hf.rect[0].r.height = h0;
??? hf.rect[0].weight?? = wt0;
?
??? hf.rect[1].r.x = x1;
??? hf.rect[1].r.y = y1;
??? hf.rect[1].r.width? = w1;
??? hf.rect[1].r.height = h1;
??? hf.rect[1].weight?? = wt1;
?
??? hf.rect[2].r.x = x2;
??? hf.rect[2].r.y = y2;
??? hf.rect[2].r.width? = w2;
??? hf.rect[2].r.height = h2;
??? hf.rect[2].weight?? = wt2;
?
??? return hf;
}
?
?
CvFastHaarFeature的數據結構:
//與CvTHaarFeature類似,不同的是通過4個點來描述特征矩形的位置大小信息
typedef?struct?CvFastHaarFeature
{
????int?tilted;
????struct
????{
????????int?p0,?p1,?p2,?p3;
????????float?weight;
????}?rect[CV_HAAR_FEATURE_MAX];
}?CvFastHaarFeature;
?
CvIntHaarFeatures的數據結構:
typedef?struct?CvIntHaarFeatures
{
????CvSize?winsize;
????int?count;
????CvTHaarFeature*?feature;
????CvFastHaarFeature*?fastfeature;
}?CvIntHaarFeatures;
了解了如何構成,我們就來創建,icvCreateIntHaarFeatures()方法的具體實現:
接下來就是最重要的一步,如何創建我們想要得到的所有特征信息及CvIntHaarFeatures,下面是icvCreateIntHaarFeatures方法的具體實現和詳細注釋
由于opencv和C++都是初學,用了很長時間寫了大量注釋,0基礎也絕對能看懂,希望能對大家有幫助
/** icvCreateIntHaarFeatures** Create internal representation of haar features** mode:* 0 - BASIC = Viola提出的原始舉行特征* 1 - CORE = All upright 所有垂直的haar特征* 2 - ALL = All features 所有haar特征*symmetric: 目標圖形是否為垂直對稱 */ static CvIntHaarFeatures* icvCreateIntHaarFeatures( CvSize winsize,int mode,int symmetric ) {CvIntHaarFeatures* features = NULL;CvTHaarFeature haarFeature;/*內存存儲器是一個可用來存儲諸如序列,輪廓,圖形,子劃分等動態增長數據結構的底層結構。它是由一系列以同等大小的內存塊構成,呈列表型*/CvMemStorage* storage = NULL;CvSeq* seq = NULL;CvSeqWriter writer;int s0 = 36; /* minimum total area size of basic haar feature */int s1 = 12; /* minimum total area size of tilted(傾斜的) haar features 2 */int s2 = 18; /* minimum total area size of tilted haar features 3 */int s3 = 24; /* minimum total area size of tilted haar features 4 */int x = 0;int y = 0;int dx = 0;int dy = 0;#if 0float factor = 1.0F;factor = ((float) winsize.width) * winsize.height / (24 * 24);s0 = (int) (s0 * factor);s1 = (int) (s1 * factor);s2 = (int) (s2 * factor);s3 = (int) (s3 * factor); #else//程序必然走這邊,為什么這么寫?s0 = 1;s1 = 1;s2 = 1;s3 = 1; #endif/* CV_VECTOR_CREATE( vec, CvIntHaarFeature, size, maxsize ) */ storage = cvCreateMemStorage();//功能:創建新序列,并初始化寫入部分 /*我的理解:這里其實是定義了writer工具每次寫入數據的大小,以及寫入到哪個內存存儲器 在之后調用 CV_WRITE_SEQ_ELEM( haarFeature, writer )時就可以自動將一個haarFeature類型的數據寫入內存存儲器中*/cvStartWriteSeq( 0, sizeof( CvSeq ), sizeof( haarFeature ), storage, &writer );/*矩形特征可位于圖像任意位置,大小也可以任意改變,所以矩形特征值是矩形模版類別、矩形位置和矩形大小這三個因素的函數*/for( x = 0; x < winsize.width; x++ ){for( y = 0; y < winsize.height; y++ ){//x,y確定了特征矩形的左上角坐標for( dx = 1; dx <= winsize.width; dx++ ){for( dy = 1; dy <= winsize.height; dy++ ){//dx,dy確定了特征矩形的大小//下面需要按照不同的特征模板類型分別討論,在模板不越界的情況下,添 加該特征// haar_x2 對應上圖中的(a)特征模板,黑色為+,白色為-if ( (x+dx*2 <= winsize.width) && (y+dy <= winsize.height) ) {if (dx*2*dy < s0) continue;if (!symmetric || (x+x+dx*2 <=winsize.width)) {//目標圖像不為垂直對稱或目標垂直對稱但滿足上式條件//若目標不垂直對稱,顯然要計算當前矩形特征的特征值//若對稱,則只計算左半部分全部位于標準樣本左半邊的矩形特征的特征值haarFeature = cvHaarFeature( "haar_x2",x, y, dx*2, dy, -1,x+dx, y, dx , dy, +2 );/* CV_VECTOR_PUSH( vec, CvIntHaarFeature, haarFeature, size, maxsize, step ) */CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// haar_y2 對應上圖中的(b)特征模板if ( (x+dx <= winsize.width) && (y+dy*2 <= winsize.height) ) {if (dx*2*dy < s0) continue;if (!symmetric || (x+x+dx <= winsize.width)) {haarFeature = cvHaarFeature( "haar_y2",x, y, dx, dy*2, -1,x, y+dy, dx, dy, +2 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// haar_x3 對應上圖中的(c)特征模板if ( (x+dx*3 <= winsize.width) && (y+dy <= winsize.height) ) {if (dx*3*dy < s0) continue;if (!symmetric || (x+x+dx*3 <=winsize.width)) {haarFeature = cvHaarFeature( "haar_x3",x, y, dx*3, dy, -1,x+dx, y, dx, dy, +3 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// haar_y3 對應上圖中的(d)特征模板if ( (x+dx <= winsize.width) && (y+dy*3 <= winsize.height) ) {if (dx*3*dy < s0) continue;if (!symmetric || (x+x+dx <= winsize.width)) {haarFeature = cvHaarFeature( "haar_y3",x, y, dx, dy*3, -1,x, y+dy, dx, dy, +3 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}if( mode != 0 /*BASIC*/ ) {// haar_x4 對應上圖中的(2b)特征模板if ( (x+dx*4 <= winsize.width) && (y+dy <= winsize.height) ) {if (dx*4*dy < s0) continue;if (!symmetric || (x+x+dx*4 <=winsize.width)) {haarFeature = cvHaarFeature( "haar_x4",x, y, dx*4, dy, -1,x+dx, y, dx*2, dy, +2 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// haar_y4 對應上圖中的(2d)特征模板if ( (x+dx <= winsize.width ) && (y+dy*4 <= winsize.height) ) {if (dx*4*dy < s0) continue;if (!symmetric || (x+x+dx <=winsize.width)) {haarFeature = cvHaarFeature( "haar_y4",x, y, dx, dy*4, -1,x, y+dy, dx, dy*2, +2 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}}// x2_y2 對應上圖中的(e)特征模板if ( (x+dx*2 <= winsize.width) && (y+dy*2 <= winsize.height) ) {if (dx*4*dy < s0) continue;if (!symmetric || (x+x+dx*2 <=winsize.width)) {haarFeature = cvHaarFeature( "haar_x2_y2",x , y, dx*2, dy*2, -1,x , y , dx , dy, +2,x+dx, y+dy, dx , dy, +2 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}if (mode != 0 /*BASIC*/) {// point 對應上圖中的(3a)特征模板if ( (x+dx*3 <= winsize.width) && (y+dy*3 <= winsize.height) ) {if (dx*9*dy < s0) continue;if (!symmetric || (x+x+dx*3 <=winsize.width)) {haarFeature = cvHaarFeature( "haar_point",x , y, dx*3, dy*3, -1,x+dx, y+dy, dx , dy , +9);CV_WRITE_SEQ_ELEM( haarFeature, writer );}}}if (mode == 2 /*ALL*/) {// tilted haar_x2 (x, y, w, h, b, weight)//對應上圖中的(1c)特征模板if ( (x+2*dx <= winsize.width) && (y+2*dx+dy <= winsize.height) && (x-dy>= 0) ) {if (dx*2*dy < s1) continue;if (!symmetric || (x <= (winsize.width / 2) )) {haarFeature = cvHaarFeature( "tilted_haar_x2",x, y, dx*2, dy, -1,x, y, dx , dy, +2 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// tilted haar_y2 (x, y, w, h, b, weight)//對應上圖中的(1d)特征模板if ( (x+dx <= winsize.width) && (y+dx+2*dy <= winsize.height) && (x-2*dy>= 0) ) {if (dx*2*dy < s1) continue;if (!symmetric || (x <= (winsize.width / 2) )) {haarFeature = cvHaarFeature( "tilted_haar_y2",x, y, dx, 2*dy, -1,x, y, dx, dy, +2 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// tilted haar_x3 (x, y, w, h, b, weight)if ( (x+3*dx <= winsize.width) && (y+3*dx+dy <= winsize.height) && (x-dy>= 0) ) {if (dx*3*dy < s2) continue;if (!symmetric || (x <= (winsize.width / 2) )) {haarFeature = cvHaarFeature( "tilted_haar_x3",x, y, dx*3, dy, -1,x+dx, y+dx, dx , dy, +3 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// tilted haar_y3 (x, y, w, h, b, weight)if ( (x+dx <= winsize.width) && (y+dx+3*dy <= winsize.height) && (x-3*dy>= 0) ) {if (dx*3*dy < s2) continue;if (!symmetric || (x <= (winsize.width / 2) )) {haarFeature = cvHaarFeature( "tilted_haar_y3",x, y, dx, 3*dy, -1,x-dy, y+dy, dx, dy, +3 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// tilted haar_x4 (x, y, w, h, b, weight)if ( (x+4*dx <= winsize.width) && (y+4*dx+dy <= winsize.height) && (x-dy>= 0) ) {if (dx*4*dy < s3) continue;if (!symmetric || (x <= (winsize.width / 2) )) {haarFeature = cvHaarFeature( "tilted_haar_x4",x, y, dx*4, dy, -1,x+dx, y+dx, dx*2, dy, +2 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}// tilted haar_y4 (x, y, w, h, b, weight)if ( (x+dx <= winsize.width) && (y+dx+4*dy <= winsize.height) && (x-4*dy>= 0) ) {if (dx*4*dy < s3) continue;if (!symmetric || (x <= (winsize.width / 2) )) {haarFeature = cvHaarFeature( "tilted_haar_y4",x, y, dx, 4*dy, -1,x-dy, y+dy, dx, 2*dy, +2 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}/*// tilted pointif ( (x+dx*3 <= winsize.width - 1) && (y+dy*3 <= winsize.height - 1) && (x-3*dy>= 0)) {if (dx*9*dy < 36) continue;if (!symmetric || (x <= (winsize.width / 2) )) {haarFeature = cvHaarFeature( "tilted_haar_point",x, y, dx*3, dy*3, -1,x, y+dy, dx , dy, +9 );CV_WRITE_SEQ_ELEM( haarFeature, writer );}}*/}}}}}/*我的理解:當前已經完成了數據的寫入,但是是存儲在內存存儲器中的,調用此方法將存儲器中的所有數據轉移到cvSeq中*/ seq = cvEndWriteSeq( &writer );在OpenCV中臨時緩存用cvAlloc和cvFree函數分配和回收.函數應注意適當對齊,對未釋放的內存保持跟蹤,檢查溢出。features = (CvIntHaarFeatures*) cvAlloc( sizeof( CvIntHaarFeatures ) +( sizeof( CvTHaarFeature ) + sizeof( CvFastHaarFeature ) ) * seq->total );features->feature = (CvTHaarFeature*) (features + 1);features->fastfeature = (CvFastHaarFeature*) ( features->feature + seq->total );features->count = seq->total;features->winsize = winsize;cvCvtSeqToArray( seq, (CvArr*) features->feature );cvReleaseMemStorage( &storage );//特征的rect由坐標表示轉換為由像素索引表示icvConvertToFastHaarFeature( features->feature, features->fastfeature,features->count, (winsize.width + 1) );return features; }
由于我是小白,感覺上面代碼中的最后幾行邏輯可能比較繞,卡在那里好久終于理解。
所以做了一張圖,可以借助下圖幫助理解
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的Haar特征原理与icvCreateIntHaarFeatures方法的具体实现附详细注释—— 人脸识别的尝试系列(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: grubbs检测c语言,Grubbs算法
- 下一篇: word如何设置长宽高_word怎么设计