OpenCV系列(一)之图像平滑

目标

  1. 使用各种低通滤镜模糊图像
  2. 将定制的滤镜应用于图像(2D卷积)

接下来,就简单介绍一下这俩种常用的滤镜技术。

图像模糊(图像平滑)

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

  1. 平均
    这是通过将图像与归一化框滤镜进行卷积来完成的。它仅获取内核区域下所有像素的平均值,并替换中心元素。这是通过功能cv.blur()或cv.boxFilter()完成的。检查文档以获取有关内核的更多详细信息。我们应该指定内核的宽度和高度。3x3归一化框式过滤器如下所示:
    在这里插入图片描述
    如下所示,其内核大小是5X5:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 1:平均
def imgJZ():
     img = cv.imread('E:\Opencv\Demo\IMG\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()
if __name__ == '__main__':
        imgJZ()

执行看一下效果,明细出现了滤镜效果,如下图所示:
均值测试
注意:如果您不想使用标准化的框式过滤器,请使用cv.boxFilter()。将参数normalize = False传递给函数。

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

如果需要,可以使用函数cv.getGaussianKernel() 创建高斯内核。
可以修改以上代码以实现高斯模糊:

blur = cv.GaussianBlur(img,(5,5),0)

完整代码如下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#高斯滤波器
def imgGaussianBlur():
    img = cv.imread('E:\Opencv\Demo\IMG\opencv-logo-white.png')
    blur = cv.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()

if __name__ == '__main__':
        imgGaussianBlur()

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

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

medianBlur = cv.medianBlur(img,5)

完整代码如下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# 中位模糊
def imgMedianBlur():
    img = cv.imread('E:\Opencv\Demo\IMG\opencv.png')
    median =cv.medianBlur(img,5)
    plt.subplot(121)
    plt.imshow(img)
    plt.title('Original')
    plt.xticks([])
    plt.yticks([])
    plt.subplot(122)
    plt.imshow(median)
    plt.title('Blurred')
    plt.xticks([])
    plt.yticks([])
    plt.show()

if __name__ == '__main__':
      imgMedianBlur()

好了,运行一下,看一下效果图:
中位模糊

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

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

原理分析:

双边滤波与高斯滤波器相比,对于图像的边缘信息能过更好的保存。其原理为一个与空间距离相关的高斯函数与一个灰度距离相关的高斯函数相乘:

  • 空间距离
    指的是当前点与中心点的欧式距离。空间域高斯函数其数学形式为:
    在这里插入图片描述

  • 灰度距离
    指的是当前点灰度与中心点灰度的差的绝对值。值域高斯函数其数学形式为:
    在这里插入图片描述
    其中gray(xi,yi)为当前点灰度值,gray(xc,yc)为中心点灰度值,sigma为值域标准差。

对于高斯滤波,仅用空间距离的权值系数核与图像卷积后,确定中心点的灰度值。即认为离中心点越近的点,其权重系数越大。

双边滤波中加入了对灰度信息的权重,即在邻域内,灰度值越接近中心点灰度值的点的权重更大,灰度值相差大的点权重越小。此权重大小,则由值域高斯函数确定。

两者权重系数相乘,得到最终的卷积模板。由于双边滤波需要每个中心点邻域的灰度信息来确定其系数,所以其速度与比一般的滤波慢很多,而且计算量增长速度为核大小的平方。
在这里插入图片描述
在这里插入图片描述

参数选择:

  • 空间域sigma选取:
    其中核大小通常为sigma的6sigma + 1。因为离中心点3sigma大小之外的系数与中点的系数只比非常小,可以认为此之外的点与中心点没有任何联系,及权重系数为0.OpenCV中默认的计算公式也是如此,OpenCV参考文档内容如下:“对应高斯参数的 Gaussian sigma (标准差). 如果为零,则标准差由下面的核尺寸计算: sigma = (n/2 - 1)*0.3 + 0.8, 其中 n=param1 对应水平核,n=param2对应垂直核.”
  • 值域sigma选取:
    另灰度差△g = abs(gray(xi,yi)- gray(xc,yc)),忽略常数的影响,因此其函数可以简化为:
    在这里插入图片描述

总结分析:

  1. Sigma越大,边缘越模糊,极限情况为simga无穷大,值域系数近似相等(忽略常数时,将近为exp(0)= 1),与高斯模板(空间域模板)相乘后可认为等效于高斯滤波。

  2. Sigma越小,边缘越清晰,极限情况为simga无限接近0,值域系数近似相等(接近exp(-∞) = 0),与高斯模板(空间域模板)相乘后,可近似为系数皆相等,等效于源图像。

了解了双边滤波与高斯滤波的区别,下面就具体看看实现效果吧:

以下示例显示了使用双边过滤器的使用方法,关于具体使用方法和参数说明,参考官方文档《双边滤波》

blur = cv.bilateralFilter(img,9,75,75)

完整代码如下:

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

# 双边滤波
def imgBilateralFilter():
    img = cv.imread('E:\Opencv\Demo\IMG\opencv.png')
    blur = cv.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()

if __name__ == '__main__':
      imgBilateralFilter()

好了,看一下效果吧:
双边滤波

2D卷积(图像过滤)

与一维信号一样,还可以使用各种低通滤波器(LPF),高通滤波器(HPF)等对图像进行滤波。LPF有助于消除噪声,使图像模糊等。HPF滤波器有助于在图像中找到边缘。

OpenCV提供了一个函数cv.filter2D来将内核与图像进行卷积。例如,我们将尝试对图像进行平均滤波。5x5平均滤波器内核如下所示:
在这里插入图片描述
操作如下:保持这个内核在一个像素上,将所有低于这个内核的25个像素相加,取其平均值,然后用新的平均值替换中心像素。它将对图像中的所有像素继续此操作。试试如下代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
#2d卷积神经网络
def img2D_Averaging():
    img = cv.imread('E:\Opencv\Demo\IMG\opencv.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()
    
if __name__ == '__main__':
      img2D_Averaging()

完成效果图如下:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/ljx1400052550/article/details/109120055