OpenCV竟然可以这样学!成神之路终将不远

Posted 满目星辰wwq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV竟然可以这样学!成神之路终将不远相关的知识,希望对你有一定的参考价值。

12 图像平滑

12.1 目标

  • 学会: - 使用各种低通滤镜模糊图像 - 将定制的滤镜应用于图像(2D卷积)

12.2 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}

以下是cv.filter2D函数原型以及具体参数:

dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
参数描述
src原图像,也就是输入图像矩阵
ddepth目标图像的所需深度,默认与输入图像一致
kernel卷积核(或相当于相关核),需要事先声明卷积核函数,单通道浮点矩阵;如果要将不同的内核应用于不同的通道,请使用拆分将图像拆分为单独的颜色平面,然后单独处理它们。
dst目标图像,与原图像尺寸和通过数相同
anchor卷积内核的锚点,指示内核中过滤点的相对位置;锚应位于内核中;默认值为(-1,-1)表示锚位于内核中心。
detal在将它们存储在dst中之前,将可选值添加到已过滤的像素中。类似于偏置。
borderType卷积到图像边界如何填充像素方法,就是像素外推法,参见BorderTypes

操作如下:保持这个内核在一个像素上,将所有低于这个内核的25个像素相加,取其平均值,然后用新的平均值替换中心像素。它将对图像中的所有像素继续此操作。试试这个代码,并检查结果:

import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

img = plt.imread('001.jpg')
kernel = np.ones((5, 5), np.float32) / 25  # 核函数归一化
dst = cv.filter2D(img, -1, kernel)
plt.subplot(121), plt.imshow(img, 'gray'), plt.title('Original Image')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(dst, 'gray'), plt.title('Convolution Image')
plt.xticks([]), plt.yticks([])
plt.show()

运行结果如下:

12.3 图像模糊(图像平滑)

通过将图像与低通滤波器内核进行卷积来实现图像模糊。这对于消除噪音很有用。它实际上从图像中消除了高频部分(例如噪声,边缘)。因此,在此操作中边缘有些模糊。(有一些模糊技术也可以不模糊边缘)。OpenCV主要提供四种类型的模糊技术。

12.3.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 传递给函数。

以下是cv.blur()函数的说明以及参数设置:

cv.blur(src, ksize, dst=None, anchor=None, borderType=None):
参数描述
src原图像,也就是输入图像矩阵
ksize卷积核大小,无需filter2D设置kernel的全部参数,只需设置卷积核大小;

查看下面的示例演示,其内核大小为3x3:

import cv2 as cv
from matplotlib import pyplot as plt

img = plt.imread('001.jpg')
blur = cv.blur(img, (3, 3))  # 均值滤波
box_filter = cv.boxFilter(img, 0, (3, 3))

plt.subplot(131), plt.imshow(img), plt.title('Original Image')
plt.xticks([]), plt.yticks([])

plt.subplot(132), plt.imshow(blur), plt.title('Blurred Image')
plt.xticks([]), plt.yticks([])

plt.subplot(133), plt.imshow(box_filter), plt.title('Box Filter Image')
plt.xticks([]), plt.yticks([])

plt.show()

运行结果如下:

12.3.2 高斯滤波

在这种情况下,代替盒式滤波器,使用了高斯核。这是通过功能cv.GaussianBlur()完成的。我们应指定内核的宽度和高度,该宽度和高度应为正数和奇数。我们还应指定X和Y方向的标准偏差,分别为sigmaX和sigmaY。如果仅指定sigmaX,则sigmaY将与sigmaX相同。如果两个都为零,则根据内核大小进行计算。高斯模糊对于从图像中去除高斯噪声非常有效。

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

以下是高斯滤波函数以及参数说明:

cv.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None):
参数描述
src输入图像

ksize

高斯核大小

sigmaX

高斯核标准派生方差
sigmaY 默认设置为0,将会设置与sigmaX一致;如果sigmaX与sigmaY都为0,那么将会通过计算ksize.width与ksize.height来输出sigmaX与sigmaY大小;

borderType

卷积在图像边缘的填充方式

可以修改以上代码以实现高斯模糊:

import cv2 as cv
from matplotlib import pyplot as plt

img = plt.imread('001.jpg')
kernel = (3, 3)
blur = cv.blur(img, kernel)  # 均值滤波
box_filter = cv.boxFilter(img, 0, kernel)
gauss_blur = cv.GaussianBlur(img, kernel, 0)

