Opencv-python从入门到放弃 —— 图像降噪(8)

自己是一个菜鸡,希望通过写博客的方式提升自己,最近正好接触到了opencv,想把学习路程以博客的形式记录下来,也算是学习opencv的一种动力吧,好吧,话不多说,干就完了!

一、基础知识

均值滤波
一个K×K大小的窗口从图像左上角开始,从左到右,从上到下划过整个图像,这个K×K的窗口称为卷积核,卷积核的锚点一般位于窗口的中心位置,所以卷积核的边长一般为奇数。在滑窗的过程中,计算窗口内像素的平均值,用这个平均值来代替锚点的像素值,遍历过后,图像的纹理信息减弱,噪声减弱,图像变得平滑。
tips:边缘怎么处理?当锚点位于图像边缘时,卷积核一部分位于图像外边,这时有两种处理方法。一种成为padding操作,即图像上下左右各添加 (Ksize - 1) / 2个像素点,这些多出来的像素点初始化的方式有很多种,一般就是初始化成0,当然还有重复、对称等等类型的初始化方法,opencv内部默认为图像做padding操作,这样经过全局卷积操作后图像的大小维持不变。另一种就是边缘的像素点不予考虑,只能从能放下完整卷积核的地方开始滑窗,经过这样的操作后图像的宽、高变为(Width - Ksize + 1, Height 0 Ksize + 1),即图像变小了。
特点:Ksize越大,图像越平滑。。也就是越模糊。。是线性滤波器。
API:res = cv2.blur(image, (ksize, ksize)) 可以作用于RGB图像
高斯滤波
高斯滤波要比均值滤波效果好很多,考虑到了卷积核内的像素值对最终结果的贡献大小,即赋予卷积核内的像素以一定的权重,每点的权重乘以当前卷积核所对应到原图的像素值相加最后除以权重的和作为输出结果。
特点:考虑到卷积核内像素的权重,是线性滤波器。是应用最多最多的平滑滤波器!一般的图像预处理操作都少不了它!!使用频率极高。一般滴,高斯卷积核越大,方差越大,图像就越模糊。
API:res = cv2.GaussianBlur(image, (size, size), sigmaX, sigmaY) sigmaX和sigmaY代表了横轴与纵轴权重的标准差,若为0就是让opencv帮你自动推算方差大小。可作用于RGB图像
中值滤波
中值滤波后代替锚点的像素值为卷积核内像素灰度值的中值。
特点:是一种非线性滤波器,能够很好的消除椒盐噪声,而线性滤波器对椒盐噪声毫无办法!只能让椒盐噪声点变大(原因很简单)
tip:椒盐噪声分为椒噪声(pepper)和盐噪声(salt)。椒噪声点处灰度值为0,盐噪声点处灰度值为255。
API:cv2.medianBlur(image, Ksize) 注意这里的第二个参数不是tuple了,是一个整数,代表了(Ksize, Ksize),所以意义是一样的。能够作用于RGB图像。
双边滤波
前面说过算法在降噪的同时也会削弱边缘、纹理等信息。有没有什么平滑滤波器能够在平滑图像(降噪)的同时,还能保留明显的边缘信息呢?这就是要说的双边滤波了。双边滤波不仅考虑卷积核内像素点位置信息的权重,还考虑了卷积核内像素点除锚点外的各点与锚点灰度差值的权重!也就是说系数由两个二维高斯函数的乘积联合确定。
特点:比如ps的磨皮、人物卡通化都是通过双边滤波实现的。该算法复杂度高,耗时长。。。
API:cv2.bilaterFilter(image, Ksize, sigmaColor, sigmaSpace) Ksize是一个整数,代表了卷积核的大小,sigmaColor是灰度差值权重的标准差,sigmaSpace是位置权重的标准差,和前面的高斯滤波的权重是一致的,这两个标准差越大,滤波能力越强,同时还能较好的保留边缘信息。能够作用于RGB图像。

二、Demo

import cv2
import numpy as np

image = cv2.imread('./trex.png')
image_blur = np.hstack(      # 结果图像的水平拼接
    [cv2.blur(image, (3, 3)),  # kernel_size为3×3
    cv2.blur(image, (5, 5)),
    cv2.blur(image, (7, 7))]  # 能够看到图像变得越来越模糊
)  
cv2.imwrite('blur_of_diff_size.jpg', image_blur)

image_gaussian = np.hstack([
    cv2.GaussianBlur(image, (3, 3), 0),
    cv2.GaussianBlur(image, (5, 5), 0),
    cv2.GaussianBlur(image, (7, 7), 0)   # 可以看出效果没有均值滤波模糊的那么厉害
])
cv2.imwrite('blur_of_diff_gaussian_size.jpg', image_gaussian)

def make_sp_noise(image, ratio):  
    """人为的为图像添加椒盐噪声,ratio规定了噪声点占全局像素的比例"""
    h, w = image.shape[:2]
    image_copy = image.copy()
    nums = int(h * w * ratio) # 椒盐噪声点占比
    for i in range(nums):
        row = np.random.randint(0, h)
        col = np.random.randint(0, w)
        if i % 2 == 0:
            image_copy[row, col] = 255
        else:
            image_copy[row, col] = 0
    return image_copy

image_with_sp = make_sp_noise(image, 0.7)
cv2.imwrite('image_with_sp.jpg', image_with_sp)
image_mid_blur = np.hstack([
    cv2.medianBlur(image_with_sp, 3),
    cv2.medianBlur(image_with_sp, 5),
    cv2.medianBlur(image_with_sp, 7)  # 邻域越大,过滤椒盐噪声效果越好,但是图像质量也会下降明显。除非非常密集椒盐噪声,否则不推荐Ksize=7这么大的卷积核
])
cv2.imwrite('image_remove_noise.jpg', image_mid_blur)
# 对比:高斯滤波对滤除椒盐噪声
image_gaussian_compare = np.hstack([
    cv2.GaussianBlur(image_with_sp, (3, 3), 0),
    cv2.GaussianBlur(image_with_sp, (5, 5), 0),
    cv2.GaussianBlur(image_with_sp, (7, 7), 0)  
])
cv2.imwrite('image_remove_noise_compare.jpg', image_gaussian_compare)

image = cv2.imread('./beach.png')
image_bilater = np.hstack([
    cv2.bilateralFilter(image, 5, 21, 21),
    cv2.bilateralFilter(image, 7, 31, 31),
    cv2.bilateralFilter(image, 9, 41, 41)
])
cv2.imwrite('image_bilater.jpg', image_bilater)

运行结果:
blur_of_diff_size.jpg
blur_of_diff_gaussian_size.jpg
image_with_sp.jpg
image_remove_noise.jpg
image_remove_noise_compare.jpg
image_bilater.jpg

三、总结

  1. 学习了均值、高斯、中值、双边滤波。其中高斯滤波应用最为广泛,几乎所有图像的预处理操作都会使用这个。中值滤波能够非常好的去除椒盐噪声。双边滤波用于人物磨皮、人物脸型卡通化等操作。
  2. 排版差。

猜你喜欢

转载自blog.csdn.net/Annihilation7/article/details/82718470