opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))

图像平滑(模糊)与图像滤波

  • 低通滤波和高通滤波
  • 学习使用不同的低通滤波器对图像进行模糊
  • 使用自定义的滤波器对图像进行卷积(2D 卷积)
  • opencv中常见的图像滤波

一、低通滤波和高通滤波

与以为信号一样,我们也可以对 2D 图像实施低通滤波(LPF),高通滤波(HPF)。

  • LPF 帮助我们去除噪音,模糊图像
  • HPF 帮助我们找到图像的边缘
  • 低通滤波器是模糊,高通滤波器是锐化
  • 低通滤波器就是允许低频信号通过,在图像中边缘和噪点都相当于高频部分,所以低通滤波器用于去除噪点、平滑和模糊图像。高通滤波器则反之,用来增强图像边缘,进行锐化处理。

二、图像卷积概念

在OpenCV中也可以自己定义自己的滤波器,然后使用filter2D函数进行运算。OpenCV 提供的函数 cv.filter2D() 可以让我们对一幅图像进行卷积操作。

dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

  • 参数 描述
    • src 原图像
    • dst 目标图像,与原图像尺寸和通过数相同
    • ddepth ddepth表示目标图像的所需深度,它包含有关图像中存储的数据类型的信息,可以是unsigned char(CV_8U),signed char(CV_8S),unsigned short(CV_16U)等等。 当ddepth=-1时,表示输出图像与原图像有相同的深度。
    • kernel 卷积核(或相当于相关核),单通道浮点矩阵;如果要将不同的内核应用于不同的通道,请使用拆分将图像拆分为单独的颜色平面,然后单独处理它们。
    • anchor 内核的锚点,指示内核中过滤点的相对位置;锚应位于内核中;默认值(-1,-1)表示锚位于内核中心。
    • detal 在将它们存储在dst中之前,将可选值添加到已过滤的像素中。类似于偏置。
    • borderType 像素外推法,参见BorderTypes

下面我们将对一幅图像使用平均滤波器。下面是一个 5x5 的平均滤波器核:
opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))_第1张图片

操作过程:将核放在图像的一个像素 A 上,求与核对应的图像上 25(5x5)个像素的和,在取平均数,用这个平均数替代像素 A 的值。重复以上操作直到将图像的每一个像素值都更新一边

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

img = cv2.imread('hair.jpg')

kernel = np.ones((5,5),np.float32)/25
dst = cv2.filter2D(img,-1,kernel)


# 显示图像
plt.figure(figsize = (15, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging'),plt.xticks([]), plt.yticks([])
plt.show()

opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))_第2张图片

三、图像平滑(模糊)

  • 使用低通滤波器可以达到图像模糊的目的

  • 去除噪音。其实就是去除图像中的高频成分(比如:噪音,边界)。所以边界也会被模糊一点。也有一些模糊技术不会模糊掉边界。

  • 平滑(模糊)和滤波的区别: 它们都属于卷积,不同滤波方法之间只是卷积核不同(对线性滤波而言)

四、图像滤波

图像滤波既可以在实域进行,也可以在频域进行。图像滤波可以更改或者增强图像。通过滤波,可以强调一些特征或者去除图像中一些不需要的部分。滤波是一个邻域操作算子,利用给定像素周围的像素的值决定此像素的最终的输出值。图像滤波可以通过公式:

其中K为滤波器,在很多文献中也称之为核(kernel)。常见的应用包括去噪、图像增强、检测边缘、检测角点、模板匹配等

OpenCV 提供五种常见的图像滤波方式:线性滤波(方框滤波、均值滤波、高斯滤波);非线性滤波(中值滤波、双边滤波)

(1)方框滤波

  • 类似于均值滤波,如3x3的kernel为:

  • 用 cv2.boxFilter() 函数实现,当可选参数 normalize 为 True 的时候,方框滤波就是均值滤波,上式中的a就等于1/9;normalize 为 False 的时候,a=1,相当于求区域内的像素和。

  • 相关函数:cv2.boxFilter()

import cv2
import random
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('tower.jpg')

# 前面的均值滤波也可以用方框滤波实现:normalize=True
boxFilter = cv2.boxFilter(img, -1, (3, 3), normalize=True)

plt.figure(figsize = (10, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(boxFilter),plt.title('boxFilter'),plt.xticks([]), plt.yticks([])
plt.show()

opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))_第3张图片

(2)均值滤波

  • 这是由一个归一化卷积框完成的。用卷积框覆盖区域所有像素的平均值来代替中心元素
  • 均值滤波是一种最简单的滤波处理,它取的是卷积核区域内元素的均值,用 cv2.blur() 实现,如3×3的卷积核:
  • 相关函数:cv2.blur()
    opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))_第4张图片
import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('tower.jpg')
blur = cv2.blur(img,(5,5))

plt.figure(figsize = (10, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred'),plt.xticks([]), plt.yticks([])
plt.show()

opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))_第5张图片

