图像滤波
- 前言
- 1.制作噪声
- 生成椒盐噪声
- 生成高斯噪声
- 2.滤波
- 均值滤波
- 框滤波
- 高斯滤波
- 中值滤波
- 总结
前言
很多时候我们能拿到的图片并不是十分干净,有时会有一些噪声,这时我们就应该采用滤波的方式对他进行处理,本文将在一张干净的图片上生成噪声并进行滤波操作。
1.制作噪声
假设我们有这样一张名为kl.jpg的图片
读入
img=cv2.imread('kl.png')
接下来我们要在这张图片上制作噪声来模拟有噪声情况下的图片,以供学习滤波
为了显示方便我们先定义一个显示图像的函数
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
生成椒盐噪声
椒盐噪声是出现在随机位置、噪点深度基本固定的噪声,下面代码的原理就是随机选择图像上的点并将他们替换成全0或者全255
import random
def make_random_noise(img, rate=0.01):
imgInfo = img.shape
height = imgInfo[0] - 1 # 防止越界
width = imgInfo[1] - 1
random_noise = img.copy()
temp = int(img.shape[0] * img.shape[1] * rate) # 噪声点的个数占总像素点的rate
for i in range(0, temp):
if random.randint(1, temp) % 2 == 0:
random_noise[random.randint(0, height), random.randint(0, width)] = (255, 255, 255)
if random.randint(1, temp) % 2 != 0:
random_noise[random.randint(0, height), random.randint(0, width)] = (0, 0, 0)
return random_noise
random_noise = make_random_noise(img)
cv_show(random_noise, 'random noise')
效果如下
生成高斯噪声
高斯噪声与椒盐噪声相反,是几乎每个点上都出现噪声、噪点深度随机的噪声
def make_gauss_noise(img, mean, var):
image = np.array(img / 255, dtype=float) # 将原始图像的像素值进行归一化,除以255使得像素值在0-1之间
noise = np.random.normal(mean, var ** 0.5, image.shape) # 创建一个均值为mean,方差为var呈高斯分布的图像矩阵
out = image + noise # 将噪声和原始图像进行相加得到加噪后的图像
if out.min() < 0:
low_clip = -1.
else:
low_clip = 0.
resultImg = np.clip(out, low_clip, 1.0) # clip函数将元素的大小限制在了low_clip和1之间了,小于的用low_clip代替,大于1的用1代替
resultImg = np.uint8(resultImg * 255) # 解除归一化,乘以255将加噪后的图像的像素值恢复
return resultImg
gauss_noise = make_gauss_noise(img, 0, 0.02)
cv_show(gauss_noise, "gauss_noise")
2.滤波
均值滤波
均值滤波实际上就是简单的平均卷积操作,即每个滤波后的像素点是有噪声的图像中对应位置的卷积核内的像素点均值
我们使用cv2.blur函数可以进行均值滤波,参数需要图像和卷积核大小
random_blur = cv2.blur(random_noise, (7, 7))
gauss_blur = cv2.blur(gauss_noise, (7, 7))
cv2.imshow('random gauss blur', np.hstack([random_blur, gauss_blur]))
cv2.waitKey(0)
cv2.destroyAllWindows()
左侧是椒盐噪声下均值滤波的效果,右侧是高斯滤波下的滤波效果,可以看到均值滤波能较好的解决椒盐噪声
框滤波
使用cv2.boxFilter可以实现框滤波,框滤波基本和均值一样,可以选择归一化,一般不进行归一化容易越界,所以尽量还是使用均值cv2.blur滤波比较好
box_1 = cv2.boxFilter(random_noise,-1,(7,7), normalize=True)
box_2 = cv2.boxFilter(random_noise,-1,(7,7), normalize=False)
cv2.imshow('box', np.hstack([box_1, box_2]))
cv2.waitKey(0)
cv2.destroyAllWindows()
左侧归一化,右侧没有归一化
高斯滤波
高斯模糊的卷积核里的数值是满足高斯分布,相当于更重视中间的,cv2.GaussianBlur可以实现高斯滤波,下面看一下高斯滤波在随机噪声和高斯噪声的效果
gauss_1 = cv2.GaussianBlur(random_noise, (9, 9), 1)
gauss_2 = cv2.GaussianBlur(gauss_noise, (9, 9), 1)
cv2.imshow('gaussian', np.hstack([gauss_1, gauss_2]))
cv2.waitKey(0)
cv2.destroyAllWindows()
可以看到高斯滤波在椒盐噪声上效果一般,但是在高斯噪声上会比均值滤波稍好一些
中值滤波
相当于用中值代替均值滤波中的均值
median_1 = cv2.medianBlur(random_noise, 5) # 中值滤波
median_2 = cv2.medianBlur(gauss_noise, 5)
cv2.imshow('median', np.hstack([median_1, median_2]))
cv2.waitKey(0)
cv2.destroyAllWindows()
由于噪声很难正好赶上是图像的中值,所以在很多情况下中值滤波能得到很好的效果
总结
均值滤波适合椒盐噪声,高斯滤波适合高斯噪声,两种噪声都要尝试一下中值滤波通过比较得出较好的图片