心胸决定格局,眼界决定境界...

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的示例代码,谨供参考

#pragma once

typedef unsigned char uchar;

class Boxfilter
{
public:
Boxfilter(void);
~Boxfilter(void);

void init(int width, int height, int mwidth=5, int mheight=5);
void boxfilter(unsigned char* img);
public:
float getMean(int x, int y); //以x,y为中心点,mwidth,mheight为直径的局部区域,下同
float getVar(int x, int y);
int getSum(int x, int y);
int getSquareSum(int x, int y);
int getLocalSize();

private:
int mwidth ;
int mheight ;
unsigned char* img;
int width;
int height;
int* f_sum;
int* f_sum2;

};

 

 

#include "Boxfilter.h"
#include <assert.h>
#include <string>

int* buff = 0;
int* buff2 = 0;
int boxwidth;
int boxheight;

Boxfilter::Boxfilter(void)    
{    
    f_sum = 0;
    f_sum2 = 0;
}

Boxfilter::~Boxfilter(void)
{
    if(f_sum)    delete[] f_sum;
    if(f_sum2)    delete[] f_sum2;
    if(buff)    delete[] buff;
    if(buff2)    delete[] buff2;
}

void Boxfilter::init(int width, int height, int mwidth, int mheight)
{
    this->mwidth = mwidth;
    this->mheight = mheight;
    this->width = width;
    this->height = height;

    boxwidth = width - mwidth;
    boxheight = height - mheight;
    f_sum = new int[boxwidth *boxheight];
    f_sum2 = new int[boxwidth *boxheight];

    buff = new int[width];
    buff2= new int[width];
}

void Boxfilter::boxfilter (unsigned char* img)
{
    int j,x,y;

    memset(buff, 0, width *sizeof(int));
    memset(buff2, 0, width *sizeof(int));
    memset(f_sum, 0, boxwidth *boxheight);
    memset(f_sum2, 0, boxwidth *boxheight);

    for(y=0; y<mheight; y++)//第一个长框
    {
        for(x=0; x<width; x++)
        {
            uchar pixel = img[y *width + x];//遍历每个像素点
            buff[x] += pixel;//和   按列
            buff2[x] += pixel*pixel;//平方和   按列
        }
 }

    for(y=0; y<height - mheight;y++)//大长框y, 从0~height-mheight 
    {
        int Xsum=0;
        int Xsum2=0;

        for(j=0; j<mwidth; j++)//滑动框
        {
            Xsum += buff[j];//像素和
            Xsum2 += buff2[j];
        }

        for(x=0; x<width - mwidth; x++)//开始向右边开始滑动
        {
            if(x!=0)
            {
                Xsum = Xsum-buff[x-1]+buff[mwidth-1+x];//前一个滑动框的和减去不包含的点 加上刚包含进来的点
                Xsum2 = Xsum2-buff2[x-1]+buff2[mwidth-1+x];
            }
            f_sum[y*(width - mwidth)+x] = (float) Xsum ;
            f_sum2[y*(width - mwidth)+x] = Xsum2;            
        }

        for(x=0; x<width; x++)//遍历到下一个长框
        {
            uchar pixel = img[y *width + x];//    
            uchar pixel2 = img[(y+mheight) *width + x];    
            buff[x] = buff[x] - pixel + pixel2;//遍历到下一个长框         
            buff2[x] = buff2[x] - pixel*pixel +    pixel2*pixel2;    
        }
    }
}

float Boxfilter::getMean(int x, int y)//获取均值
{
    return getSum(x,y) / (float)(mwidth*mheight);
}

float Boxfilter::getVar(int x, int y)//获取方差
{
    float mean = getMean(x, y);
    return (float)getSquareSum(x, y)/(mwidth *mheight) - mean*mean;
}

int Boxfilter::getSquareSum(int x, int y)//获取平方和
{
    if(y>mheight/2 && y<height - mheight/2 && x>mwidth/2 && x<width - mwidth/2)
        return f_sum2[(y - mheight/2) *boxwidth + (x - mwidth/2)];
    else
        return -1;
}

int    Boxfilter::getSum(int x, int y)//获取和
{
    if(y>mheight/2 && y<height - mheight/2 && x>mwidth/2 && x<width - mwidth/2)
        return f_sum[(y - mheight/2) *boxwidth + (x - mwidth/2)];//x,y  转换成 f_sum的下标        实际上(y-mheight)   (x-mwidth);    上下各缺失一半,  y  对应  y-mheight/2 
else return -1; }
int Boxfilter::getLocalSize()//获取本地大小 { return mwidth > mheight ? mwidth : mheight; }