images = [img, blur, box_filter, gauss_blur]
titles = ['Original Image', 'Blurred Image', 'Box Filter Image',
          'Gaussian Blurred Image']

for i in range(2):
    plt.subplot(2, 2, 2 * i + 1)
    plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])

    plt.subplot(2, 2, 2 * i + 2)
    plt.imshow(images[i + 1], 'gray')
    plt.title(titles[i + 1])
    plt.xticks([]), plt.yticks([])

plt.show()

运行结果如下:

12.3.3 中值滤波

在这里,函数cv.medianBlur()提取内核区域下所有像素的中值,并将中心元素替换为该中值。这对于消除图像中的椒盐噪声非常有效。有趣的是,在上述过滤器中,中心元素是新计算的值,该值可以是图像中的像素值或新值。但是在中值模糊中,中心元素总是被图像中的某些像素值代替。有效降低噪音。其内核大小应为正奇数整数。

以下是cv.medianBlur()函数原型以及具体参数:

median = cv.medianBlur(src, ksize, dst=None):
参数描述
src输入图像

ksize

滤波核大小

dst

输出图像,与原图像尺寸和通过数相同

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

import cv2 as cv
from matplotlib import pyplot as plt

img = plt.imread('001.jpg')
kernel = (3, 3)
blur = cv.blur(img, kernel)  # 均值滤波
box_filter = cv.boxFilter(img, 0, kernel)
gauss_blur = cv.GaussianBlur(img, kernel, 0)
median = cv.medianBlur(img, 5)

images = [img, blur, box_filter, gauss_blur, median, img]
titles = ['Original Image', 'Blurred Image', 'Box Filter Image',
          'Gaussian Blurred Image', 'Median Image', 'Original Image']

for i in range(2):
    plt.subplot(2, 3, i * 3 + 1)
    plt.imshow(images[i * 3], 'gray')
    plt.title(titles[i * 3])
    plt.xticks([]), plt.yticks([])

    plt.subplot(2, 3, i * 3 + 2)
    plt.imshow(images[i * 3 + 1], 'gray')
    plt.title(titles[i * 3 + 1])
    plt.xticks([]), plt.yticks([])

    plt.subplot(2, 3, i * 3 + 3)
    plt.imshow(images[i * 3 + 2], 'gray')
    plt.title(titles[i * 3 + 2])
    plt.xticks([]), plt.yticks([])

plt.show()

运行结果如下:

12.3.4 双边滤波

cv.bilateralFilter() 在去除噪声的同时保持边缘清晰锐利非常有效。但是,与其他过滤器相比,该操作速度较慢。我们已经看到,高斯滤波器采用像素周围的邻域并找到其高斯加权平均值。高斯滤波器仅是空间的函数,也就是说,滤波时会考虑附近的像素。它不考虑像素是否具有几乎相同的强度。它不考虑像素是否是边缘像素。因此它也模糊了边缘,这是我们不想做的。

双边滤波器在空间中也采用高斯滤波器,但是又有一个高斯滤波器,它是像素差的函数。空间的高斯函数确保仅考虑附近像素的模糊,而强度差的高斯函数确保仅考虑强度与中心像素相似的那些像素的模糊。由于边缘的像素强度变化较大,因此可以保留边缘。

以下示例显示了使用双边过滤器(有关参数的详细信息,请访问docs)。

cv.bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)

其中:

参数描述
src输入图像

d

滤波核函数的邻域直径,如果是负数,则根据sigmaSpace来计算得出;

sigmaColor

滤波色彩空间的sigma参数(值域)
sigmaSpace坐标空间的sigma参数(空域)

dst

输出图像
borderType

图像卷积边界填充方式

12.4 其他资源

有关双边过滤的详细信息都在这里
 

 


欢迎评论区留言,一起探讨OpenCV成神之路的奥秘。

顺便给我加个关注,点个赞,加个收藏,让我们一起登上神坛。

以上是关于OpenCV竟然可以这样学!成神之路终将不远的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV竟然可以这样学!成神之路终将不远(十四)

OpenCV竟然可以这样学!成神之路终将不远(二十)

OpenCV竟然可以这样学!成神之路终将不远(三十四)

OpenCV竟然可以这样学!成神之路终将不远(三十四)

OpenCV竟然可以这样学!成神之路终将不远

OpenCV竟然可以这样学!成神之路终将不远