盒式滤波器BoxFilter
其主要功能是:在给定的滑动窗⼝⼤⼩下,对每个窗⼝内的像素值进⾏快速相加求和 在模式识别领域,Haar特征是⼤家⾮常熟悉的⼀种图像特征了,它可以应⽤于许多⽬标检测的算法中。与Haar相似,图像的局部矩形内像素的和、平⽅和、均值、⽅差等特征也可以⽤类似Haar特征的计算⽅法来计算。这些特征有时会频繁的在某些算法中使⽤,因此对它的优化势在必⾏。Boxfilter就是这样⼀种优化⽅法,它可以使复杂度为O(MN)的求和,求⽅差等运算降低到O(1)或近似于O(1)的复杂度,它的缺点是不⽀持多尺度。 第⼀个提出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的初始化过程如下:
1、给定⼀张图像,宽⾼为(M,N),确定待求矩形模板的宽⾼(m,n),如图紫⾊矩形。图中每个⿊⾊⽅块代表⼀个像素,红⾊⽅块是假想像素。
2、开辟⼀段⼤⼩为M的数组,记为buff, ⽤来存储计算过程的中间变量,⽤红⾊⽅块表⽰
3、将矩形模板(紫⾊)从左上⾓(0,0)开始,逐像素向右滑动,到达⾏末时,矩形移动到下⼀⾏的开头(0,1),如此反复,每移动到⼀个新位置时,计算矩形内的像素和,保存在数组A中。以(0,0)位置为例进⾏说明:⾸先将绿⾊矩形内的每⼀列像素求和,结果放在buff内(红⾊⽅块),再对蓝⾊矩形内的像素求和,结果即为紫⾊特征矩形内的像素和,把它存放到数组A中,如此便完成了第⼀次求和运算。
4、每次紫⾊矩形向右移动时,实际上就是求对应的蓝⾊矩形的像素和,此时只要把上⼀次的求和结果减去蓝⾊矩形内的第⼀个红⾊块,再加上它右⾯的⼀个红⾊块,就是当前位置的和了,⽤公式表⽰ sum[i] = sum[i-1] - buff[x-1] + buff[x+m-1]
5、当紫⾊矩形移动到⾏末时,需要对buff进⾏更新。因为整个绿⾊矩形下移了⼀个像素,所以对于每个buff[i], 需要加上⼀个新进来的像素,再减去⼀个出去的像素,然后便开始新的⼀⾏的计算了。
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
6void displayImageNewWindow(char *title,CvArr* img){
7 cvNamedWindow(title,1);
8 cvShowImage(title,img);
9 }
10void box_filter(IplImage* img,IplImage* result){
11//init part
12 CvScalar s;
13int width = img->width, height = img->height;
14int m_w = 5,m_h = 5;//window_size
15int boxwidth = width - m_w, boxheight = height - m_h;
16int *sum = (int*)malloc(boxwidth *boxheight*sizeof(double));
17int *buff= (int*)malloc(width*sizeof(double));
18 memset(sum,0,boxwidth *boxheight*sizeof(int));
19 memset(buff,0,width*sizeof(int));
20
syk-214
21//set buff:from 0 to 4 rows,per col
22int x,y,j;
23for(y=0; y<m_h; y++){
24for(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
31for(y=0; y<height - m_h;y++){
32int Xsum = 0;
33
34for(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
38for(x=0; x<boxwidth; x++){
39if(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弹簧绳
45for(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
52for( y=0; y<height-5; y++){
53for( x=0; x<width; x++){
54if(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 }
64int 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();
73return0;
分质供水设备74 }