图像去噪

文章目录
  1. 1. 理论
    1. 1.1. 噪声
    2. 1.2. 去噪
  2. 2. 实践
    1. 2.1. 添加噪声
    2. 2.2. 简单去噪
    3. 2.3. 均值滤波去噪法
    4. 2.4. 中值滤波去噪法
    5. 2.5. 高斯滤波去噪法
    6. 2.6. 傅里叶变换去噪
  3. 3. 后记

理论

噪声

噪声在图像上常表现为一引起较强视觉效果的孤立像素点或像素块。一般,噪声信号与要研究的对象不相关,它以无用的信息形式出现,扰乱图像的可观测信息。通俗的说就是噪声让图像不清楚。

图像常见噪声基本上有四种:高斯噪声,泊松噪声,乘性噪声,椒盐噪声。

令f(x,y)表示原始图象,g(x,y)表示图象信号,n(x,y)表示噪声。

根据噪声和信号的关系可将其分为三种形式:
1、加性噪声,此类噪声与输入图象信号无关,含噪图象可表示为f(x,y)=g(x,y)+n(x,y),信道噪声及光导摄像管的摄像机扫描图象时产生的噪声就属这类噪声;
2、乘性噪声,此类噪声与图象信号有关,含噪图象可表示为f(x,y)=g(x,y)+n(x,y)g(x,y),飞点扫描器扫描图象时的噪声,电视图象中的相关噪声,胶片中的颗粒噪声就属于此类噪声;
3、量化噪声,此类噪声与输入图象信号无关,是量化过程存在量化误差,再反映到接收端而产生。

更多内容参考图像噪声简介浅析“高斯白噪声”,“泊松噪声”,“椒盐噪声”的区别

去噪

图像的去噪处理方法基本上可分为空间域法和变换域法两大类。

空间域去噪方法的思想就是在原图像上对图像灰度值进行处理,通常采取“平均”或“平滑”的方法,将突变的噪声分量分散到周围像素中去,使图像变得较为平滑,降低噪声的影响。常用的空间域去噪方法有:均值去噪法,中值去噪法,高斯去噪法、维纳滤波去噪法等。

变换域去噪方法的思想是将原图像进行相关的变换,将图像信息变换到变换域中,再通过一定的方法来对图像信息进行处理,之后再通过反变换恢复图像信息,以达到图像去噪的目的。常用的变换域去噪方法有:傅里叶变换去噪方法,小波变换去噪方法等。

更多内容参考图像降噪一文道尽传统图像降噪方法

去噪方法又可以分为线性滤波和非线性滤波,更多内容参考什么是线性滤波、非线性滤波

实践

主要参考Image DenoisingSmoothing ImagesOpenCV图像噪声与去噪函数方法对比使用介绍

OpenCV中有多个可以降低图像噪声、对图像实现平滑滤波的函数,最常见的就是均值模糊与高斯模糊,它们都可以在一定程度上减低上述几种噪声,另外还有中值模糊、双边模糊、非局部去噪等函数方法可以使用,针对特定种类的噪声,使用有针对性函数与合理的参数可以取得较好的效果。

  • blur:对各种噪声都有一定的抑制作用。
  • GaussianBlur:对随机噪声比较好,对椒盐噪声效果不好。
  • medianBlur:对椒盐噪声效果比较好。
  • fastNlMeansDenoising:只支持灰度图像,非局部去噪,速度很慢,可以调参。
  • fastNlMeansDenoisingColored:同上,去噪针对彩色图像。

添加噪声

参考Python+opencv3对图像添加高斯噪声和椒盐噪声,给图像添加椒盐噪声。

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
# -*- coding: utf-8 -*-

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 定义添加椒盐噪声的函数
def SaltAndPepper(src,percetage):
SP_NoiseImg=np.copy(src)
SP_NoiseNum=int(percetage*src.shape[0]*src.shape[1])
for i in range(SP_NoiseNum):
randX=np.random.random_integers(0,src.shape[0]-1)
randY=np.random.random_integers(0,src.shape[1]-1)
if np.random.random_integers(0,1)==0:
SP_NoiseImg[randX,randY]=0
else:
SP_NoiseImg[randX,randY]=255
return SP_NoiseImg