(3)中值滤波

  • 中值又叫中位数,是所有数排序后取中间的值。顾名思义就是用与卷积框对应像素的中值来替代中心像素的值。

  • 中值滤波器经常用来去除椒盐噪声。前面的滤波器都是用计算得到的一个新值来取代中心像素的值,而中值滤波是用中心像素周围(也可以使他本身)的值来取代他。他能有效的去除噪声。卷积核的大小也应该是一个奇数。

  • 所以那种孤立的斑点,如0或255很容易消除掉,适用于去除椒盐噪声和斑点噪声。中值是一种非线性操作,效率相比前面几种线性滤波要慢

在这个例子中,我们给原始图像加上噪声,然后再使用中值滤波去除噪声。

def sp_noise(image,prob):

    '''
    添加椒盐噪声
    prob:噪声比例
    '''

    output = np.zeros(image.shape,np.uint8)
    thres = 1 - prob

    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            rdn = random.random()
            if rdn < prob:
                output[i][j] = 0
            elif rdn > thres:
                output[i][j] = 255
            else:
                output[i][j] = image[i][j]

    return output
import cv2
import random
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('tower.jpg')

# 添加椒盐噪声,噪声比例为 0.02
noise_img = sp_noise(img, prob=0.02)

# 中值滤波
medianBlur = cv2.medianBlur(noise_img,5)

plt.figure(figsize = (15, 10))
plt.subplot(131),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(noise_img),plt.title('Noise'),plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(medianBlur),plt.title('medianBlur'),plt.xticks([]), plt.yticks([])
plt.show()

opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))_第6张图片

(4)高斯滤波

  • 现在把卷积核换成高斯核(简单来说,方框不变,将原来每个方框的值是相等的,现在里面的值是符合高斯分布的,方框中心的值最大,其余方框根据距离中心元素的距离递减,构成一个高斯小山包。原来的求平均数现在变成求加权平均数,权就是方框里的值)。

  • 不同于均值滤波,高斯滤波的卷积核权重并不相同:中间像素点权重最高,越远离中心的像素权重越小,类似于正态分布

  • 实现的函数是 cv2.GaussianBlur()。我们需要指定高斯核的宽和高(必须是奇数)。以及高斯函数沿 X,Y 方向的标准差。如果我们只指定了 X 方向的的标准差,Y 方向也会取相同值。如果两个标准差都是 0,那么函数会根据核函数的大小自己计算。高斯滤波可以有效的从图像中去除高斯噪音。

  • 如果你愿意的话,你也可以使用函数 cv2.getGaussianKernel() 自己构建一个高斯核。

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

img = cv2.imread('tower.jpg')

# 0 是指根据窗口大小(5,5)来计算高斯函数标准差
GaussianBlur = cv2.GaussianBlur(img,(5,5),0)

plt.figure(figsize = (10, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(GaussianBlur),plt.title('GaussianBlur'),plt.xticks([]), plt.yticks([])
plt.show()

opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))_第7张图片

(5)双边滤波

模糊操作基本都会损失掉图像细节信息,使用线性滤波器,图像的边缘信息很难保留下来。边缘(edge)信息作为图像中很重要的一个特征,需要被保留,所以这才有了双边滤波。

  • 函数 cv2.bilateralFilter() 能在保持边界清晰的情况下有效的去除噪音。 但是这种操作与其他滤波器相比会比较慢。

  • 我们已经知道高斯滤波器是求中心点邻近区域像素的高斯加权平均值。这种高斯滤波器只考虑像素之间的空间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会别模糊掉,而这正不是我们想要。

  • 双边滤波同时使用空间高斯权重和灰度值相似性高斯权重

    • 空间高斯函数确保只有邻近区域的像素对中心点有影响
    • 灰度值相似性高斯函数确保只有与中心像素灰度值相近的才会被用来做模糊运算。

    所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大

import cv2
import random
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('Bimodal.jpg')

# 双边滤波
#9 邻域直径,两个 75 分别是空间高斯函数标准差,灰度值相似性高斯函数标准差
bilateralFilter = cv2.bilateralFilter(img,9,75,75)

plt.figure(figsize = (15, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(bilateralFilter),plt.title('bilateralFilter'),plt.xticks([]), plt.yticks([])
plt.show()

opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波))_第8张图片

参考

http://www.cnblogs.com/wy1996/p/10858376.html

https://zhuanlan.zhihu.com/p/60770435?utm_source=wechat_session&utm_medium=social&utm_oi=825629365701332992

https://blog.csdn.net/jiang_ming_/article/details/82594261

你可能感兴趣的:(opencv-python:14_图像平滑(模糊)与 常见图像滤波(低通与高通滤波、图像卷积cv.filter2D()、线性滤波(方框滤波、均值滤波、高斯滤波)、非线性滤波(中值滤波、双边滤波)))