图像快速高斯滤波实现

1、二维高斯滤波公式:(μ=0,σ)

  G(x,y) = 1/2πσ2·exp(-(x2+y2)/2σ2)

  G(x,y)可以分离为:G(x,y) = G(x)·G(y)= 1/2πσ2·exp(-x2/2σ2)·exp(-y2/2σ2),其中系数1/2πσ2可以不考虑,因为在归一化时又将其消掉了。

  所以,二维的滤波可以分离为两个一维的滤波。

2、假设灰度图像宽高分别为W、H,二维高斯滤波模板宽高均为m_size,那么二维模板直接卷积计算复杂度为O(W*H*m_size*m_size)

  同样采用两次一维(横向、纵向)卷积计算的复杂度为O(W*H*m_szie*2),显然计算复杂度降低,滤波模板阶数越高计算速度的提升越明显。

  通常根据3σ原则来计算模板阶数,阶数k = 2*ceil(3σ)+1,因为高斯分布中(μ=0)±3σ几乎涵盖了所有的分布,所以可以根据此规则估算合理的模板阶数(奇数)。

3、代码实现中这里使用了自己创建的二维数组,目的是来比对两种滤波的结果,代码如下:

#include <QCoreApplication>
#include <iostream>
#include <math.h>
using namespace std;

double** CreateGaussMap(int map_size, double sigma);
double* CreateGauss(int map_size, double sigma);
void GaussFilter2(int src[9][9], double dst[9][9], double** map);
void GaussFilter(int src[9][9], double dst[9][9], double* map);

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    double** gauss2 = CreateGaussMap(3,0.33);
    for (int i=0;i<3;++i) {
        for (int j=0;j<3;++j) {
            cout<<gauss2[i][j]<< " ";
        }
        cout<<endl;
    }
    cout<<endl;

    double* gauss = CreateGauss(3,0.33);
    for (int i=0;i<3;++i) {
        cout<<gauss[i]<< " ";
    }
    cout<<endl;

    int arr[9][9]={{1,1,1,1,1,1,1,1,1},{2,2,2,2,2,2,2,2,2},
                   {3,3,3,3,3,3,3,3,3},{4,4,4,4,4,4,4,4,4},
                   {5,5,5,5,5,5,5,5,5},{6,6,6,6,6,6,6,6,6},
                   {7,7,7,7,7,7,7,7,7},{8,8,8,8,8,8,8,8,8},
                   {9,9,9,9,9,9,9,9,9}};
    double dst2[9][9];
    double dst[9][9];
    GaussFilter2(arr,dst2,gauss2);

    for (int i=0;i<9;++i) {
        for (int j=0;j<9;++j) {
            cout<<dst2[i][j]<<" ";
        }
        cout<<endl;
    }
    GaussFilter(arr,dst,gauss);
    for (int i=0;i<9;++i) {
        for (int j=0;j<9;++j) {
            cout<<dst[i][j]<<" ";
        }
        cout<<endl;
    }

    return a.exec();
}


double** CreateGaussMap(int map_size, double sigma){
    // g(x,y) = (1/(2*pi*sigma^2))*exp(-(x^2+y^2)/(2*sigma^2))
    int center = (map_size-1)/2;
    //double amplitude = 1/(2*M_PI*sigma*sigma);
    double sigma_sqr = 2*pow(sigma,2);
    double x_sqr = 0, y_sqr = 0;
    double** gauss = new double*[map_size];
    double sum = 0;

//    for (int i=0;i<map_size;++i) {

//    }

    for(int i=0;i<map_size;++i){
        gauss[i] = new double[map_size];
        y_sqr = pow(double(i-center),2);
        for (int j=0;j<map_size;++j) {
            x_sqr = pow(double(j-center),2);
            sum += gauss[i][j] = exp(-(x_sqr + y_sqr)/sigma_sqr);
        }
    }

    if(sum != 0){
        for (int i=0;i<map_size;++i) {
            for (int j=0;j<map_size;++j) {
                gauss[i][j] /= sum;
            }
        }
    }

    return gauss;
}

