高斯滤波

高斯滤波器是一类根据高斯函数的形状来选择权值的线性平滑滤波器。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。一维零均值高斯函数为:

g(x)=exp( -x^2/(2 sigma^2) 

其中,高斯分布参数Sigma决定了高斯函数的宽度。对于图像处理来说,常用二维零均值离散高斯函数作平滑滤波器,高斯函数的图形: 

Python高斯一维滤波 一维高斯滤波的原理_opencv

 对于图像来说,高斯滤波器是利用高斯核的一个2维的卷积算子,用于图像模糊化(去除细节和噪声)。

Python高斯一维滤波 一维高斯滤波的原理_Python高斯一维滤波_02

Python高斯一维滤波 一维高斯滤波的原理_opencv_03

高斯滤波性质

高斯函数具有五个重要的性质,这些性质使得它在早期图像处理中特别有用.这些性质表明,高斯平滑滤波器无论在空间域还是在频率域都是十分有效的低通滤波器,且在实际图像处理中得到了工程人员的有效使用.高斯函数具有五个十分重要的性质,它们是: 

  (1)二维高斯函数具有旋转对称性,即滤波器在各个方向上的平滑程度是相同的.一般来说,一幅图像的边缘方向是事先不知道的,因此,在滤波前是无法确定一个方向上比另一方向上需要更多的平滑.旋转对称性意味着高斯平滑滤波器在后续边缘检测中不会偏向任一方向. 

  (2)高斯函数是单值函数.这表明,高斯滤波器用像素邻域的加权均值来代替该点的像素值,而每一邻域像素点权值是随该点与中心点的距离单调增减的.这一性质是很重要的,因为边缘是一种图像局部特征,如果平滑运算对离算子中心很远的像素点仍然有很大作用,则平滑运算会使图像失真. 

  (3)高斯函数的傅立叶变换频谱是单瓣的.正如下面所示,这一性质是高斯函数付立叶变换等于高斯函数本身这一事实的直接推论.图像常被不希望的高频信号所污染(噪声和细纹理).而所希望的图像特征(如边缘),既含有低频分量,又含有高频分量.高斯函数付立叶变换的单瓣意味着平滑图像不会被不需要的高频信号所污染,同时保留了大部分所需信号. 

  (4)高斯滤波器宽度(决定着平滑程度)是由参数σ表征的,而且σ和平滑程度的关系是非常简单的.σ越大,高斯滤波器的频带就越宽,平滑程度就越好.通过调节平滑程度参数σ,可在图像特征过分模糊(过平滑)与平滑图像中由于噪声和细纹理所引起的过多的不希望突变量(欠平滑)之间取得折衷. 

  (5)由于高斯函数的可分离性,较大尺寸的高斯滤波器可以得以有效地实现.二维高斯函数卷积可以分两步来进行,首先将图像与一维高斯函数进行卷积,然后将卷积结果与方向垂直的相同一维高斯函数卷积.因此,二维高斯滤波的计算量随滤波模板宽度成线性增长而不是成平方增长.

void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                double sigmaX, double sigmaY = 0,
                                int borderType = BORDER_DEFAULT );
  • src:待高斯滤波图像,图像可以具有任意的通道数目,但是数据类型必须为CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
  • dst:输出图像,与输入图像src具有相同的尺寸、通道数和数据类型。
  • ksize:高斯滤波器的尺寸,滤波器可以不为正方形,但是必须是正奇数。如果尺寸为0,则由标准偏差计算尺寸。
  • sigmaX:X方向的高斯滤波器标准偏差。
  • sigmaY:Y方向的高斯滤波器标准偏差;如果输入量为0,则将其设置为等于sigmaX,如果两个轴的标准差均为0,则根据输入的高斯滤波器尺寸计算标准偏差。
  • borderType:像素外推法选择标志,取值范围在表3-5中给出,默认参数为BORDER_DEFAULT,表示不包含边界值倒序填充。

 高斯滤波器的尺寸和标准偏差存在着一定的互相转换关系,OpenCV 提供了输入滤波器单一方向尺寸和标准偏差生成单一方向高斯滤波器的getGaussianKernel()函数,在函数的定义中给出了滤波器尺寸和标准偏差存在的关系

Python高斯一维滤波 一维高斯滤波的原理_高斯滤波_04

 生成一个二维的高斯滤波器需要调用两次getGaussianKernel()函数,将X方向的一维高斯滤波器和Y方向的一维高斯滤波器相乘,得到最终的二维高斯滤波器。

Python高斯一维滤波 一维高斯滤波的原理_卷积_05

Python高斯一维滤波 一维高斯滤波的原理_opencv_06

简单示例

//
// Created by smallflyfly on 2021/6/11.
//

#include "opencv2/opencv.hpp"
#include "opencv2/highgui.hpp"

#include <iostream>

using namespace std;
using namespace cv;

int main() {

    Mat im = imread("test.jpg");
    resize(im, im, Size(0, 0), 0.5, 0.5);

    imshow("im", im);

    Mat gaussNoise = Mat::zeros(im.rows, im.cols, im.type());
    RNG rng;
    rng.fill(gaussNoise, RNG::NORMAL, 10, 20);

    Mat gaussIm = im + gaussNoise;
    imshow("gaussNoise", gaussIm);

    Mat gauss1;
    GaussianBlur(im, gauss1, Size(3, 3), 10 ,20);
    imshow("gauss1", gauss1);

    Mat gauss2;
    GaussianBlur(gaussIm, gauss2, Size(3, 3), 10, 20);
    imshow("gauss2", gauss2);

    waitKey(0);

    destroyAllWindows();

    return 0;

}