3 高斯滤波
本文作者:图像与视觉InSight 行者 杨尚朋 转载请注明
目录
3.1 处理效果展示
图像处理前后对比1
图1 原图
图2 高斯噪声处理后的图像
图3 高斯滤波处理后的图像
图像处理前后对比2
图4 原图像2
图5 高斯噪声处理过的图像
图6 高斯滤波算法处理过的图像
3.2 高斯滤波方法原理
3.2.1 高斯噪声
所谓高斯噪声,是指它的概率密度函数服从高斯分布(即正态分布)的一类噪声,形态如下:
只看图,还是觉得抽象,深入分析一下,得到下面这幅图。
如果,统计各噪声分量幅值,分析他们出现的频率,将会得到如下结果:
观察这种噪声幅值的频率分布,可看出该分布类似高斯函数,这就将该噪声与高斯函数联系了起来,统一称为高斯噪声。
3.2.2 高斯函数简介
高斯滤波方法来源于高斯函数,主要用于滤除高斯噪声及相关无关信息。
一维高斯函数的解析式,形如下式:
使用了不同的参数,生成了不同的图像:
二维高斯函数解析式,形如下式:
二维高斯函数的图像,形如下图:
高斯函数各参数意义:a 能调节函数的最大值,表示幅度大小;b 与函数对称轴位置直接相关,x = b 为函数的对称轴;c 则与函数的半峰全宽有关。
高斯函数特点:高斯函数是一个典型的正态分布函数,有以下性质:在图像对称轴处,有最大值,随着自变量x向正轴或者负轴延伸,函数值变小,至无穷远处,逼近于0。
这条性质非常好用。
3.2.3 高斯滤波原理
高斯滤波的本质,是对邻域的线性卷积。
很好懂吧,接下来咱们具体看。
图像,在逻辑上,存储方式为二维矩阵,是离散变量(各灰度值)集合。对离散变量的卷积,仅仅是,核窗口内各元素乘以对应权值,再加到一起,和值作为核窗口中心元素的新值。
你看,卷积也没什么难的。
无论是均值滤波、高斯滤波、巴特沃斯滤波,还是Canny、Sobber算法求边缘,本质都是卷积运算,因为算子不同,所以才有了不同的效果。
以 3×3 的卷积核为例。
均值滤波的核窗口内,各元素权重都为1/(3×3)=1/9。滤波过程为,各元素都乘以1/9之后再相加,所得和值填入核窗口中心像素内,作为新值。新值的生成,需要邻域灰度值的参与,邻域灰度值对新值的大小施加了影响,影响的大小由权值确定,都是1/9。一个图像由width×height个点构成,滑动核窗口,对下一个点进行均值滤波操作,重复,直至达到迭代结束的条件。
简单,对吧。
高斯滤波呢?是一样的过程。只是,权值不再固定为1/9,而是交由二维高斯函数计算。权值计算完毕,核窗口内各灰度值乘以核窗口内对应权值,再加到一块,和值就作为核窗口中心点的灰度值。核窗口中心点的灰度值的确定,也引入了邻域灰度值的影响。
滚动鼠标中键,稍微往前翻一下,一起来看流星雨二维高斯函数的解析式。公式右上角出现了 ,该和项表征当前点距中心的远近程度,该项越大,距离越远,对应的二维高斯函数函数值越小,对应的权重值越小。
下面展示完整的高斯滤波过程。
设σ=1.5,那么核窗口内各点的权重值为:
上述表格中数字相加为0.4787147,需要将相加和设定为1,同比例缩放后,各点的权重为:
假设图像某区域各像素灰度值如下:
首先,各像素灰度值与对应权值相乘:
然后,将各和值加到中心点,完成了单点的高斯滤波:
最后,滑动核窗口,遍历处理各像素,直至达到迭代结束条件。
3.3 代码展示
//给图像添加高斯噪声
#include <cmath>
#include <limits>
#include <cstdlib>
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
using namespace cv;
using namespace std;
double generateGaussianNoise(double m, double sigma);
Mat addGaussianNoise(Mat &srcImag);
int main()
{
Mat srcImage = imread("C:\\Users\\SYYSP\\Desktop\\BLOG\\滤波专题\\高斯滤波\\cp.jpg");
if (!srcImage.data)
{
cout << "未正确读入图片!" << endl;
system("pause");
return -1;
}
Mat dstImage = addGaussianNoise(srcImage);
string sResultPath = "C:\\Users\\SYYSP\\Desktop\\BLOG\\滤波专题\\高斯滤波\\cpAddGaussianNoise.jpg";
imwrite(sResultPath, dstImage);
GaussianBlur(dstImage, dstImage, Size(7, 7), 0, 0);
imwrite("C:\\Users\\SYYSP\\Desktop\\BLOG\\滤波专题\\高斯滤波\\cpRemoveGauss.jpg", dstImage);
waitKey();
return 0;
}
//生成高斯噪声
double generateGaussianNoise(double mu, double sigma)
{
//定义小值
const double epsilon = numeric_limits<double>::min();
static double z0, z1;
static bool flag = false;
flag = !flag;
//flag为假构造高斯随机变量X
if (!flag)
return z1 * sigma + mu;
double u1, u2;
//构造随机变量
do
{
u1 = rand() * (1.0 / RAND_MAX);
u2 = rand() * (1.0 / RAND_MAX);
} while (u1 <= epsilon);
//flag为真构造高斯随机变量
z0 = sqrt(-2.0*log(u1))*cos(2 * CV_PI*u2);
z1 = sqrt(-2.0*log(u1))*sin(2 * CV_PI*u2);
return z0 * sigma + mu;
}
//为图像添加高斯噪声
Mat addGaussianNoise(Mat &srcImag)
{
Mat dstImage = srcImag.clone();
int channels = dstImage.channels();
int rowsNumber = dstImage.rows;
int colsNumber = dstImage.cols*channels;
//判断图像的连续性
if (dstImage.isContinuous())
{
colsNumber *= rowsNumber;
rowsNumber = 1;
}
for (int i = 0; i < rowsNumber; i++)
{
for (int j = 0; j < colsNumber; j++)
{
//添加高斯噪声
int val = dstImage.ptr<uchar>(i)[j] +
generateGaussianNoise(2, 0.8) * 32;
if (val < 0)
val = 0;
if (val > 255)
val = 255;
dstImage.ptr<uchar>(i)[j] = (uchar)val;
}
}
return dstImage;
}
用作实例的两幅图像均来自网络,侵删。