// cv2.4 test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "Boxfilter.h"
#include <iostream>
using namespace cv;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    Mat src = imread("C:\\Documents and Settings\\Administrator\\桌面\\img1.png",0);

    Boxfilter box;
    box.init(src.cols, src.rows, 5, 5);
    box.boxfilter((uchar*)src.data);

    int x = 50, y = 50;
    float a = box.getMean(x, y);    //求出以(x,y)为中心的矩形的均值
    float b = box.getVar(x, y);
    int c = box.getSum(x, y);
    int d = box.getSquareSum(x, y);
    int e = box.getLocalSize();

    cout<<"mean: "        <<a<<endl;
    cout<<"var:    "        <<b<<endl;
    cout<<"sum:    "        <<c<<endl;
    cout<<"squaresum: "    <<d<<endl;
    cout<<"size:    "    <<e<<endl;

    getchar();
    return 0;
}



http://blog.csdn.net/s12244315/article/details/50187941
  1. Mat boxfilter(Mat &imSrc, int r)  //r为邻域的大小,
  2. {  
  3.     int hei = imSrc.rows;  
  4.     int wid = imSrc.cols;  
  5.     Mat imDst = Mat::zeros( hei, wid, CV_64FC1);  
  6.     //imCum = cumsum(imSrc, 1);  
  7.     Mat imCum = cumsum(imSrc,1);  //1表示逐行累加    
  8.     //imDst(1:r+1, :) = imCum(1+r:2*r+1, :);  
  9.     for( int i = 0; i<r+1; i++)//初始化,    第r~2*r,  imCum的第r行,对应 imDst的第一行     
  10.     {  
  11.         for( int j=0; j<wid; j++ )  
  12.         {  
  13.             imDst.at<double>(i,j) = imCum.at<double>(i+r,j);  //
  14.         }  
  15.     }  
  16.     //imDst(r+2:hei-r, :) = imCum(2*r+2:hei, :) - imCum(1:hei-2*r-1, :);  
  17.     for( int i =r+1; i<hei-r;i++)  //
  18.     {  
  19.         for( int j = 0; j<wid;j++)  
  20.         {  
  21.             imDst.at<double>(i,j) = imCum.at<double>(i+r,j)-imCum.at<double>(i-r-1,j);  //减去    i,        i+r     ~   i+r-2r-1       因为是r的框中,   不是0~r的框中
  22.         }  
  23.     }  
  24.     //imDst(hei-r+1:hei, :) = repmat(imCum(hei, :), [r, 1]) - imCum(hei-2*r:hei-r-1, :);  
  25.     for( int i = hei-r; i< hei; i++)  
  26.     {  
  27.         for( int j = 0; j< wid; j++)  
  28.         {  
  29.             imDst.at<double>(i,j) = imCum.at<double>(hei-1,j)-imCum.at<double>(i-r-1,j);  
  30.         }  
  31.     }  
  32.     imCum = cumsum(imDst, 2);  
  33.     //imDst(:, 1:r+1) = imCum(:, 1+r:2*r+1);  
  34.     for( int i = 0; i<hei; i++)  
  35.     {  
  36.         for( int j=0; j<r+1; j++ )  
  37.         {  
  38.             imDst.at<double>(i,j) = imCum.at<double>(i,j+r);  
  39.         }  
  40.     }  
  41.     //imDst(:, r+2:wid-r) = imCum(:, 2*r+2:wid) - imCum(:, 1:wid-2*r-1);  
  42.     for( int i =0 ; i<hei;i++)  
  43.     {  
  44.         for( int j = r+1; j<wid-r ;j++ )  
  45.         {  
  46.             imDst.at<double>(i,j) = imCum.at<double>(i,j+r)-imCum.at<double>(i,j-r-1);  
  47.         }  
  48.     }  
  49.     //imDst(:, wid-r+1:wid) = repmat(imCum(:, wid), [1, r]) - imCum(:, wid-2*r:wid-r-1);  
  50.     for( int i = 0; i< hei; i++)  
  51.     {  
  52.         for( int j = wid-r; j<wid; j++)  
  53.         {  
  54.             imDst.at<double>(i,j) = imCum.at<double>(i,wid-1)-imCum.at<double>(i,j-r-1);  
  55.         }  
  56.     }  
  57.     return imDst;  
  58. }  


复制代码
// cv2.4 test.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "Boxfilter.h"
#include <iostream>
using namespace cv;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    Mat src = imread("C:\\Documents and Settings\\Administrator\\桌面\\img1.png",0);

    Boxfilter box;
    box.init(src.cols, src.rows, 5, 5);
    box.boxfilter((uchar*)src.data);

    int x = 50, y = 50;
    float a = box.getMean(x, y);    //求出以(x,y)为中心的矩形的均值
    float b = box.getVar(x, y);
    int c = box.getSum(x, y);
    int d = box.getSquareSum(x, y);
    int e = box.getLocalSize();

    cout<<"mean: "        <<a<<endl;
    cout<<"var:    "        <<b<<endl;
    cout<<"sum:    "        <<c<<endl;
    cout<<"squaresum: "    <<d<<endl;
    cout<<"size:    "    <<e<<endl;

    getchar();
    return 0
posted @ 2016-10-31 15:17  WELEN  阅读(286)  评论(0)    收藏  举报