本教程将学习如下内容:
- 学习使用各种低通滤波器模糊图像
- 学习对图像应用定制滤镜(二维卷积)
二维卷积(图像滤波)
对于一维信号,图像也可以用各种低通滤波器(LPF)、高通滤波器(HPF)等进行滤波。
LPF有助于去除噪声或模糊图像。HPF滤镜有助于在图像中找到边缘。
OpenCV提供了一个函数cv2.filter2D()
,用于将内核与图像进行卷积。
作为一个例子,我们将在图像上尝试一个平均滤波器。5x5平均滤波器核可以定义如下:
$$\begin{aligned} K = \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{bmatrix} \end{aligned}$$
使用上述内核进行滤波的结果如下:对于每个像素,一个5x5的窗口以该像素为中心, 将该窗口内的所有像素相加,将结果除以25。 这相当于计算该窗口内像素值的平均值。 对图像中的所有像素执行此操作,以产生输出滤波图像。 尝试此代码并检查结果:
import cv2
import numpy as np
from matplotlib import pyplot as plt
# img = cv2.imread('opencv_logo.png')
img = cv2.imread('/data/cvdata/opencv_logo.jpg')
kernel = np.ones((5,5),np.float32)/25
dst = cv2.filter2D(img,-1,kernel)
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主要提供四种模糊技术。
平均值
这是通过将图像与归一化框过滤器进行卷积来实现的。它只是取核区域下所有像素的平均值,并用该平均值替换中心元素。
这是通过函数cv2.blur()
或cv2.boxFilter()
完成的。
我们应该指定内核的宽度和高度。3x3标准化的框过滤器看起来像这样:
$$\begin{aligned} K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix} \end{aligned}$$
注意:
如果不想使用规范化的框过滤器,请使用cv2.boxFilter()
并将参数normalize=False
传递给函数。
使用5x5大小的内核查看下面的示例演示:
import cv2
import numpy as np
from matplotlib import pyplot as plt
# img = cv2.imread('opencv_logo.png')
img = cv2.imread('/data/cvdata/opencv_logo.jpg')
blur = cv2.blur(img,(5,5))
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()
blur = cv2.GaussianBlur(img,(5,5),0)
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()
blur = cv2.medianBlur(img,5)
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()
结果如下:
双边过滤
正如所指出的,之前提出的过滤器往往会模糊边缘。
双边滤波器cv2.bilateralFilter()
的情况并非如此,它是为定义的,在保留边缘的同时,在去除噪声方面非常有效。
但与其他过滤器相比,操作速度较慢。
我们已经看到,高斯滤波器取像素周围的a邻域,并找到其高斯加权平均值。
这种高斯滤波器仅是空间的函数,即在滤波时考虑附近的像素。 它不考虑像素的强度值是否几乎相同,也不考虑像素是否位于边缘上。 由此产生的效果是高斯滤波器倾向于模糊边缘,这是不理想的。
双边滤波器在空间域中也使用高斯滤波器,但它还使用了一个额外的(乘法)高斯滤波器分量,该分量是像素强度差的函数。 空间的高斯函数确保只考虑像素作为“空间邻居”进行滤波,而在强度域中应用的高斯分量(强度差的高斯函数), 确保只包括强度与中心像素相似的像素(“强度邻居”)来计算模糊强度值。 因此,这种方法保留了边缘,因为对于位于边缘附近的像素,放置在边缘另一侧的相邻像素(因此与中心像素相比表现出较大的强度变化)将不包括在模糊范围内。
下面的示例演示了双边过滤的使用(有关参数的详细信息,请参阅OpenCV文档)。
blur = cv2.bilateralFilter(img,9,75,75)
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()
结果如下:
请注意,表面上的纹理已消失,但边缘仍保留。
扩展阅读
- 有关双边过滤的详细信息,请访问此处。
练习
- 拍摄一张图像,添加高斯噪声和椒盐噪声,比较在更改噪声水平时, 通过方框、高斯、中值和双边滤波器对两幅噪声图像的模糊效果。