目标
学习:
- 用各种低通滤波器模糊图像
- 在图像上应用定制的滤波器(二维卷积)
二维卷积 ( 图像滤波 )
与一维信号一样,图像也可以用各种低通滤波器(LPF)、高通滤波器(HPF)等进行过滤。LPF有助于去除噪音、模糊图像等。HPF滤波器有助于寻找图像的边缘。
OpenCV提供了一个函数cv.filter2D()来将一个内核与图像进行融合。作为一个例子,我们将在一个图像上尝试一个平均滤波器。一个5x5的平均滤波核看起来就像下面这样:
K
=
1
25
[
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
]
K=\frac{1}{25}\left[ \begin{matrix} 1& 1& 1& \begin{matrix} 1& 1\\ \end{matrix}\\ 1& 1& 1& \begin{matrix} 1& 1\\ \end{matrix}\\ 1& 1& 1& \begin{matrix} 1& 1\\ \end{matrix}\\ \begin{array}{c} 1\\ 1\\ \end{array}& \begin{array}{c} 1\\ 1\\ \end{array}& \begin{array}{c} 1\\ 1\\ \end{array}& \begin{array}{c} \begin{matrix} 1& 1\\ \end{matrix}\\ \begin{matrix} 1& 1\\ \end{matrix}\\ \end{array}\\ \end{matrix} \right]
K=251
1111111111111111111111111
这个操作是这样的:在一个像素上面保持这个核,把这个核下面的所有25个像素加起来,取平均值,然后用新的平均值替换中心像素。这个操作对图像中的所有像素都是持续的。试试这段代码并检查结果:
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('opencv_logo.png')
kernel = np.ones((5,5),np.float32)/25
dst = cv.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提供了四种主要类型的模糊技术。
1. 平均滤波
这是通过用一个归一化的盒式滤波器对图像进行卷积来完成的。它只是取核区下所有像素的平均值,并替换中心元素。这是由函数cv.blur()或cv.boxFilter()完成的。查看文档以了解关于内核的更多细节。我们应该指定内核的宽度和高度。一个3x3的归一化盒式滤波器看起来就像下面这样:
K
=
1
9
[
1
1
1
1
1
1
1
1
1
]
K=\frac{1}{9}\left[ \begin{matrix} 1& 1& 1\\ 1& 1& 1\\ 1& 1& 1\\ \end{matrix} \right]
K=91
111111111
注意 如果你不想使用规范化的盒子过滤器,请使用cv.boxFilter()。向该函数传递一个参数normalize=False。
请看下面的样本演示,内核大小为5x5:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('opencv-logo-white.png')
blur = cv.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()
结果:
2. 高斯模糊法/高斯滤波
在这个方法中,使用了高斯核而不是箱形滤波器。它是通过函数cv.GaussianBlur()完成的。我们应该指定核的宽度和高度,应该是正数和奇数。我们还应该指定X和Y方向的标准偏差,分别为sigmaX和sigmaY。如果只指定sigmaX,sigmaY将被视为与sigmaX相同。如果两者都是零,则根据核大小计算。高斯模糊对去除图像中的高斯噪声非常有效。
如果你愿意,你可以用函数cv.getGaussianKernel()创建一个高斯核。
下面的代码可以为高斯模糊进行修改:
blur = cv.GaussianBlur(img,(5,5),0)
结果:
3.中值滤波
在这里,函数cv.medianBlur()取核区下所有像素的中值,中心元素被替换成这个中值。这对图像中的盐和胡椒的噪声非常有效。有趣的是,在上述过滤器中,中心元素是一个新的计算值,可能是图像中的一个像素值或一个新值。但在中值模糊中,中心元素总是被图像中的某个像素值所取代。它能有效地减少噪音。它的内核大小应该是一个正奇数的整数。
在这个演示中,我给我们的原始图像添加了50%的噪声,并应用中值模糊。检查结果:
median = cv.medianBlur(img,5)
结果:
4. 双边滤波
cv.bilateralFilter()在去除噪声的同时保持边缘的清晰度方面非常有效。但与其他过滤器相比,其操作速度较慢。我们已经看到,高斯滤波器取像素周围的邻域并找到其高斯加权平均值。这个高斯滤波器是一个单独的空间函数,也就是说,在过滤时考虑附近的像素。它不考虑像素是否有几乎相同的强度。它不考虑一个像素是否是一个边缘像素。因此,它也模糊了边缘,这是我们不希望看到的。
双边滤波也需要一个空间的高斯滤波,但多了一个高斯滤波,这是一个像素差异的函数。空间的高斯函数确保只有附近的像素被考虑进行模糊处理,而强度差的高斯函数则确保只有那些与中心像素强度相似的像素被考虑进行模糊处理。所以它保留了边缘,因为边缘的像素会有很大的强度变化。
下面的例子显示了双边滤波器的使用(关于参数的细节,请访问文档):
blur = cv.bilateralFilter(img,9,75,75)
结果:
看,表面的纹理已经消失了,但边缘仍然保存着。
其他资源
关于双边滤波的细节