要点
1.图像的几种去噪处理
(1)均值滤波
(2)高斯滤波
(3)中值滤波
(4)双边滤波
2.解释
概述:从统计学的观点来看,凡是统计特征不随时间变化的噪声称为平稳噪声,而统计特征随时间变化的噪声称为非平稳噪声。幅值基本相同,但是噪声出现的位置是随机的,称为椒盐噪声;如果噪声的幅值是随机的,根据幅值大小的分布,有高斯型和瑞利型两种,分别称为高斯噪声和瑞利噪声。
(1)均值滤波:均值滤波方法是,对待处理的当前像素,选择一个模板,该模板为其邻近的若干个像素组成,用模板的均值来替代原像素的值的方法。
均值滤波算法较简单粗暴,先直接选定一个核,然后在图像上做卷积,取值为一个核内的平均值。优点是计算简单,缺点是会造成图像的模糊,特别在边缘和一些细节部分。
(2)高斯滤波:高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。(简单做一个理解,还是要到程序中进行体会,另外需要说明的是高斯核在尺度空间中有很大的作用,它是唯一能够模拟scale变化的因子)。
(3)中值滤波:中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点。方法是用某种结构的二维滑动模板,将板内像素按照像素值的大小进行排序,生成单调上升(或下降)的为二维数据序列。其实中值滤波的思想很简单,就是对均值滤波的一点点小的改进,主要针对的是椒盐噪声,针对这些异常值取中值的话自然能够有一个比较好的结果。
(4)双边滤波:双边滤波相对而言较为复杂些,它是针对高斯滤波做的一个改进,高斯滤波实质上关注的是空间上的靠近程度,其实在一幅图像中,除了空间上的相似,还有一些别的特性,简单说,它还比较像素值相近的区域的一种靠近程度。像素一下,一幅图片中,有两面墙,这两面墙在图片中的左右边,空间域上是不临近的,不过实质上这两片像素区域也是相近的,如果在这里引入了噪声,那么综合考虑这两面墙是不是能增强滤波效果?答案是肯定的。滤波器是由两个函数构成。一个函数是由几何空间距离决定滤波器系数。另一个由像素差值决定滤波器系数。这两个函数都是高斯的。
下面附上一些公式:
双边滤波器中,输出像素的值依赖于邻域像素的值的加权组合
权重系数w(i,j,k,l)取决于定义域核
和值域核
的乘积
3.程序
废话不多说,附上程序,直接用opencv去实现的,如果要自己写,问题也不难,均值滤波没写
#include <opencv2\opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
Mat g_srcImage, g_dstImage1, g_dstImage2, g_dstImage3;
int g_GaussianValue = 1;
int g_mediaValue = 1;
int g_biValue = 1;
static void on_GaussianFilter(int, void *)
{
GaussianBlur(g_srcImage, g_dstImage1, Size(g_GaussianValue * 2 + 1, g_GaussianValue * 2 + 1), 0, 0);
imshow("Gaussian Filter", g_dstImage1);
}
static void on_mediaFilter(int, void *)
{
medianBlur(g_srcImage, g_dstImage2, 2 * g_mediaValue + 1);
imshow("Median Filter", g_dstImage2);
}
static void on_biFilter(int, void *)
{
bilateralFilter(g_srcImage, g_dstImage3, g_biValue, 2 * g_biValue, g_biValue / 2);//每个像素邻域的直径
imshow("Bilateral Filter", g_dstImage3);
}
double gaussianNoise(double mu, double sigma)
{
const double epilson = numeric_limits<double>::min();
double z0;
double z1=0.0;
static bool flag = false;
flag = !flag;
if (!flag)
return z1*sigma + mu;
double u1, u2;
do
{
u1 = rand()*(1.0 / RAND_MAX);
u2 = rand()*(1.0 / RAND_MAX);
} while (u1 <= epilson);
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 addNoise(Mat& image)
{
Mat dstImage = image.clone();
int channels = dstImage.channels();
for (int y = 0; y < image.rows; y++)
{
for (int x = 0; x < image.cols*channels; x++)
{
int val = dstImage.ptr<uchar>(y)[x] + gaussianNoise(2, 1) * 32;
if (val < 0)
val = 0;
if (val>255)
val = 255;
dstImage.ptr<uchar>(y)[x] = (uchar)val;
}
}
return dstImage;
}
int main()
{
system("color5E");
g_srcImage = imread("F:\\c_code\\week5_1\\week5_1\\1.jpg");
g_srcImage = addNoise(g_srcImage);
if (!g_srcImage.data)
{
cout << "error" << endl;
}
namedWindow("source", 1);
imshow("source", g_srcImage);
namedWindow("Gaussian Filter", 1);
createTrackbar("kernel:", "Gaussian Filter", &g_GaussianValue, 40, on_GaussianFilter);
on_GaussianFilter(g_GaussianValue, 0);//初始化
namedWindow("Median Filter", 1);
createTrackbar("kernel:", "Median Filter", &g_mediaValue, 40, on_mediaFilter);
on_mediaFilter(g_mediaValue, 0);
namedWindow("Bilateral Filter", 1);
createTrackbar("kernel:", "Bilateral Filter", &g_biValue, 40, on_biFilter);
on_biFilter(g_biValue, 0);
while (char(waitKey(1) != 'q'))
{
}
return 0;
}
最后华丽丽的给出结果图
实验效果请各位童鞋在源代码上进行修改应用,并自行查看O(∩_∩)O