图像处理高斯滤波器_高斯滤波器 图像处理 - CSDN
  • 图像处理基础(4):高斯滤波器详解 本文主要介绍了高斯滤波器的原理及其实现过程 高斯滤波器是一种线性滤波器,能够有效的抑制噪声,平滑图像。其作用原理和均值滤波器类似,都是取滤波器窗口内的像素的均值...
    图像处理基础(4):高斯滤波器详解
    

    本文主要介绍了高斯滤波器的原理及其实现过程

    高斯滤波器是一种线性滤波器,能够有效的抑制噪声,平滑图像。其作用原理和均值滤波器类似,都是取滤波器窗口内的像素的均值作为输出。其窗口模板的系数和均值滤波器不同,均值滤波器的模板系数都是相同的为1;而高斯滤波器的模板系数,则随着距离模板中心的增大而系数减小。所以,高斯滤波器相比于均值滤波器对图像个模糊程度较小。

    什么是高斯滤波器

    既然名称为高斯滤波器,那么其和高斯分布(正态分布)是有一定的关系的。一个二维的高斯函数如下:

    h(x,y)=e−x2+y22σ2

    其中(x,y)为点坐标,在图像处理中可认为是整数;σ是标准差。要想得到一个高斯滤波器的模板,可以对高斯函数进行离散化,得到的高斯函数值作为模板的系数。例如:要产生一个3×3的高斯滤波器模板,以模板的中心位置为坐标原点进行取样。模板在各个位置的坐标,如下所示(x轴水平向右,y轴竖直向下)

    这样,将各个位置的坐标带入到高斯函数中,得到的值就是模板的系数。
    对于窗口模板的大小为 (2k+1)×(2k+1),模板中各个元素值的计算公式如下:

    Hi,j=12πσ2e−(i−k−1)2+(j−k−1)22σ2

    这样计算出来的模板有两种形式:小数和整数。

    • 小数形式的模板,就是直接计算得到的值,没有经过任何的处理;
    • 整数形式的,则需要进行归一化处理,将模板左上角的值归一化为1,下面会具体介绍。使用整数的模板时,需要在模板的前面加一个系数,系数为1∑(i,j)∈wwi,j,也就是模板系数和的倒数。

    高斯模板的生成

    知道模板生成的原理,实现起来也就不困难了

    void generateGaussianTemplate(double window[][11], int ksize, double sigma)
    {
        static const double pi = 3.1415926;
        int center = ksize / 2; // 模板的中心位置,也就是坐标的原点
        double x2, y2;
        for (int i = 0; i < ksize; i++)
        {
            x2 = pow(i - center, 2);
            for (int j = 0; j < ksize; j++)
            {
                y2 = pow(j - center, 2);
                double g = exp(-(x2 + y2) / (2 * sigma * sigma));
                g /= 2 * pi * sigma;
                window[i][j] = g;
            }
        }
        double k = 1 / window[0][0]; // 将左上角的系数归一化为1
        for (int i = 0; i < ksize; i++)
        {
            for (int j = 0; j < ksize; j++)
            {
                window[i][j] *= k;
            }
        }
    }

    需要一个二维数组,存放生成的系数(这里假设模板的最大尺寸不会超过11);第二个参数是模板的大小(不要超过11);第三个参数就比较重要了,是高斯分布的标准差。
    生成的过程,首先根据模板的大小,找到模板的中心位置ksize/2。 然后就是遍历,根据高斯分布的函数,计算模板中每个系数的值。
    需要注意的是,最后归一化的过程,使用模板左上角的系数的倒数作为归一化的系数(左上角的系数值被归一化为1),模板中的每个系数都乘以该值(左上角系数的倒数),然后将得到的值取整,就得到了整数型的高斯滤波器模板。
    下面截图生成的是,大小为3×3,σ=0.8的模板

    对上述解结果取整后得到如下模板:

    116[121242121]

    这个模板就比较熟悉了,其就是根据σ=0.8的高斯函数生成的模板。

    至于小数形式的生成也比较简单,去掉归一化的过程,并且在求解过程后,模板的每个系数要除以所有系数的和。具体代码如下:

    void generateGaussianTemplate(double window[][11], int ksize, double sigma)
    {
        static const double pi = 3.1415926;
        int center = ksize / 2; // 模板的中心位置,也就是坐标的原点
        double x2, y2;
        double sum = 0;
        for (int i = 0; i < ksize; i++)
        {
            x2 = pow(i - center, 2);
            for (int j = 0; j < ksize; j++)
            {
                y2 = pow(j - center, 2);
                double g = exp(-(x2 + y2) / (2 * sigma * sigma));
                g /= 2 * pi * sigma;
                sum += g;
                window[i][j] = g;
            }
        }
        //double k = 1 / window[0][0]; // 将左上角的系数归一化为1
        for (int i = 0; i < ksize; i++)
        {
            for (int j = 0; j < ksize; j++)
            {
                window[i][j] /= sum;
            }
        }
    }

    3×3,σ=0.8的小数型模板。

    σ值的意义及选取

    通过上述的实现过程,不难发现,高斯滤波器模板的生成最重要的参数就是高斯分布的标准差σ。标准差代表着数据的离散程度,如果σ较小,那么生成的模板的中心系数较大,而周围的系数较小,这样对图像的平滑效果就不是很明显;反之,σ较大,则生成的模板的各个系数相差就不是很大,比较类似均值模板,对图像的平滑效果比较明显。

    来看下一维高斯分布的概率分布密度图:

    横轴表示可能得取值x,竖轴表示概率分布密度F(x),那么不难理解这样一个曲线与x轴围成的图形面积为1。σ(标准差)决定了这个图形的宽度,可以得出这样的结论:σ越大,则图形越宽,尖峰越小,图形较为平缓;σ越小,则图形越窄,越集中,中间部分也就越尖,图形变化比较剧烈。这其实很好理解,如果sigma也就是标准差越大,则表示该密度分布一定比较分散,由于面积为1,于是尖峰部分减小,宽度越宽(分布越分散);同理,当σ越小时,说明密度分布较为集中,于是尖峰越尖,宽度越窄!
    于是可以得到如下结论:
    σ越大,分布越分散,各部分比重差别不大,于是生成的模板各元素值差别不大,类似于平均模板;
    σ越小,分布越集中,中间部分所占比重远远高于其他部分,反映到高斯模板上就是中心元素值远远大于其他元素值,于是自然而然就相当于中间值得点运算。

    基于OpenCV的实现

    在生成高斯模板好,其简单的实现和其他的空间滤波器没有区别,具体代码如下:

    void GaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma)
    {
        CV_Assert(src.channels() || src.channels() == 3); // 只处理单通道或者三通道图像
        const static double pi = 3.1415926;
        // 根据窗口大小和sigma生成高斯滤波器模板
        // 申请一个二维数组,存放生成的高斯模板矩阵
        double **templateMatrix = new double*[ksize];
        for (int i = 0; i < ksize; i++)
            templateMatrix[i] = new double[ksize];
        int origin = ksize / 2; // 以模板的中心为原点
        double x2, y2;
        double sum = 0;
        for (int i = 0; i < ksize; i++)
        {
            x2 = pow(i - origin, 2);
            for (int j = 0; j < ksize; j++)
            {
                y2 = pow(j - origin, 2);
                // 高斯函数前的常数可以不用计算,会在归一化的过程中给消去
                double g = exp(-(x2 + y2) / (2 * sigma * sigma));
                sum += g;
                templateMatrix[i][j] = g;
            }
        }
        for (int i = 0; i < ksize; i++)
        {
            for (int j = 0; j < ksize; j++)
            {
                templateMatrix[i][j] /= sum;
                cout << templateMatrix[i][j] << " ";
            }
            cout << endl;
        }
        // 将模板应用到图像中
        int border = ksize / 2;
        copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT);
        int channels = dst.channels();
        int rows = dst.rows - border;
        int cols = dst.cols - border;
        for (int i = border; i < rows; i++)
        {
            for (int j = border; j < cols; j++)
            {
                double sum[3] = { 0 };
                for (int a = -border; a <= border; a++)
                {
                    for (int b = -border; b <= border; b++)
                    {
                        if (channels == 1)
                        {
                            sum[0] += templateMatrix[border + a][border + b] * dst.at<uchar>(i + a, j + b);
                        }
                        else if (channels == 3)
                        {
                            Vec3b rgb = dst.at<Vec3b>(i + a, j + b);
                            auto k = templateMatrix[border + a][border + b];
                            sum[0] += k * rgb[0];
                            sum[1] += k * rgb[1];
                            sum[2] += k * rgb[2];
                        }
                    }
                }
                for (int k = 0; k < channels; k++)
                {
                    if (sum[k] < 0)
                        sum[k] = 0;
                    else if (sum[k] > 255)
                        sum[k] = 255;
                }
                if (channels == 1)
                    dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
                else if (channels == 3)
                {
                    Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
                    dst.at<Vec3b>(i, j) = rgb;
                }
            }
        }
        // 释放模板数组
        for (int i = 0; i < ksize; i++)
            delete[] templateMatrix[i];
        delete[] templateMatrix;
    }

    只处理单通道或者三通道图像,模板生成后,其滤波(卷积过程)就比较简单了。不过,这样的高斯滤波过程,其循环运算次数为m×n×ksize2,其中m,n为图像的尺寸;ksize为高斯滤波器的尺寸。这样其时间复杂度为O(ksize2),随滤波器的模板的尺寸呈平方增长,当高斯滤波器的尺寸较大时,其运算效率是极低的。为了,提高滤波的运算速度,可以将二维的高斯滤波过程分解开来。

    分离实现高斯滤波

    由于高斯函数的可分离性,尺寸较大的高斯滤波器可以分成两步进行:首先将图像在水平(竖直)方向与一维高斯函数进行卷积;然后将卷积后的结果在竖直(水平)方向使用相同的一维高斯函数得到的模板进行卷积运算。具体实现代码如下:

    // 分离的计算
    void separateGaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma)
    {
        CV_Assert(src.channels()==1 || src.channels() == 3); // 只处理单通道或者三通道图像
        // 生成一维的高斯滤波模板
        double *matrix = new double[ksize];
        double sum = 0;
        int origin = ksize / 2;
        for (int i = 0; i < ksize; i++)
        {
            // 高斯函数前的常数可以不用计算,会在归一化的过程中给消去
            double g = exp(-(i - origin) * (i - origin) / (2 * sigma * sigma));
            sum += g;
            matrix[i] = g;
        }
        // 归一化
        for (int i = 0; i < ksize; i++)
            matrix[i] /= sum;
        // 将模板应用到图像中
        int border = ksize / 2;
        copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT);
        int channels = dst.channels();
        int rows = dst.rows - border;
        int cols = dst.cols - border;
        // 水平方向
        for (int i = border; i < rows; i++)
        {
            for (int j = border; j < cols; j++)
            {
                double sum[3] = { 0 };
                for (int k = -border; k <= border; k++)
                {
                    if (channels == 1)
                    {
                        sum[0] += matrix[border + k] * dst.at<uchar>(i, j + k); // 行不变,列变化;先做水平方向的卷积
                    }
                    else if (channels == 3)
                    {
                        Vec3b rgb = dst.at<Vec3b>(i, j + k);
                        sum[0] += matrix[border + k] * rgb[0];
                        sum[1] += matrix[border + k] * rgb[1];
                        sum[2] += matrix[border + k] * rgb[2];
                    }
                }
                for (int k = 0; k < channels; k++)
                {
                    if (sum[k] < 0)
                        sum[k] = 0;
                    else if (sum[k] > 255)
                        sum[k] = 255;
                }
                if (channels == 1)
                    dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
                else if (channels == 3)
                {
                    Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
                    dst.at<Vec3b>(i, j) = rgb;
                }
            }
        }
        // 竖直方向
        for (int i = border; i < rows; i++)
        {
            for (int j = border; j < cols; j++)
            {
                double sum[3] = { 0 };
                for (int k = -border; k <= border; k++)
                {
                    if (channels == 1)
                    {
                        sum[0] += matrix[border + k] * dst.at<uchar>(i + k, j); // 列不变,行变化;竖直方向的卷积
                    }
                    else if (channels == 3)
                    {
                        Vec3b rgb = dst.at<Vec3b>(i + k, j);
                        sum[0] += matrix[border + k] * rgb[0];
                        sum[1] += matrix[border + k] * rgb[1];
                        sum[2] += matrix[border + k] * rgb[2];
                    }
                }
                for (int k = 0; k < channels; k++)
                {
                    if (sum[k] < 0)
                        sum[k] = 0;
                    else if (sum[k] > 255)
                        sum[k] = 255;
                }
                if (channels == 1)
                    dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
                else if (channels == 3)
                {
                    Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
                    dst.at<Vec3b>(i, j) = rgb;
                }
            }
        }
        delete[] matrix;
    }

    代码没有重构较长,不过其实现原理是比较简单的。首先得到一维高斯函数的模板,在卷积(滤波)的过程中,保持行不变,列变化,在水平方向上做卷积运算;接着在上述得到的结果上,保持列不边,行变化,在竖直方向上做卷积运算。 这样分解开来,算法的时间复杂度为O(ksize),运算量和滤波器的模板尺寸呈线性增长。

    在OpenCV也有对高斯滤波器的封装GaussianBlur,其声明如下:

    CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                    double sigmaX, double sigmaY = 0,
                                    int borderType = BORDER_DEFAULT );

    二维高斯函数的标准差在x和y方向上应该分别有一个标准差,在上面的代码中一直设其在x和y方向的标准是相等的,在OpenCV中的高斯滤波器中,可以在x和y方向上设置不同的标准差。
    下图是自己实现的高斯滤波器和OpenCV中的GaussianBlur的结果对比

    上图是5×5,σ=0.8的高斯滤波器,可以看出两个实现得到的结果没有很大的区别。

    总结

    高斯滤波器是一种线性平滑滤波器,其滤波器的模板是对二维高斯函数离散得到。由于高斯模板的中心值最大,四周逐渐减小,其滤波后的结果相对于均值滤波器来说更好。
    高斯滤波器最重要的参数就是高斯分布的标准差σ,标准差和高斯滤波器的平滑能力有很大的能力,σ越大,高斯滤波器的频带就较宽,对图像的平滑程度就越好。通过调节σ参数,可以平衡对图像的噪声的抑制和对图像的模糊。



    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
    展开全文
  • 数字图像处理——高斯滤波器【像素级别处理】(python) 文章目录数字图像处理——高斯滤波器【像素级别处理】(python)简介代码实现 简介 高斯滤波通常用它来减少图像噪声以及降低细节层次。这种模糊技术生成的...

    数字图像处理——高斯滤波器【像素级别处理】(python)

    简介

    高斯滤波通常用它来减少图像噪声以及降低细节层次。这种模糊技术生成的图像,其视觉效果就像是经过一个半透明屏幕在观察图像,这与镜头焦外成像效果散景以及普通照明阴影中的效果都明显不同。高斯平滑也用于计算机视觉算法中的预先处理阶段,以增强图像在不同比例大小下的图像效果.从数学的角度来看,图像的高斯模糊过程就是图像与正态分布做卷积。由于正态分布又叫作“高斯分布”,所以这项技术就叫作高斯模糊。图像与圆形方框模糊做卷积将会生成更加精确的焦外成像效果。由于高斯函数的傅立叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波器。

    代码实现

    import cv2
    import numpy as np
    import matplotlib.pyplot as plt
    
    img = cv2.imread('Fig0340.tif')  # 测试图片
    H = img.shape[0]
    W = img.shape[1]
    
    #   产生5*5的Gaussian smoothing filter
    # Σ=3,h(x,y)=e^((x^2+y^2)/(2*Σ*Σ))
    h = np.zeros((5, 5))  # 高斯模板
    
    for i in range(5):
        for j in range(5):
            x = i - 2
            y = j - 2
            h[i, j] = np.power(np.e, -(x * x + y * y) / 18)
    
    h /= np.sum(h)  # 归一化处理
    spanImg = np.zeros((H + 4, W + 4, 3), np.uint8)  # 5*5扩充后的图像
    
    for i in range(H):
        for j in range(W):
            spanImg[i + 2, j + 2] = img[i, j]
    
    blurImg = np.zeros((H, W, 3), np.uint8)  # 高斯模糊化之后的图像
    for i in range(H):
        for j in range(W):
            pix = 0
            for x in range(5):
                for y in range(5):
                    pix += h[x, y] * spanImg[i + x, j + y, 0]
            blurImg[i, j, 0] = round(pix)
            blurImg[i, j, 1] = blurImg[i, j, 0]
            blurImg[i, j, 2] = blurImg[i, j, 0]
    
    plt.subplot(1, 2, 1)
    plt.title('original image')
    plt.imshow(img)
    plt.axis('off')
    
    plt.subplot(1, 2, 2)
    plt.title('blur image')
    plt.imshow(blurImg)
    plt.axis('off')
    plt.show()
    
    

    在这里插入图片描述

    展开全文
  • 图像处理基础(4):高斯滤波器详解注:3sigma原则1sigma : 数值分布在(μ—σ,μ+σ)中的概率为0.65262sigma: 数值分布在(μ—2σ,μ+2σ)中的概率为0.95443sigma: 数值分布在(μ—3σ,μ+3σ)中的概率为0.9974...

    图像处理基础(4):高斯滤波器详解

    注:3sigma原则
    1sigma : 数值分布在(μ—σ,μ+σ)中的概率为0.6526

    2sigma: 数值分布在(μ—2σ,μ+2σ)中的概率为0.9544

    3sigma: 数值分布在(μ—3σ,μ+3σ)中的概率为0.9974

    其中在正态分布中σ代表标准差,μ代表均值x=μ即为图像的对称轴

    3σ准则又称为拉依达准则,它是先假设一组检测数据只含有随机误差,对其进行计算处理得到标准偏差,按一定概率确定一个区间,认为凡超过这个区间的误差,就不属于随机误差而是粗大误差,含有该误差的数据应予以剔除。且3σ适用于有较多组数据的时候。

    可以认为,数值分布几乎全部集中在(μ-3σ,μ+3σ)区间内,超出这个范围的可能性仅占不到0.3%.


    以下转载自博客园,原文链接https://www.cnblogs.com/wangguchangqing/p/6407717.html,作者Brook_icv


    高斯滤波器是一种线性滤波器,能够有效的抑制噪声,平滑图像。其作用原理和均值滤波器类似,都是取滤波器窗口内的像素的均值作为输出。其窗口模板的系数和均值滤波器不同,均值滤波器的模板系数都是相同的为1;而高斯滤波器的模板系数,则随着距离模板中心的增大而系数减小。所以,高斯滤波器相比于均值滤波器对图像个模糊程度较小。

    什么是高斯滤波器

    既然名称为高斯滤波器,那么其和高斯分布(正态分布)是有一定的关系的。一个二维的高斯函数如下:

    h(x,y)=ex2+y22σ2h(x,y)=e−x2+y22σ2

    其中(x,y)(x,y)为点坐标,在图像处理中可认为是整数;σσ是标准差。要想得到一个高斯滤波器的模板,可以对高斯函数进行离散化,得到的高斯函数值作为模板的系数。例如:要产生一个3×33×3的高斯滤波器模板,以模板的中心位置为坐标原点进行取样。模板在各个位置的坐标,如下所示(x轴水平向右,y轴竖直向下)

    这样,将各个位置的坐标带入到高斯函数中,得到的值就是模板的系数。
    对于窗口模板的大小为 (2k+1)×(2k+1)(2k+1)×(2k+1),模板中各个元素值的计算公式如下:

    Hi,j=12πσ2e(ik1)2+(jk1)22σ2Hi,j=12πσ2e−(i−k−1)2+(j−k−1)22σ2

    这样计算出来的模板有两种形式:小数和整数。

    • 小数形式的模板,就是直接计算得到的值,没有经过任何的处理;
    • 整数形式的,则需要进行归一化处理,将模板左上角的值归一化为1,下面会具体介绍。使用整数的模板时,需要在模板的前面加一个系数,系数为1(i,j)wwi,j1∑(i,j)∈wwi,j,也就是模板系数和的倒数。

    高斯模板的生成

    知道模板生成的原理,实现起来也就不困难了

    void generateGaussianTemplate(double window[][11], int ksize, double sigma)
    {
        static const double pi = 3.1415926;
        int center = ksize / 2; // 模板的中心位置,也就是坐标的原点
        double x2, y2;
        for (int i = 0; i < ksize; i++)
        {
            x2 = pow(i - center, 2);
            for (int j = 0; j < ksize; j++)
            {
                y2 = pow(j - center, 2);
                double g = exp(-(x2 + y2) / (2 * sigma * sigma));
                g /= 2 * pi * sigma;
                window[i][j] = g;
            }
        }
        double k = 1 / window[0][0]; // 将左上角的系数归一化为1
        for (int i = 0; i < ksize; i++)
        {
            for (int j = 0; j < ksize; j++)
            {
                window[i][j] *= k;
            }
        }
    }

    需要一个二维数组,存放生成的系数(这里假设模板的最大尺寸不会超过11);第二个参数是模板的大小(不要超过11);第三个参数就比较重要了,是高斯分布的标准差。
    生成的过程,首先根据模板的大小,找到模板的中心位置ksize/2。 然后就是遍历,根据高斯分布的函数,计算模板中每个系数的值。
    需要注意的是,最后归一化的过程,使用模板左上角的系数的倒数作为归一化的系数(左上角的系数值被归一化为1),模板中的每个系数都乘以该值(左上角系数的倒数),然后将得到的值取整,就得到了整数型的高斯滤波器模板。
    下面截图生成的是,大小为3×3,σ=0.83×3,σ=0.8的模板

    对上述解结果取整后得到如下模板:

    116121242121116[121242121]

    这个模板就比较熟悉了,其就是根据σ=0.8σ=0.8的高斯函数生成的模板。

    至于小数形式的生成也比较简单,去掉归一化的过程,并且在求解过程后,模板的每个系数要除以所有系数的和。具体代码如下:

    void generateGaussianTemplate(double window[][11], int ksize, double sigma)
    {
        static const double pi = 3.1415926;
        int center = ksize / 2; // 模板的中心位置,也就是坐标的原点
        double x2, y2;
        double sum = 0;
        for (int i = 0; i < ksize; i++)
        {
            x2 = pow(i - center, 2);
            for (int j = 0; j < ksize; j++)
            {
                y2 = pow(j - center, 2);
                double g = exp(-(x2 + y2) / (2 * sigma * sigma));
                g /= 2 * pi * sigma;
                sum += g;
                window[i][j] = g;
            }
        }
        //double k = 1 / window[0][0]; // 将左上角的系数归一化为1
        for (int i = 0; i < ksize; i++)
        {
            for (int j = 0; j < ksize; j++)
            {
                window[i][j] /= sum;
            }
        }
    }

    3×3,σ=0.83×3,σ=0.8的小数型模板。

    σσ值的意义及选取

    通过上述的实现过程,不难发现,高斯滤波器模板的生成最重要的参数就是高斯分布的标准差σσ。标准差代表着数据的离散程度,如果σσ较小,那么生成的模板的中心系数较大,而周围的系数较小,这样对图像的平滑效果就不是很明显;反之,σσ较大,则生成的模板的各个系数相差就不是很大,比较类似均值模板,对图像的平滑效果比较明显。

    来看下一维高斯分布的概率分布密度图:

    横轴表示可能得取值x,竖轴表示概率分布密度F(x),那么不难理解这样一个曲线与x轴围成的图形面积为1。σσ(标准差)决定了这个图形的宽度,可以得出这样的结论:σσ越大,则图形越宽,尖峰越小,图形较为平缓;σσ越小,则图形越窄,越集中,中间部分也就越尖,图形变化比较剧烈。这其实很好理解,如果sigma也就是标准差越大,则表示该密度分布一定比较分散,由于面积为1,于是尖峰部分减小,宽度越宽(分布越分散);同理,当σσ越小时,说明密度分布较为集中,于是尖峰越尖,宽度越窄!
    于是可以得到如下结论:
    σσ越大,分布越分散,各部分比重差别不大,于是生成的模板各元素值差别不大,类似于平均模板;
    σσ越小,分布越集中,中间部分所占比重远远高于其他部分,反映到高斯模板上就是中心元素值远远大于其他元素值,于是自然而然就相当于中间值得点运算。

    基于OpenCV的实现

    在生成高斯模板好,其简单的实现和其他的空间滤波器没有区别,具体代码如下:

    void GaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma)
    {
        CV_Assert(src.channels() || src.channels() == 3); // 只处理单通道或者三通道图像
        const static double pi = 3.1415926;
        // 根据窗口大小和sigma生成高斯滤波器模板
        // 申请一个二维数组,存放生成的高斯模板矩阵
        double **templateMatrix = new double*[ksize];
        for (int i = 0; i < ksize; i++)
            templateMatrix[i] = new double[ksize];
        int origin = ksize / 2; // 以模板的中心为原点
        double x2, y2;
        double sum = 0;
        for (int i = 0; i < ksize; i++)
        {
            x2 = pow(i - origin, 2);
            for (int j = 0; j < ksize; j++)
            {
                y2 = pow(j - origin, 2);
                // 高斯函数前的常数可以不用计算,会在归一化的过程中给消去
                double g = exp(-(x2 + y2) / (2 * sigma * sigma));
                sum += g;
                templateMatrix[i][j] = g;
            }
        }
        for (int i = 0; i < ksize; i++)
        {
            for (int j = 0; j < ksize; j++)
            {
                templateMatrix[i][j] /= sum;
                cout << templateMatrix[i][j] << " ";
            }
            cout << endl;
        }
        // 将模板应用到图像中
        int border = ksize / 2;
        copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT);
        int channels = dst.channels();
        int rows = dst.rows - border;
        int cols = dst.cols - border;
        for (int i = border; i < rows; i++)
        {
            for (int j = border; j < cols; j++)
            {
                double sum[3] = { 0 };
                for (int a = -border; a <= border; a++)
                {
                    for (int b = -border; b <= border; b++)
                    {
                        if (channels == 1)
                        {
                            sum[0] += templateMatrix[border + a][border + b] * dst.at<uchar>(i + a, j + b);
                        }
                        else if (channels == 3)
                        {
                            Vec3b rgb = dst.at<Vec3b>(i + a, j + b);
                            auto k = templateMatrix[border + a][border + b];
                            sum[0] += k * rgb[0];
                            sum[1] += k * rgb[1];
                            sum[2] += k * rgb[2];
                        }
                    }
                }
                for (int k = 0; k < channels; k++)
                {
                    if (sum[k] < 0)
                        sum[k] = 0;
                    else if (sum[k] > 255)
                        sum[k] = 255;
                }
                if (channels == 1)
                    dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
                else if (channels == 3)
                {
                    Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
                    dst.at<Vec3b>(i, j) = rgb;
                }
            }
        }
        // 释放模板数组
        for (int i = 0; i < ksize; i++)
            delete[] templateMatrix[i];
        delete[] templateMatrix;
    }

    只处理单通道或者三通道图像,模板生成后,其滤波(卷积过程)就比较简单了。不过,这样的高斯滤波过程,其循环运算次数为m×n×ksize2m×n×ksize2,其中m,n为图像的尺寸;ksize为高斯滤波器的尺寸。这样其时间复杂度为O(ksize2)O(ksize2),随滤波器的模板的尺寸呈平方增长,当高斯滤波器的尺寸较大时,其运算效率是极低的。为了,提高滤波的运算速度,可以将二维的高斯滤波过程分解开来。

    分离实现高斯滤波

    由于高斯函数的可分离性,尺寸较大的高斯滤波器可以分成两步进行:首先将图像在水平(竖直)方向与一维高斯函数进行卷积;然后将卷积后的结果在竖直(水平)方向使用相同的一维高斯函数得到的模板进行卷积运算。具体实现代码如下:

    // 分离的计算
    void separateGaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma)
    {
        CV_Assert(src.channels()==1 || src.channels() == 3); // 只处理单通道或者三通道图像
        // 生成一维的高斯滤波模板
        double *matrix = new double[ksize];
        double sum = 0;
        int origin = ksize / 2;
        for (int i = 0; i < ksize; i++)
        {
            // 高斯函数前的常数可以不用计算,会在归一化的过程中给消去
            double g = exp(-(i - origin) * (i - origin) / (2 * sigma * sigma));
            sum += g;
            matrix[i] = g;
        }
        // 归一化
        for (int i = 0; i < ksize; i++)
            matrix[i] /= sum;
        // 将模板应用到图像中
        int border = ksize / 2;
        copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT);
        int channels = dst.channels();
        int rows = dst.rows - border;
        int cols = dst.cols - border;
        // 水平方向
        for (int i = border; i < rows; i++)
        {
            for (int j = border; j < cols; j++)
            {
                double sum[3] = { 0 };
                for (int k = -border; k <= border; k++)
                {
                    if (channels == 1)
                    {
                        sum[0] += matrix[border + k] * dst.at<uchar>(i, j + k); // 行不变,列变化;先做水平方向的卷积
                    }
                    else if (channels == 3)
                    {
                        Vec3b rgb = dst.at<Vec3b>(i, j + k);
                        sum[0] += matrix[border + k] * rgb[0];
                        sum[1] += matrix[border + k] * rgb[1];
                        sum[2] += matrix[border + k] * rgb[2];
                    }
                }
                for (int k = 0; k < channels; k++)
                {
                    if (sum[k] < 0)
                        sum[k] = 0;
                    else if (sum[k] > 255)
                        sum[k] = 255;
                }
                if (channels == 1)
                    dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
                else if (channels == 3)
                {
                    Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
                    dst.at<Vec3b>(i, j) = rgb;
                }
            }
        }
        // 竖直方向
        for (int i = border; i < rows; i++)
        {
            for (int j = border; j < cols; j++)
            {
                double sum[3] = { 0 };
                for (int k = -border; k <= border; k++)
                {
                    if (channels == 1)
                    {
                        sum[0] += matrix[border + k] * dst.at<uchar>(i + k, j); // 列不变,行变化;竖直方向的卷积
                    }
                    else if (channels == 3)
                    {
                        Vec3b rgb = dst.at<Vec3b>(i + k, j);
                        sum[0] += matrix[border + k] * rgb[0];
                        sum[1] += matrix[border + k] * rgb[1];
                        sum[2] += matrix[border + k] * rgb[2];
                    }
                }
                for (int k = 0; k < channels; k++)
                {
                    if (sum[k] < 0)
                        sum[k] = 0;
                    else if (sum[k] > 255)
                        sum[k] = 255;
                }
                if (channels == 1)
                    dst.at<uchar>(i, j) = static_cast<uchar>(sum[0]);
                else if (channels == 3)
                {
                    Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };
                    dst.at<Vec3b>(i, j) = rgb;
                }
            }
        }
        delete[] matrix;
    }

    代码没有重构较长,不过其实现原理是比较简单的。首先得到一维高斯函数的模板,在卷积(滤波)的过程中,保持行不变,列变化,在水平方向上做卷积运算;接着在上述得到的结果上,保持列不边,行变化,在竖直方向上做卷积运算。 这样分解开来,算法的时间复杂度为O(ksize)O(ksize),运算量和滤波器的模板尺寸呈线性增长。

    在OpenCV也有对高斯滤波器的封装GaussianBlur,其声明如下:

    CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                    double sigmaX, double sigmaY = 0,
                                    int borderType = BORDER_DEFAULT );

    二维高斯函数的标准差在x和y方向上应该分别有一个标准差,在上面的代码中一直设其在x和y方向的标准是相等的,在OpenCV中的高斯滤波器中,可以在x和y方向上设置不同的标准差。
    下图是自己实现的高斯滤波器和OpenCV中的GaussianBlur的结果对比

    上图是5×5,σ=0.85×5,σ=0.8的高斯滤波器,可以看出两个实现得到的结果没有很大的区别。

    总结

    高斯滤波器是一种线性平滑滤波器,其滤波器的模板是对二维高斯函数离散得到。由于高斯模板的中心值最大,四周逐渐减小,其滤波后的结果相对于均值滤波器来说更好。
    高斯滤波器最重要的参数就是高斯分布的标准差σσ,标准差和高斯滤波器的平滑能力有很大的能力,σσ越大,高斯滤波器的频带就较宽,对图像的平滑程度就越好。通过调节σσ参数,可以平衡对图像的噪声的抑制和对图像的模糊。

    展开全文
  • 描述:高斯平滑滤波器被使用去模糊图像,和均值滤波器差不多,但是和均值滤波器不一样的地方就是核不同。均值滤波器的核每一个值都是相等,而高斯平滑滤波器的核内的数却是呈现高斯分布的。 对于二维高斯分布: ...

    描述:高斯平滑滤波器被使用去模糊图像,和均值滤波器差不多,但是和均值滤波器不一样的地方就是核不同。均值滤波器的核每一个值都是相等,而高斯平滑滤波器的核内的数却是呈现高斯分布的。

    对于二维高斯分布:



    它的分布图如下:

    作为高斯平滑滤波器的核就应该呈现出上图的布局,例如:


    上图分布凸显出了高斯该有的特点,因此,一般而言,高斯平滑滤波器要优于均值滤波器。


    Code:


      /**
       * Takes an input image and a gaussian distribution, calculates
       * an appropriate kernel and applies a convolution to gaussian
       * smooth the image.
       *
       * @param input the input image array
       * @param w the width of the image
       * @param h the height of the image
       * @param ks the size of the kernel to be generated
       * @param theta the gaussian distribution
       * @return smoothed image array
       */
      public static int [] smooth_image(int [] input, int w, int h,
    				    int ks, double theta){
        double [][] input2D = new double [w][h];
        double [] output1D = new double [w*h];
        double [][] output2D = new double [w][h];
        int [] output = new int [w*h];
        //extract greys from input (1D array) and place in input2D
        for(int j=0;j<h;++j){
          for(int i=0;i<w;++i){
    	input2D[i][j] = (new Color(input[j*w+i])).getRed();
          }
        }
        //now smooth this new 2D array
        output2D = smooth(input2D,w,h,ks,theta);
    
        for(int j=0;j<h;++j){
          for(int i=0;i<w;++i){
    	output1D[j*w+i]=output2D[i][j];
          }
        }
        for(int i=0;i<output1D.length;++i){
          int grey = (int) Math.round(output1D[i]);
          if (grey > 255) { grey = 255;}
          if (grey < 0) { grey = 0;}
          //System.out.println(grey);
          output[i] = (new Color(grey,grey,grey)).getRGB();
        }
    
        return output;
      }
    
    }


    Input Image




    Output Image:

    经过一个均值为0,方差了1的高斯核(5*5)进行处理得到下图:



    经过一个均值为0,方差为2的高斯核(9*9)处理得到下图:



    再经过一个均值为0,方差为4的高斯核(15*15)处理得到下图:



    总结:高斯平滑滤波器平滑效果比均值滤波器更好明显。

    展开全文
  • 图像处理--高斯滤波

    2013-12-27 10:01:36
    原文http://blog.csdn.net/l_inyi/article/details/8915116 部分内容整理自: http://blog.csdn.net/jianxiong8814/article/details/1562728 ... htt
  • 滤波器作为图像处理课程的重要内容,大致可分为两类,空域滤波器和频率域滤波器。本文主要介绍常用的四种滤波器:中值滤波器、均值滤波器、高斯滤波器、双边滤波器,并基于opencv做出实现。空域的滤波器一般可以通过...
  • 图像处理中,高斯滤波一般用高斯模板。除此之外,还有递归高斯滤波、FFT法、重复卷积法等。 1、直接卷积法 2、重复卷积法 3、FFT实现法         原理很简单out...
  • 滤波器作为图像处理课程的重要内容,大致可分为两类,空域滤波器和频率域滤波器。本文主要介绍常用的四种滤波器:中值滤波器、均值滤波器、高斯滤波器、双边滤波器,并基于opencv做出实现。空域的滤波器一般可以通过...
  • 高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。
  • 高斯滤波器及其实现

    2015-01-23 10:57:50
    高斯滤波器是一种平滑线性滤波器,使用高斯滤波器图像进行滤波,其效果是降低图像灰度的“尖锐”变化,也就是使图像“模糊”了。高斯滤波对于抑制服从正态分布的噪声效果非常好,其代价是使图像变得“模糊”。 ...
  • 深度理解高斯滤波器

    2016-03-28 16:21:17
    1.高斯滤波器综述  高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。一维零均值高斯函数为:  g(x)=exp( -x^2/(2 sigma^2) 其中,...
  • (5)——使用高斯滤波器提取图像特征(一)前 言(二)高斯滤波器的python实现(三)总 结 (一)前 言 高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对...
  • 高斯滤波器平滑图像

    2019-06-16 07:13:23
    高斯滤波器平滑图像基本原理从空间域讲,可以理解为带权重的空间平均;从频率域讲,是进行了一次低通滤波;虽然表达式非常繁琐,可以通过一个模板矩阵,指定每一个附近点的加权值来计算而不是直接公式计算...
  • 高斯滤波器 先给出高斯函数的图形。  高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。一维零均值高斯函数为:  g(x)...
  • 本文主要介绍了高斯滤波器的原理及其实现过程 高斯滤波器是一种线性滤波器,能够有效的抑制噪声,平滑图像。其作用原理和均值滤波器类似,都是取滤波器窗口内的像素的均值作为输出。其窗口模板的系数和均值滤波器...
  • 高斯滤波器是空间滤波器的一种,学习高斯滤波器,需要空间滤波的知识作为先验知识(各种数字图像处理的书中都有介绍,冈萨雷斯的经典教材说的还是比较清楚的,建议看英文版,个人感觉比翻译过来的更容易理解)。...
  • 数字图像处理,评语滤波,理想低通滤波器,高斯滤波器,巴特沃斯滤波器
  •  高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。一维零均值高斯函数为:  g(x)=exp( -x^2/(2 sigma^2) 其中,高斯分布参数Sigma决定了...
  • 图像处理-线性滤波-3 高斯滤波器 文章转自:http://www.cnblogs.com/pegasus/archive/2011/05/20/2052031.html 对于图像来说,高斯滤波器是利用高斯核的一个2维的卷积算子,用于图像模糊化(去除细节和...
  • 常用的滤波器有以下几种: 频域滤波器 频域平滑滤波器 理想低通滤波器 巴特沃斯低通滤波器 ...滤波的基本模型G(u,v) = H(u,v)F(u,v),其中 F(u,v) 是图像的傅立叶变换结果, H(u,v) 称为滤波器传输...
1 2 3 4 5 ... 20
收藏数 13,012
精华内容 5,204
关键字:

图像处理高斯滤波器