首先說一下這個級聯分類器,OpenCV中級聯分類器是根據VJ 04年的那篇論文(Robust Real-Time Face Detection)編寫的,查看那篇論文,知道構建分類器的步驟如下:
1、根據haar-like特征訓練多個弱分類器
2、使用adaboost算法將多個弱分類器組合成一個強分類器
3、最終的分類器是由多個強分類器級聯而成
下面這幅圖是弱分類器組合成強分類器的示意圖(圖片來源於網絡):
下面這張是多個強分類器級聯的示意圖(圖片來源於網絡):
在了解了級聯分類器是怎么一回事后,我們來看一看OpenCV里面級聯分類器的結構
在調用OpenCV中的級聯分類器對目標進行分類時,都會將一個訓練好的分類器(一個訓練好的.xml文件)讀入到一個CvHaarClassifierCascade結構中,如下:
1 CvHaarClassifierCascade* cascade = (CvHaarClassifierCascade*)cvLoad( "haarcascade_frontalface_alt.xml", 0, 0, 0 );
那么這個CvHaarClassifierCascade結構體里面的內容都有哪些呢?
1 typedef struct CvHaarClassifierCascade 2 { 3 int flags; /* 標志位 */ 4 int count; /* 分級分類器中強分類器的數量 */ 5 CvSize orig_window_size; /* 訓練中原始目標的大小 */ 6 7 /* these two parameters are set by cvSetImagesForHaarClassifierCascade */ 8 CvSize real_window_size; /* 待檢測物體的大小 */ 9 double scale; /* Haar塊縮放的尺寸 */ 10 11 CvHaarStageClassifier* stage_classifier; /* 定義強分類器數組 */ 12 CvHidHaarClassifierCascade* hid_cascade; 13 }CvHaarClassifierCascade;
第一個flags,還不是很清楚,在debug模式下,flags=1112539136(好吧,這個值很詭異),我也不是很清楚
第二個count,表示整個分級分類器中強分類器的數量,即最后參與級聯的強分類器的個數
第三個orig_window_size,表示的是在訓練時用的正樣本的尺寸,OpenCV中的尺寸是20x20
第四個和第五個,注釋中說了,這兩個參數需要自己設置,具體每個參數看注釋
第六個stage_classifier,是強分類器指針,指向一個強分類器數組,之前的count是多少,那么此處的強分類器就有多少
最后一個hid_cascade,還不是很清楚
下面來看上面第六個參數的強分類器結構體
1 typedef struct CvHaarStageClassifier 2 { 3 int count; /* number of classifiers in the battery 構成強分類器的弱分類器的數量*/ 4 float threshold; /* threshold for the boosted classifier 疊加分類器的閾值*/ 5 CvHaarClassifier* classifier; /* array of classifiers 定義分類器數組*/ 6 /* these fields are used for organizing trees of stage classifiers, 7 rather than just stright cascades */ 8 int next; 9 int child; 10 int parent; 11 }CvHaarStageClassifier;
第一個count,表示該強分類器中,弱分類器的數量,即該強分類器由多少個弱分類器組成
第二個threshold,疊加分類器的閾值(好吧。。這個我也不知道)
第三個classifier,是一個指針,指向的是一個弱分類器數組,之前的count是多少,此處的弱分類器就有多少
后面3個都不清楚。。。(望知道的網友給予幫助)
下面是弱分類器的結構
1 typedef struct CvHaarClassifier 2 { 3 int count; /* number of nodes in the decision tree */ 4 /* these are "parallel" arrays. Every index i corresponds to a node of the decision tree (root has 0-th index). 5 left[i] - index of the left child (or negated index if the left child is a leaf) 6 right[i] - index of the right child (or negated index if the right child is a leaf) 7 threshold[i] - branch threshold. if feature responce is <= threshold, left branch is chosen, otherwise right branch is chosed. 8 alpha[i] - output value correponding to the leaf. */ 9 10 CvHaarFeature* haar_feature; 11 float* threshold; 12 int* left; 13 int* right; 14 float* alpha; 15 }CvHaarClassifier;
第一個count,在opencv里,發現始終都是1,自己想了想,因為這個結構體記錄的是一個弱分類器,自然弱分類器的個數就是1了。
第二個haar_feature,也是一個指針,指向一個(因為count是1)特征結構體CvHaarFeature,這個結構體中記錄的內容是弱分類器的類型(包括該haar-like特征的位置,大小,以及種類,這個結構體會在下面給出,再細說)
第三個threshold,就是那個判別函數:h(x,f,p,theta) = (p*f(x) < p*theta ? 1 : 0),中的閾值theta
第四個left,第五個right不是很清楚(求知道的同學詳解啊~~~~)
第六個alpha,就是這個弱分類器的權重(每一個強分類器都是由多個弱分類器按照各自的權重進行表決,而得到的)
特征的結構體如下
1 #define CV_HAAR_FEATURE_MAX 3 2 // 一個Haar特征由2~3個具有相應權重的矩形組成 3 typedef struct CvHaarFeature 4 { 5 int tilted; // 0 means up-right feature, 1 means 45-rotated feature 6 struct 7 { 8 CvRect r; 9 float weight; 10 } rect[CV_HAAR_FEATURE_MAX]; 11 // 2-3 rectangles with weights of opposite signs and with absolute values inversely proportional to the areas of the rectangles. if rect[2].weight != 0, then the feature consists of 3 rectangles, otherwise it consists of 2. 12 }CvHaarFeature;
第一個參數titled,0表示該特征是標准的haar-like特征,1表示旋轉45°后的特征
標准的haar-like特征如下:
而旋轉45°后的特征如下:
第二個參數是個結構體數組,每個結構體中包括一個矩形和一個權重,這個數組的大小是CV_HAAR_FEATURE_MAX(3)(注釋中說:此處可能有2~3個矩形,這里的矩形等看了下面的解釋就知道了),這個矩形和權重有什么用呢?
在debug模式下,查看第一個弱分類器數組內的元素
第一個元素:
1 rect[0].r.x = 3 2 rect[0].r.y = 7 3 rect[0].r.width = 14 4 rect[0].r.height = 4 5 rect[0].weight = -1
第二個元素:
1 rect[1].r.x = 3 2 rect[1].r.y = 9 3 rect[1].r.width = 14 4 rect[1].r.height = 2 5 rect[1].weight = 2
第三個元素則全都是0
這么看這些坐標,並不是很清楚,我們可以畫個圖:
由圖可見,第一個矩形表示的是A+B區域,第二個矩形表示的是B區域。
此時再看一看每個元素的權重weight,結合積分圖的概念,發現第一個矩形的積分圖乘以其權重加上第二個積分圖乘以其權重,恰好得到下述結果:
(A+B)*(-1)+B*2=B-A
看到這個公式,大家都不會陌生,這正式VJ論文中給出的眾多haar-like模板中的其中一個模板的計算方法(此處不知如何表達,大家將就,看懂就行)
我們繼續考察第二個弱分類器的特征部分,其特征參數如下:
1 rect[0].r.x = 1, rect[0].r.y = 2 2 rect[0].r.width = 18, rect[0].r.height = 4 3 rect[0].weight = -1 4 5 rect[1].r.x = 7, rect[1].r.y = 2 6 rect[1].r.width = 6, rect[1].r.height = 4 7 rect[1].weight = 3
數組的第三個元素依然都是是0,對其繪圖:
第一塊矩形區域是A+B+C,第二塊矩形區域是B,積分圖乘以權重,再相加,可得:
(A+B+C)*(-1)+B*3 = 2*B-A-C
也是haar-like特征模板之一(此處不知如何表達,大家將就,看懂就行)
剛剛找了好久,找到一個第三個元素權重不為0的,該數組三個元素如下:
1 rect[0].r.x = 0, rect[0].r.y = 2 2 rect[0].r.width = 20, rect[0].r.height = 6; 3 rect[0].weight = -1 4 5 rect[1].r.x = 10, rect[1].r.y = 2 6 rect[1].r.width = 10, rect[1].r.height = 3; 7 rect[1].weight = 2 8 9 rect[2].r.x = 0, rect[2].r.y = 5 10 rect[2].r.width = 10, rect[2].r.height = 3; 11 rect[2].weight = 2
繪圖可得:
將每個矩形乘以相應的權重,相加可得:
(A+B+C+D)*(-1)+2*B + 2*C = B+C-(A+D)
也是模板之一
(佩服設計這個結構體的程序員)
到此,四個結構體都說完了,如有不對,請大家指正