今天上完图像处理的实验课
记录一下中值滤波的原理和Python的实现方式:
大佬中值滤波的博客(代码参考)
中值滤波法是一种非线性平滑技术,它将每一像素点的灰度值设置为该点某邻域窗口内的所有像素点灰度值的中值。
这种滤波法对椒盐噪声有很强的过滤效果。
首先,我们为一张灰度图片添加椒盐噪点,这里选用的是经典的Lena图:
from PIL import Image
import numpy as np
def AddNoise(src, dst, probability=0.05, method="salt_pepper"): # 给图像添加椒盐噪声
imarray = np.array(Image.open(src))
height, width, R = imarray.shape # 打开的图象是三通道的,所以需要三个数值来接收
for i in range(height):
for j in range(width):
if np.random.random(1) < probability: # probability限制椒盐噪声出现的频率
if np.random.random(1) < 0.5:
imarray[i, j] = 0
else:
imarray[i, j] = 255
new_im = Image.fromarray(imarray)
new_im.save(dst)
gray_girl = "E:\kong\Pycharm\homework\lena.jpg"
tar = "E:\kong\Pycharm\homework\lena_saltpepper.jpg"
AddNoise(gray_girl, tar)
添加噪点之前:
添加噪点之后:
接下来编写中值滤波器的代码,这里我们按照上面那篇大佬的文章里滤波器的形式。不使用填充,同时忽略边缘:
def MedianFilter(src, dst, k=3, padding=None): # 进行中值滤波,选择的是忽略边缘的滤波方式
imarray = np.array(Image.open(src).convert('L')) # 也可以采用convert直接转换成灰度图
height, width = imarray.shape
if not padding: # 当没有边缘时
edge = int((k - 1) / 2) # 边缘忽略值
if height - 1 - edge <= edge or width - 1 - edge <= edge:
print("The parameter k is to large.")
return None
new_arr = np.zeros((height, width), dtype="uint8")
for i in range(height):
for j in range(width):
if i <= edge - 1 or i >= height - 1 - edge or j <= edge - 1 or j >= height - edge - 1:
new_arr[i, j] = imarray[i, j]
else: # 没有设计排序算法,直接使用Numpy中的寻找中值函数
new_arr[i, j] = np.median(imarray[i - edge:i + edge + 1, j - edge:j + edge + 1])
new_im = Image.fromarray(new_arr)
new_im.save(dst)
src = "E:\kong\Pycharm\homework\lena_saltpepper.jpg"
dst = "E:\kong\Pycharm\homework\lena_saltpepper_finish.jpg"
MedianFilter(src, dst)
这是滤波之后的图片:
可以观察到,除了图像边缘之外的椒盐噪点被有效清除了。
同时对比可以发现,这一张图片的清晰度对比添加噪点之前的清晰度有所降低。
这是因为中值滤波会对图片里面的边缘也进行中值处理,会使得整个图像的清晰度下降。至于如何降低此操作的影响,详情也请见上方置顶的大佬的文章。