图像处理——图像降噪

图像降噪

数字图像在数字化和成像过程中会受到成像设备或外界环境的影响,受到干扰产生的图像叫做噪声图像。

按照噪声的引入方式分类,可以将噪声分成加性噪声乘法性噪声。加性噪声的幅度与信号的幅度无关,是叠加在图像上的,比较容易去除。成性噪声的幅度与信号的幅度成正比,比较难去除。不过乘性噪声可以通过取对数的方式转化为加性噪声,实际上大部分去噪算法都会假设噪声为加性高斯白噪声

按照噪声的性质分类,可以将噪声分成脉冲噪声(Impluse Noise)),椒盐噪声(Pepper-Salt noise)和⾼斯⽩噪声(Gaussian white noise),莱斯噪声(Racian noise)等。

传统降噪算法根据降噪的原理不同可分为基于邻域像素特征的⽅法,基于频域变换的⽅法,和基于特定模型的⽅法。本文主要讲述基于邻域像素特征的方法,并用 OpenCV 实现相应算法。

基于邻域像素特征的⽅法,是通过分析在⼀定⼤⼩的窗口内,中⼼像素与其他相邻像素之间在灰度空间的直接联系,来获取新的中⼼像素值的⽅法,因此往往都会存在⼀个典型的输⼊参数,即滤波半径 r。此滤波半径可能被⽤于在该局部窗⼜内计算像素的相似性,也可能是⼀些⾼斯或拉普拉斯算⼦的计算窗口。在邻域滤波⽅法⾥⾯,最具有代表性的滤波⽅法有以下⼏种。

算数均值滤波

均值滤波示意图

上图演示 6x6 的图片,采用边框补零的方式,与 3x3 的卷积核做步长为 1 的卷积操作。

原理:均值滤波用像素邻域的平均灰度来代替像素值,适用于脉冲噪声,因为脉冲噪声一般与周围像素的灰度级不相关,而且亮度高出其他像素很多。

缺点:均值滤波随着半径取值增大而变得越来越模糊,因为均值操作之后,噪声被分散到了周围像素点,但是噪声区域也不可避免地增大了。

解决:采用设定阈值的方式可以一定程度上避免这一问题。比较噪声和领域像素的灰度,只有当灰度差达到设定的阈值才判定为噪声。

实现:可以使用 OpenCV 中的 blur() 实现算数均值滤波的效果。

1
2
3
4
5
6
void cv::blur	(	InputArray src,
					OutputArray dst,
					Size ksize,
					Point anchor = Point(-1,-1),
					int borderType = BORDER_DEFAULT 
)
  • src: 带有噪声的原图像,深度必须为 CV_8U, CV_16U, CV_16S, CV_32F or CV_64F 中的一种
  • dst: 去噪之后的图像,要求图像大小与噪声图像一样,可以使用 Mat::Clone 的方法实现
  • ksize: 卷积核的大小,比如说 Size(3, 3) 表示大小为 3x3 的矩阵
  • point: Point 类型的 anchor,采用默认值表示取卷积核的中心为锚点
  • borderType: 推断图像外包部像素的某种边界模式,一般用默认的即可
1
cv::blur(src, meanFilter, cv::Size(6, 6));

高斯滤波

原理:用一个卷积核扫描图像中的每一个像素,确定领域内像素的加权平均灰度值去代替模板中心像素点的值。图像高斯模糊的过程就是图像与正态分布做卷积,正态分布也叫高斯分布,所以也叫高斯模糊技术。

优点:相比于均值滤波,高斯滤波矩阵的权值随着与中心像素点距离的增加呈现高斯衰减的特性,因此对距离算子越远的像素点作用越小,从⽽能在⼀定程度上保持图像的边缘特征。通过调节⾼斯平滑参数,可以在图像特征过分模糊和⽋平滑之间取得折中。

实现:可以使用 OpenCV 中的 GaussianBlur() 实现算数均值滤波的效果。

1
2
3
4
5
6
7
void cv::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 or CV_64F 中的一种
  • dst: 去噪之后的图像,要求图像大小与噪声图像一样,可以使用 Mat::Clone 的方法实现
  • ksize: 高斯滤波矩阵的代销,ksize.width and ksize.height 可以不同,但必须为正数、奇数或零,它们是用过 signma 计算得到的。
  • sigmaX: 高斯核函数在 X 方向的标准偏差
  • sigmaY: 高斯核函数在 Y 方向的标准偏差。若 sigmaY 为 0 就将其设为 sigmaX;若 sigmaX 和 sigmaY 都为 0,则通过 ksize.width and ksize.height 计算得出。
  • borderType: 推断图像外包部像素的某种边界模式,一般用默认的即可
1
cv::GaussianBlur(src, gaussianBlur, cv::Size(5, 5), 0, 0);

统计中值滤波