img = cv2.imread('../image/test.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
NoiseImage = SaltAndPepper(GrayImage,0.01)

plt.subplot(121),plt.imshow(GrayImage,'gray')
plt.subplot(122),plt.imshow(NoiseImage,'gray')
plt.show()

简单去噪

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
# -*- coding: utf-8 -*-

import numpy as np
import cv2
import matplotlib.pyplot as plt

# 定义添加椒盐噪声的函数
def SaltAndPepper(src,percetage):
SP_NoiseImg=np.copy(src)
SP_NoiseNum=int(percetage*src.shape[0]*src.shape[1])
for i in range(SP_NoiseNum):
randX=np.random.random_integers(0,src.shape[0]-1)
randY=np.random.random_integers(0,src.shape[1]-1)
if np.random.random_integers(0,1)==0:
SP_NoiseImg[randX,randY]=0
else:
SP_NoiseImg[randX,randY]=255
return SP_NoiseImg

# 加载图片,灰度化,添加噪声
img = cv2.imread('../image/test.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
NoiseImage = SaltAndPepper(GrayImage,0.01)

# 直接调用opencv函数
dst = cv2.fastNlMeansDenoising(NoiseImage,10,7,21)

plt.subplot(121),plt.imshow(NoiseImage,'gray')
plt.subplot(122),plt.imshow(dst,'gray')
plt.show()

dst=cv.fastNlMeansDenoising(src, h[, dst[, templateWindowSize[, searchWindowSize[, normType]]]])参数说明:

  • src:输入8位1通道,2通道,3通道或4通道图像。
  • dst:输出与src具有相同大小和类型的图像。
  • h:参数调节滤波器强度。大h值可以完美地消除噪点,但也可以消除图像细节,较小的h值可以保留细节,但也会保留一些噪点。
  • templateWindowSize:用于计算权重的模板修补程序的窗口大小,奇数,推荐值7像素。
  • searchWindowSize:窗口的像素大小,用于计算给定像素的加权平均值,奇数,推荐21像素。

均值滤波去噪法

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
# -*- coding: utf-8 -*-

import numpy as np
import cv2
import matplotlib.pyplot as plt

# 定义添加椒盐噪声的函数
def SaltAndPepper(src,percetage):
SP_NoiseImg=np.copy(src)
SP_NoiseNum=int(percetage*src.shape[0]*src.shape[1])
for i in range(SP_NoiseNum):
randX=np.random.random_integers(0,src.shape[0]-1)
randY=np.random.random_integers(0,src.shape[1]-1)
if np.random.random_integers(0,1)==0:
SP_NoiseImg[randX,randY]=0
else:
SP_NoiseImg[randX,randY]=255
return SP_NoiseImg

img = cv2.imread('../image/test.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
NoiseImage = SaltAndPepper(GrayImage,0.01)
dst = cv2.blur(NoiseImage, (3,3))

plt.subplot(121),plt.imshow(NoiseImage,'gray')
plt.subplot(122),plt.imshow(dst,'gray')
plt.show()

dst=cv.blur(src, ksize[, dst[, anchor[, borderType]]])参数说明:

  • src:输入的图片。
  • ksize:模糊内核大小。
  • anchor:锚点,默认值Point(-1,-1)表示锚点位于内核中心。
  • borderType:边界模式用于外推图像外的像素。

均值滤波是一种典型的线性滤波算法,主要是利用像素点邻域的像素值来计算像素点的值。其具体方法是首先给出一个滤波模板kernel,该模板将覆盖像素点周围的其他邻域像素点,去掉像素本身,将其邻域像素点相加然后取平均值即为该像素点的新的像素值,这就是均值滤波的本质。官方给出的kernel模板如下:

中值滤波去噪法

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
# -*- coding: utf-8 -*-

import numpy as np
import cv2
import matplotlib.pyplot as plt

# 定义添加椒盐噪声的函数
def SaltAndPepper(src,percetage):
SP_NoiseImg=np.copy(src)
SP_NoiseNum=int(percetage*src.shape[0]*src.shape[1])
for i in range(SP_NoiseNum):
randX=np.random.random_integers(0,src.shape[0]-1)
randY=np.random.random_integers(0,src.shape[1]-1)
if np.random.random_integers(0,1)==0:
SP_NoiseImg[randX,randY]=0
else:
SP_NoiseImg[randX,randY]=255
return SP_NoiseImg

img = cv2.imread('../image/test.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
NoiseImage = SaltAndPepper(GrayImage,0.01)
dst = cv2.medianBlur(NoiseImage, 3)

plt.subplot(121),plt.imshow(NoiseImage,'gray')
plt.subplot(122),plt.imshow(dst,'gray')
plt.show()

dst=cv.medianBlur(src, ksize[, dst])参数说明:

  • src:输入的图片。
  • ksize:窗口的尺寸。它必须是奇数且大于1,例如:3、5、7。

中值滤波法和均值滤波法类似,不同的是,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值。

高斯滤波去噪法

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
# -*- coding: utf-8 -*-

import numpy as np
import cv2
import matplotlib.pyplot as plt

# 定义添加椒盐噪声的函数
def SaltAndPepper(src,percetage):
SP_NoiseImg=np.copy(src)
SP_NoiseNum=int(percetage*src.shape[0]*src.shape[1])
for i in range(SP_NoiseNum):
randX=np.random.random_integers(0,src.shape[0]-1)
randY=np.random.random_integers(0,src.shape[1]-1)
if np.random.random_integers(0,1)==0:
SP_NoiseImg[randX,randY]=0
else:
SP_NoiseImg[randX,randY]=255
return SP_NoiseImg

img = cv2.imread('../image/test.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
NoiseImage = SaltAndPepper(GrayImage,0.01)
dst = cv2.GaussianBlur(NoiseImage, (3,3), 0.8, 0.8)

plt.subplot(121),plt.imshow(NoiseImage,'gray')
plt.subplot(122),plt.imshow(dst,'gray')
plt.show()


dst=cv.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])参数说明:

  • src:输入的图片。
  • ksize:高斯核大小。ksize.width和ksize.height可以不同,但​​它们都必须是正数和奇数。或者,它们可以为零,然后根据sigma计算。
  • sigmaX:X方向的高斯核标准偏差。
  • sigmaY:Y方向的高斯核标准偏差。如果sigmaY为零,则将其设置为等于sigmaX,如果两个sigma均为零,则分别从ksize.width和ksize.height计算。

高斯滤波的原理参考高斯滤波器详解

傅里叶变换去噪

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
39
40
41
42
43
44
# -*- coding: utf-8 -*-

import numpy as np
import cv2
import matplotlib.pyplot as plt

# 定义添加椒盐噪声的函数
def SaltAndPepper(src,percetage):
SP_NoiseImg=np.copy(src)
SP_NoiseNum=int(percetage*src.shape[0]*src.shape[1])
for i in range(SP_NoiseNum):
randX=np.random.random_integers(0,src.shape[0]-1)
randY=np.random.random_integers(0,src.shape[1]-1)
if np.random.random_integers(0,1)==0:
SP_NoiseImg[randX,randY]=0
else:
SP_NoiseImg[randX,randY]=255
return SP_NoiseImg

# 加载图片,灰度化,添加噪声
img = cv2.imread('../image/test.jpg')
GrayImage = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
NoiseImage = SaltAndPepper(GrayImage,0.01)

# dft
dft = cv2.dft(np.float32(NoiseImage),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

rows, cols = NoiseImage.shape
crow, ccol = int(rows/2) , int(cols/2)

# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

# apply mask and inverse DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
dst = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

plt.subplot(121),plt.imshow(NoiseImage,'gray')
plt.subplot(122),plt.imshow(dst,'gray')
plt.show()


dst=cv.dft(src[, dst[, flags[, nonzeroRows]]])参数说明:

  • src:输入数组可能是实数或复数。
  • flag:转换标志,代表DftFlags的组合。
  • nonezeroRows:当参数不为零时,该函数假定只有输入数组的第一个非零行或仅输出数组的第一个非零行包含非零。因此,函数可以更有效地处理其余行并节省一些时间,这种技术对于使用DFT计算阵列互相关或卷积非常有用。

更多内容参考:

后记

以上,实现了部分滤波去噪法。对于维纳滤波去噪法和小波变换去噪法,数学原理比较复杂,就先放一边,等有需要了再来进行实现。对于傅里叶变换去噪法,一知半解,还需要继续学习。