盒式濾波器Box Filter

其主要功能是:在給定的滑動窗口大小下,對每一個窗口內的像素值進行快速相加求和算法

在模式識別領域,Haar特徵是你們很是熟悉的一種圖像特徵了,它能夠應用於許多目標檢測的算法中。與Haar類似,圖像的局部矩形內像素的和、平方和、均值、方差等特徵也能夠用相似Haar特徵的計算方法來計算。這些特徵有時會頻繁的在某些算法中使用,所以對它的優化勢在必行。Boxfilter就是這樣一種優化方法,它可使複雜度爲O(MN)的求和,求方差等運算下降到O(1)或近似於O(1)的複雜度,它的缺點是不支持多尺度。api

第一個提出Haar特徵快速計算方法的是CVPR2001上的那篇經典論文Rapid Object Detection using a Boosted Cascade of Simple Features ,它提出了integral image的概念,這個方法使得圖像的局部矩形求和運算的複雜度從O(MN)降低到了O(4)。它的原理很簡單:首先創建一個數組A,寬高與原圖像相等,而後對這個數組賦值,每一個元素的值A[i]賦爲該點與圖像原點所構成的矩形中全部像素的和。初始化以後,想要計算某個矩形像素和的時候能夠採用以下方法:如圖D矩形的像素和就等於A[4] – A[2] – A[3] + A[1],共4次運算,即O(4)。Integral Image極大的提升了Haar特徵的計算速度,它的優勢在於可以快速計算任意大小的矩形求和運算。數組

  Boxfilter的原理有點相似Integral Image,並且比它還要快,可是實現步驟比較複雜。在計算矩形特徵以前,Boxfilter與Integral Image都須要對圖像進行初始化(即對數組A賦值),不一樣於Integral Image, Boxfilter的數組A中的每一個元素的值是該像素鄰域內的像素和(或像素平方和),在須要求某個矩形內像素和的時候,直接訪問數組中對應的位置就能夠了。所以能夠看出它的複雜度是O(1)。優化

 

Boxfilter的初始化過程以下:spa

一、給定一張圖像,寬高爲(M,N),肯定待求矩形模板的寬高(m,n),如圖紫色矩形。圖中每一個黑色方塊表明一個像素,紅色方塊是假想像素。code

二、開闢一段大小爲M的數組,記爲buff, 用來存儲計算過程的中間變量,用紅色方塊表示blog

三、將矩形模板(紫色)從左上角(0,0)開始,逐像素向右滑動,到達行末時,矩形移動到下一行的開頭(0,1),如此反覆,每移動到一個新位置時,計算矩形內的像素和,保存在數組A中。以(0,0)位置爲例進行說明:首先將綠色矩形內的每一列像素求和,結果放在buff內(紅色方塊),再對藍色矩形內的像素求和,結果即爲紫色特徵矩形內的像素和,把它存放到數組A中,如此便完成了第一次求和運算。it

四、每次紫色矩形向右移動時,實際上就是求對應的藍色矩形的像素和,此時只要把上一次的求和結果減去藍色矩形內的第一個紅色塊,再加上它右面的一個紅色塊,就是當前位置的和了,用公式表示 sum[i] = sum[i-1] - buff[x-1] + buff[x+m-1]io

五、當紫色矩形移動到行末時,須要對buff進行更新。由於整個綠色矩形下移了一個像素,因此對於每一個buff[i], 須要加上一個新進來的像素,再減去一個出去的像素,而後便開始新的一行的計算了。opencv

 

  Boxfilter的初始化過程很是快速,每一個矩形的計算基本上只須要一加一減兩次運算。從初始化的計算速度上來講,Boxfilter比Integral Image要快一些,大約25%。在具體求某個矩形特徵時,Boxfilter比Integral Image快4倍,所謂的4倍其實就是從4次加減運算下降到1次,雖然這個優化很是眇小,可是把它放到幾層大循環裏面,仍是能節省一些時間的。對於那些實時跟蹤檢測算法,一幀的處理時間要嚴格在40ms如下,正是這些細小的優化決定了程序的效率,聚沙成塔,積少成多。

下面的程序是Boxfilter的示例代碼,謹供參考(C語言)

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <math.h>
 4 #include <opencv2\opencv.hpp>  
 5 
 6 void displayImageNewWindow(char *title,CvArr* img){
 7     cvNamedWindow(title,1);
 8     cvShowImage(title,img);
 9 }
10 void box_filter(IplImage* img,IplImage* result){
11     //init part
12     CvScalar s;
13     int width = img->width, height = img->height;
14     int m_w = 5,m_h = 5;//window_size
15     int boxwidth = width - m_w, boxheight = height - m_h;
16     int *sum = (int*)malloc(boxwidth *boxheight*sizeof(double));
17     int *buff= (int*)malloc(width*sizeof(double));
18     memset(sum,0,boxwidth *boxheight*sizeof(int));
19     memset(buff,0,width*sizeof(int));
20     
21     //set buff:from 0 to 4 rows,per col
22     int x,y,j;
23     for(y=0; y<m_h; y++){
24         for(x=0; x<width; x++){
25             uchar pixel = CV_IMAGE_ELEM(img,uchar,y,x);
26             buff[x] += pixel;
27             //printf("%d:%d\n",x,buff[x]);
28         }    
29     }
30 
31     for(y=0; y<height - m_h;y++){
32         int Xsum = 0;
33 
34         for(j=0; j<m_w; j++){
35             Xsum += buff[j];//sum of pixel from (0,0) to (m_h,m_w) (also x = 0)
36         }
37 
38         for(x=0; x<boxwidth; x++){
39             if(x!=0){
40                 Xsum = Xsum-buff[x-1]+buff[m_w-1+x];//Xsum:sum of cols range from x to x+m_w ,rows range from 0 to 4
41             }
42             sum[y*boxwidth + x] = (float) Xsum;        
43         }
44 
45         for(x=0; x<width; x++){
46             uchar pixel = CV_IMAGE_ELEM(img,uchar,y,x);//img[y *width + x];    
47             uchar pixel2= CV_IMAGE_ELEM(img,uchar,y+m_h,x);//img[(y+mheight) *width + x];    
48             buff[x] = buff[x] - pixel + pixel2;      
49         }
50     }
51     //遍歷,獲得每一個點的和,傳給矩陣result
52     for( y=0; y<height-5; y++){
53         for( x=0; x<width; x++){
54             if(y>m_h/2 && y<height - m_h/2 && x>m_w/2 && x<width - m_w/2){
55                 s.val[0] =  sum[(y - m_h/2) *boxwidth + (x - m_h/2)]/(m_h*m_w);
56                 cvSet2D(result,y,x,s);
57             }else{
58                 s.val[0] = -1;
59                 cvSet2D(result,y,x,s);
60             }//end else
61         }//end the first for
62     }//end the second for
63 }
64 int main(int argc,char** argv){
65     IplImage* left = cvLoadImage(argv[1]);
66     IplImage* dst = cvCreateImage(cvGetSize(left),8,1);
67     IplImage* mat =  cvCreateImage(cvGetSize(left),8,1);
68     cvZero(mat);
69     cvCvtColor(left,dst,CV_RGB2GRAY);
70     box_filter(dst,mat);
71     displayImageNewWindow("mat",mat);
72     cvWaitKey();
73     return 0;
74 }
相關文章
相關標籤/搜索