使用中值滤波器去除椒盐噪声

379 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第35天,点击查看活动详情

前言

邻域平均可以抑制孤立的异常值噪声,但相应的副作用是它也会模糊图像中较为突然变化,例如线条特征、锐利的边缘和其他图像细节,这些图像细节均与高频相对应。非线性中值滤波器在保持图像中有用细节方面通常比线性均值滤波器更加有效,并且更适合去除图像中的椒盐噪声。

与平均滤波器一样,中值滤波器依次考虑图像中的每个像素,并查看其窗口邻域中的像素值来决定该像素能否表示周围邻域。它不是简单地用相邻像素值的平均值替换像素,而是用这些值的中位数代替。首先将周围邻域中的所有像素值按数字顺序排序,然后用排序后的序列中间值替换像素值。

使用中值滤波器去除椒盐噪声

首先,导入所需 Python 库,读取输入 RGB 彩色图像,并在输入图像中添加 1% 随机脉冲噪声:

import numpy as np
import matplotlib.pylab as plt
from PIL import Image, ImageFilter
from copy import deepcopy

def plot_image(image, title=None, sz=10):
    plt.imshow(image)
    plt.title(title, size=sz)
    plt.axis('off')

def add_noise(im, prop_noise, salt=True, pepper=True):
    im = deepcopy(im)
    n = int(im.width * im.height * prop_noise)
    x, y = np.random.randint(0, im.width, n), np.random.randint(0, im.height, n)
    for (x,y) in zip(x,y):
        im.putpixel((x, y),         # generate salt-and-pepper noise
        ((0,0,0) if np.random.rand() < 0.5 else (255,255,255)) if salt and pepper \
        else (255,255,255) if salt \
        else (0, 0, 0)) # if pepper
    return im

im = Image.open('1.png')
im = add_noise(im, prop_noise = 0.1)

使用 PILimage.filter() 函数指定参数 imageFilter.medianfilter 创建多个不同核窗口大小的中值滤波器,绘制使用不同尺寸大小的滤波器得到的输出图像。

如前所述,中值滤波器为从给定大小的滑动窗口中选取中值像素值:

plt.figure(figsize=(20,10))
plt.subplot(1,4,1)
plot_image(im, 'Input noisy image')
i = 2
for sz in [3,7,11]:
    im1 = im.filter(ImageFilter.MedianFilter(size=sz))
    plt.subplot(1,4,i), plot_image(im1, 'Output (Filter size=' + str(sz) + ')', 10)
    i += 1
plt.tight_layout()
plt.show()

Figure_3.png

从以上输出结果可以看出,与平均滤波器相比,中值滤波器产生的模糊性较小,但是对于较大尺寸的中值滤波器核,它会在输出图像中导致较多纹理损失。