原理:对窗口内的像素值进⾏排序,然后使⽤灰度值的中间值代替窗口中⼼位置像素的灰度,适⽤于椒盐噪声和脉冲噪声。

优点:中值滤波属于非线性滤波,当噪声是散粒噪声而不是高斯噪声时,即图像偶尔会出现很大的值时,用高斯滤波对图像进行模糊噪声像素不会被去除,而中值滤波⽐相同尺⼨的线性平滑滤波器引起的模糊更少,能较好的保持边缘。

缺点:中值滤波会使图像中的⼩⽬标丢失。当噪声像素个数⼤于窗口像素总数的⼀半时,由于灰度排序的中间值仍为噪声像素灰度值,会导致滤波效果很差,且中值滤波花费的时间是均值滤波的 5 倍以上。

实现:可以使用 OpenCV 中的 medianBlur() 实现中值滤波。

1
2
3
4
void cv::medianBlur	(	InputArray src,
						OutputArray dst,
						int ksize
)
  • src: 带有噪声的原图像,深度必须为 CV_8U, CV_16U, CV_16S, CV_32F or CV_64F 中的一种
  • dst: 去噪之后的图像,要求图像大小与噪声图像一样,可以使用 Mat::Clone 的方法实现
  • ksize: aperture linear size,必须为大于 1 的奇数,比如:3、5、7、9……
1
cv::medianBlur(src, medianBlur, 3);

双边滤波

原理:滤波器是由两个函数构成。⼀个函数是由⼏何空间距离决定滤波器系数,另⼀个由像素差值决定滤波器系数。双边滤波器中,输出像素的值依赖于邻域像素的值的加权组合,它同时考虑了空间域与值域的差别。

优点:可以做到边缘保存,在边缘附近,距离较远的像素不会对边缘上的像素造成太大影响。

缺点:由于保存了过多的高频信息,对于图像里的高频噪声,双边滤波器不能干净地过滤掉,只能对于低频信号进行较好的滤波。

实现:可以使用 OpenCV 中的 bilateralFilter() 实现双边滤波的效果。

1
2
3
4
5
6
7
void cv::bilateralFilter	(	InputArray 	src,
								OutputArray 	dst,
								int 	d,
								double 	sigmaColor,
								double 	sigmaSpace,
								int 	borderType = BORDER_DEFAULT 
)
  • src: 带有噪声的原图像,深度必须为 CV_8U, CV_16U, CV_16S, CV_32F or CV_64F 中的一种
  • dst: 去噪之后的图像,要求图像大小与噪声图像一样,可以使用 Mat::Clone 的方法实现
  • d: 表示在过滤过程中每个像素邻域的直径,如果这个值被设为非正数,那么 OpenCV 会从第 5 个参数 sigmaSpace 来计算出它
  • sigmaColor: 颜色空间滤波器 sigma 值,这个参数的值越大,就表名该像素邻域范围内有越宽广的颜色会被很合到一起,产生较大的半相等颜色区域
  • sigmaSpace: 做表空间中滤波器的 sigma 值,坐标空间的标注方差。它的数值越大,意味着越远的像素会相互影响,从而使更大的区域中足够相似的颜色获得相同的颜色。当 d>0 时,d 指定了邻域大小且与 sigmaSpace 无关。否则,d 正比于 sigmaSpace。
  • borderType: 推断图像外包部像素的某种边界模式,一般用默认的即可
1
cv::bilateralFilter(src,bilateralfilter,25,25*2,25/2);

代码与效果演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
 * 使用 4 种空域滤波方法,对 noise 图进行降噪
 * 
 * 1. 算数均值滤波
 * 2. 高斯滤波
 * 3. 统计中值滤波
 * 4. 双边滤波
 * 
 **/

#include <iostream>
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgcodecs.hpp"

int main()
{
    cv::Mat src = cv::imread("../images/noise.jpg", cv::IMREAD_COLOR);
    cv::Mat meanFilter;
    cv::Mat medianBlur;
    cv::Mat gaussianBlur;
    cv::Mat bilateralfilter;

    cv::blur(src, meanFilter, cv::Size(6, 6));
    cv::GaussianBlur(src, gaussianBlur, cv::Size(5, 5), 0, 0);
    cv::medianBlur(src, medianBlur, 3);
    cv::bilateralFilter(src,bilateralfilter,25,25*2,25/2);

    cv::imshow("1. src", src);
    cv::imshow("2. meanFilter", meanFilter);
    cv::imshow("3. gaussianBlur", gaussianBlur);
    cv::imshow("4. medianBlur", medianBlur);
    cv::imshow("5. bilateralfilter", bilateralfilter);

    cv::waitKey(0);

    return 0;
}

图像降噪效果图

posted @ 2019-06-02 02:01  深页  阅读(592)  评论(0编辑  收藏  举报