double* CreateGauss(int map_size, double sigma){
    // g(x,y) = (1/(2*pi*sigma^2))*exp(-(x^2+y^2)/(2*sigma^2))
    int radius = (map_size-1)/2;
    //double amplitude = 1/(2*M_PI*sigma*sigma);
    double sigma_sqr = 2*pow(sigma,2);
    double* gauss = new double [map_size];
    double sum = 0;

    for(int i=0;i<map_size;++i){
        gauss[i] = exp(-(pow(double(i-radius),2))/sigma_sqr);
        sum += gauss[i];
    }

    if(sum != 0){
        for (int i=0;i<map_size;++i) {
            gauss[i] /= sum;
        }
    }

    return gauss;
}

void GaussFilter2(int src[9][9], double dst[9][9], double** map){

    for (int i=0;i<9;++i) {
        for (int j=0;j<9;++j) {
            dst[i][j] = src[i][j];
        }
    }

    int center = 1;
    for (int i=0;i<9-center-1;++i) {
        for (int j=0;j<9-center-1;++j) {
            for (int k=0;k<3;++k) {
                for (int m=0;m<3;++m) {
                    dst[i+center][j+center] += src[i+k][j+m]*map[k][m];
                }
            }
        }
    }
}

void GaussFilter(int src[9][9], double dst[9][9], double* map){
    double tmp[9][9];
    for (int i=0;i<9;++i) {
        for (int j=0;j<9;++j) {
            tmp[i][j] = src[i][j];
        }
    }

    int center = 1;
    int a=0;
    double t=0;
    for (int i=0;i<9-center-1;++i) {
        for (int j=0;j<9-center-1;++j) {
            tmp[i+center][j+center] = 0;
            for (int k=0;k<3;++k) {
                a = src[i+center][j+k];
                t=map[k];
                tmp[i+center][j+center] += (src[i+center][j+k])*map[k];
            }
        }
    }

    for (int i=0;i<9;++i) {
        for (int j=0;j<9;++j) {
            dst[i][j] = tmp[i][j];
        }
    }

    for (int j=0;j<9-center-1;++j) {
        for (int i=0;i<9-center-1;++i) {
            for (int k=0;k<3;++k) {
                dst[i+center][j+center] += tmp[i+k][j+center]*map[k];
            }
        }
    }
}

4、结果中,两中方式滤波结果一致,μ=0,σ=0.33,k = 3。

二维高斯滤波模板:

9.87532e-005  0.00973996  9.87532e-005
0.00973996     0.960645      0.00973996
9.87532e-005  0.00973996  9.87532e-005

对9*9的二维数组滤波结果:
1 1   1   1   1   1   1   1   1
2 4   4   4   4   4   4   4   2
3 6   6   6   6   6   6   6   3
4 8   8   8   8   8   8   8   4
5 10 10 10 10 10 10 10 5
6 12 12 12 12 12 12 12 6
7 14 14 14 14 14 14 14 7
8 16 16 16 16 16 16 16 8
9 9   9   9   9   9   9   9   9

 

一维高斯滤波模板

[0.00993747  0.980125  0.00993747]

两次一维高斯滤波的结果:(注:第一次横向卷积计算后的数据进行第二次纵向卷积计算
1 1   1   1   1   1   1   1   1
2 4   4   4   4   4   4   4   2
3 6   6   6   6   6   6   6   3
4 8   8   8   8   8   8   8   4
5 10 10 10 10 10 10 10 5
6 12 12 12 12 12 12 12 6
7 14 14 14 14 14 14 14 7
8 16 16 16 16 16 16 16 8
9 9   9   9   9   9   9   9   9

posted @ 2020-08-06 14:54  zarjen  阅读(1022)  评论(0编辑  收藏  举报