OpenCV  4.10.0
开源计算机视觉
加载中...
搜索中...
没有匹配项
平滑图像

目标

学习

  • 使用多种低通滤波器模糊图像
  • 将定制滤波器应用于图像(2D 卷积)

2D 卷积(图像滤波)

和一维信号中一样,图像可以用多种低通滤波器 (LPF)、高通滤波器 (HPF) 等滤波。LPF 用于去除噪声、模糊图像等。HPF 用于查找图像中的边缘。

OpenCV 提供了一个函数 cv.filter2D() 来用内核与图像卷积。例如,我们将在图像上尝试一个平均滤波器。5x5 平均滤波器内核如下所示

\[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}\]

此操作的运作方式如下:将此内核保持在像素上方,将此内核下方所有 25 个像素相加,取平均值,然后用新的平均值替换中央像素。此操作将继续对图像中的所有像素进行。试用此代码并检查结果

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('opencv_logo.png')
assert img is not None, "file could not be read, check with os.path.exists()"
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()
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR)
从文件中加载图像。
void filter2D(InputArray src, OutputArray dst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT)
用内核对图像进行卷积。

结果

图像

图像模糊(图像平滑)

通过图像与低通滤波器内核进行卷积,可以实现图像模糊。此方法有助于去除噪点。它实际上是去除了图像中的高频内容(例如:噪点、边缘)。因此,此操作会稍微模糊边缘(还有一些不会模糊边缘的模糊技术)。OpenCV 提供四种主要类型模糊技术。

1. 均值滤波

通过将图像与归一化框滤波器进行卷积来完成此操作。它只是取内核区域下所有像素的平均值并替换中心元素。此操作通过函数 cv.blur()cv.boxFilter() 完成。查看文档了解有关内核的更多详细信息。我们应该指定内核的宽度和高度。3x3 归一化框滤波器将如下所示

\[K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}\]

注意
如果你不希望使用归一化框滤波器,可以使用 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')
assert img is not None, "file could not be read, check with os.path.exists()"
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()
void blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT)
使用归一化框滤波器模糊图像。

结果

图像

2. 高斯模糊

在此方法中,使用高斯内核,而不是框滤波器。此操作通过函数 cv.GaussianBlur() 完成。我们应该指定内核的宽度和高度,它们必须是正奇数。我们还应该分别指定 X 和 Y 方向的标准差 sigmaX 和 sigmaY。如果仅指定了 sigmaX,则 sigmaY 的值将取与 sigmaX 相同的值。如果两者都给定为零,则它们将根据内核大小计算。高斯模糊在从图像中去除高斯噪点方面非常有效。

如果你希望,可以使用函数 cv.getGaussianKernel() 创建高斯内核。

可修改上面代码以进行高斯模糊

blur = cv.GaussianBlur(img,(5,5),0)
void GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT)
使用高斯滤波器对图像进行模糊处理。

结果

图像

3. 中值模糊

这里,函数cv.medianBlur()获取内核区域下所有像素的中值,并用此中值替换中心元素。这对于消除图像中的盐噪声非常有效。有趣的是,在上述滤波器中,中心元素是新计算的值,它可能是图像中的像素值或新值。但在中值模糊中,中心元素始终由图像中的某个像素值替换。它能有效减少噪声。其内核大小应为正奇数。

在此演示中,我在原始图像中添加了 50% 的噪声并应用了中值模糊。查看结果

median = cv.medianBlur(img,5)
void medianBlur(InputArray src, OutputArray dst, int ksize)
使用中值滤波器对图像进行模糊处理。

结果

图像

4. 双边滤波

cv.bilateralFilter()在消除噪声的同时,可以保持边缘锐利,效果非常好。但与其他滤波器相比,此操作速度较慢。我们已经看到高斯滤波器获取了像素周围的邻域并求出了它的高斯加权平均值。这个高斯滤波器仅是空间的函数,也就是说,在滤波时会考虑附近的像素。它不考虑像素是否具有几乎相同的强度。它也不考虑像素是否是一个边缘像素。所以它还会模糊边缘,这是我们不希望发生的。

双边滤波器也在空间中采用高斯滤波器,但采用另外一个高斯滤波器来表示像素差异。空间的高斯函数确保模糊处理时仅考虑附近的像素,而强度差异的高斯函数确保模糊处理时仅考虑与中心像素具有相似强度的像素。所以它保留了边缘,因为边缘处的像素会有较大的强度变化。

下面的样本展示了双边滤波器的使用(有关参数的详细信息,请访问文档)。

blur = cv.bilateralFilter(img,9,75,75)
void bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT)
将双边滤波器应用到图像上。

结果

图像

请看,表面的纹理已经消失,但边缘仍然保留。

其他资源

  1. 双边滤波详细信息

练习