最早的Haar特徵由Papageorgiou C.等提出(《A general framework for object detection》),後來Paul Viola和Michal Jones提出利用積分圖像法快速計算Haar特徵的方法(《Rapid object detection using a boosted cascade of simple features》)。之後,Rainer Lienhart 和 Jochen Maydt用對角特徵對Haar特徵庫進行了擴展(《An extended set of Haar-like features for rapid object detection》)。OpenCV的Haar分類器就是基於擴展後的特徵庫實現的。
Haar特徵/矩形特徵
Haar特徵本身並不複雜,就是用圖中黑色矩形所有像素值的和減去白色矩形所有像素值的和。
看過Rainer Lienhart文章的人知道,Rainer Lienhart在文章中給出了計算特定圖像面積內Haar特徵個數公式。小女才拙,到最後也沒推出那個公式來,還望看明白的大牛留言指教~
Haar特徵個數計算
Rainer Lienhart計算Haar特徵個數的公式:
其中,爲圖片大小,爲矩形特徵大小,表示矩形特徵在水平和垂直方向的能放大的最大比例係數。
對於45°的rotated特徵(如1(c)和1(d)),w,h表示如下圖所示:
其計算公式爲:
*論文中沒有說明,個人認爲此處除了Z,XY值也有變化:
下面是我理解的計算過程~
首先有兩點要清楚:
1、對於某特定大小的特徵,在窗口內滑動計算。
也就是如圖1(a)特徵大小爲2*1,對於24*24的圖像。水平可滑動23步,垂直滑動24步,所以共有23*24個特徵。
2、對於一個特徵,特徵本身沿水平、豎直方向分別縮放。
還看特徵1(a),特徵大小爲2*1,則延水平方向可放大爲:4*1,6*1,8*1,…,24*1;豎直方向可放大爲:2*1,2*2,2*3,…,2*24。即每個特徵有XY种放大方式。(!放大的矩形特徵並限制保持2:1的比例!)
清楚這兩點,就很容易寫出計算特徵個數的代碼:
- int getHaarCount(int W,int H,int w,int h){
- int X=W/w;
- int Y=H/h;
- int count=0;
- //放大Haar特徵到 iw*jh
- for (int i=1;i<=X;i++)
- for(int j=1;j<=Y;j++)
- //滑動iw*jh矩形,遍歷圖像計算每個位置Haar特徵
- for(int x=1;x<=W-i*w+1;x++)
- for(int y=1;y<=H-j*h+1;y++)
- count++;
- return count;
- }
對於45°特徵,由於Rainer Lienhart定義的w,h與原矩陣含義不同(參見第一幅圖),即實際滑動的矩陣框爲(h+w)*(w+h)。
所以只要用如下方式調用原函數:
- getHaarCount(W,H,h+w,w+h);
當然如果你喜歡寫代碼,也可以寫個新的函數:
- int getRotatedHaarCount(int W,int H,int w,int h){
- int X=W/(w+h);//計算新的X
- int Y=H/(w+h);//計算新的Y
- int count=0;
- for (int i=1;i<=X;i++)
- for(int j=1;j<=Y;j++)
- //注意這裏滑動窗口邊界變化
- for(int x=1;x<=W-i*(w+h)+1;x++)
- for(int y=1;y<=H-j*(w+h)+1;y++)
- count++;
- return count;
- }
計算在24*24的圖片中,幾種特徵的個數爲:
可以看到和論文用公式計算得到的值是一致的~
另一種遞推計算方法:
特徵個數雖然很大,但很有規律,不用程序用筆也很容易推出遞推公式。
如1(a)和1(b)特徵遞推爲:(12^2)*(1+2+...+24)=43,200
具體參見此貼:Re: [OpenCV] Re: Number of haar features