均值滤波的快速解法

均值滤波是一种非常常见的滤波方法,本身算法难度并不大,但是想当然的算法复杂度都是width*height*size的复杂度。下面我试着写了下一个height*width复杂度算法

这个快速算法的精髓是采用一个数组代替滑动窗口。

以5*5的图像进行3*3的均值滤波为例。(height=width=5;size=3)

首先创建一个列和数组cur_rowSum,初始化为前size(3)行像素的列和。

0

5

7

9

0

(1) 列和数组为1*width

0

0

0

0

0

0

1

2

3

0

0

4

5

6

0

0

7

8

9

0

0

0

0

0

0

(2) 原始图像,周围pad为0

下面进行第一行的计算:

计算第一个像素的值,P=cur_rowSum[0..size-1],之后下一个像素的值刚好为p-最左一列的列和值加上最右一列的列和值。

0

5

7

9

0

0

0

0

0

0

0

12

2

3

0

0

4

5

6

0

0

7

8

9

0

0

0

0

0

0

由于在计算下一行的像素值时,也需要cur_rowSum。因此在第一行计算列和的时候同时计算下一个”cur_rowSum”,为了确保不影响本行的计算,因此采用另外一个数组存储。

计算时的方式为一个列和减去所在列的第一个像素,加上所在列的下一行像素。

0

12

7

9

0

0

0

0

0

0

0

1

2

3

0

0

4

5

6

0

0

7

8

9

0

0

0

0

0

0

如图,12=5-0+7;

如此进行循环进行,直到计算完毕,期间注意不要数组越界。

下面是代码。

#include<iostream>  
#include<vector>  
using namespace std;  
void avg_filter(int *src_pad,int height,int width,int size=3){  
    int *src_pad1=src_pad;  
    int *temp_src=src_pad1;  
    vector<int> cur_sumRow(width,0);  
    //初始化cur_sumRow为前size行元素的和,也就列和。  
    for(int i=0;i<size;i++){  
        for(int j=0;j<width;j++){  
            cur_sumRow[j]+=*temp_src;  
            //假设src为按行存储。  
            temp_src++;  
        }  
    }  
    /* 
    *假设src为pad后的矩阵,一般pad时,奇数扩展size-1行/列,偶数扩展size行 
    */  
    int src_height=height-size/2*2;  
    int src_width=width-size/2*2;  
    //*生成原始图像大小的矩阵。  
    int *result=new int[src_height*src_width];  
    int *temp_pad=src_pad+size*width;  
    int ind=0;  
    //由于移动中需要更新列和数组的临时变量  
    vector<int> temp_sumRow(width,0);  
    for(int i=size/2;i<height-size/2;i++){  
        int temp_sum=0;  
        for(int cur_i=0;cur_i<width;cur_i++){  
            temp_sumRow[cur_i]=cur_sumRow[cur_i];  
        }  
        for(int cur_i=0;cur_i<size;cur_i++){  
            temp_sum+=temp_sumRow[cur_i];  
        }  
        for(int j=0;j<width;j++){  
            if(j>=size/2&&j<width-size/2){  
                result[ind]=temp_sum;  
                ind++;  
                //减去最左列的值,加上最右列的值。  
                temp_sum-=temp_sumRow[j-size/2];  
                if(j+size/2+1<width){  
                    if(size%2!=0){  
                        temp_sum+=temp_sumRow[j+size/2+1];  
                    }else{  
                        temp_sum+=temp_sumRow[j+size/2];  
                    }  
                }  
            }  
            //减去最上一行的值,加上下一行的值。由于是一维存储,因此用两个指针快速访问  
            cur_sumRow[j]-=*src_pad;  
            src_pad++;  
            //最后一行不计算。切会发生越界  
            if(i!=height-size/2-1){  
                cur_sumRow[j]+=*temp_pad;  
                temp_pad++;  
            }  
        }  
        //如果pad的为同一个数,不用考虑两端的列和变化、  
    }  
    for(int i=0;i<9;i++){  
        cout<<result[i]<<" ";  
        if((i+1)%3==0)  
            cout<<endl;  
    }  
}  
int main(){  
    int src[25]={  
        0, 0, 0, 0, 0,  
        0, 1, 2, 3, 0,  
        0, 4, 5, 6, 0,  
        0, 7, 8, 9, 0,  
        0, 0, 0, 0, 0  
    };  
    avg_filter(src,5,5,3);  
}  
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值