使用Python,OpenCV进行平滑和模糊

这篇博客将介绍如何使用OpenCV对图片进行平滑和模糊操作。
具体包括:

  • 简单平均模糊(cv2.blur)
  • 加权高斯模糊(cv2.GaussianBlur)
  • 中值滤波(cv2.medianBlur)
  • 双边滤波(cv2.bilateralFilter)

平滑和模糊是计算机视觉和图像处理中最常见的预处理步骤之一。

模糊是当相机拍摄的照片失去焦点时发生的事情。图像中更清晰的区域会丢失其细节。模糊意味着图像中的每个像素与其周围的像素强度混合。邻居中的一个“混合”像素成为模糊像素。

平滑能够减少高频内容,帮助忽略图像中较小的细节,而留下更多图像结果的内容。首先对图像平滑或模糊后,会使得阈值化、边缘检测能取得更好的效果。

1. 效果图

简单均值模糊——原始图 VS 3 * 3 VS 9 * 9 VS 15 * 15 效果图如下:

M * N(均为奇数)的内核取平均值作为中心像素的值,可以看到随着内核的增加,图像越来越模糊~
在这里插入图片描述高斯模糊——原始图 VS 3 * 3 VS 9 * 9 VS 15 * 15 效果图如下:

M*N(均为奇数)的内核,不是简单的取平均值,而是取加权平均值。可以看到随着内核的增大,图像也会变得模糊,但能保存更多的图像边缘。
在这里插入图片描述
中值模糊——原始图 VS 3 * 3 VS 9 * 9 VS 15 * 15 效果图如下:

M * M(奇数,正方形)的内核,不取均值,也不取加权平均值,而是取邻域像素的中位数值,可以看到中值模糊不像高斯平滑那样的“自然模糊”,丢失了更多的细节和噪声。
在这里插入图片描述
模糊方法的目的是减少图像中的噪声和细节;然而,缺点是往往会失去图像的边缘。为了在保持边缘的同时减少噪声,可以使用双边模糊。双边模糊通过引入两个高斯分布来实现。

双边模糊——原始图 VS sc=21 VS sc=41 VS sc=61 效果图如下:
可以看到既模糊了图像,又极大的保持了边缘。在这里插入图片描述

2. 原理

2.1 依赖库及安装

pip install opencv-contrib-python

opencv安装可参考

2.2 简单平均模糊

平均值过滤器:采用M* N(均为奇数)的标准化滤波器对图像进行卷积,取一个中心像素周围的像素区域,将所有这些像素平均在一起,并用平均值替换中心像素。

对于输入图像中的每个像素,这个内核将从左到右,从上到下滑动。要计算内核中心的像素(必须使用奇数,否则就不会有真正的“中心”)被设置为它周围所有其他像素的平均值。

  • 随着内核大小的增加,图像的模糊程度也会随之增加。简单地说:平滑内核越大,图像看起来就越模糊。 这很容易导致图像中对象的重要结构边缘的丢失。
  • 虽然平均平滑很容易理解,但它也会平均加权核心区域内的每个像素,这样做很容易使图像过度模糊,错过重要的边缘。可以通过应用高斯模糊来解决这个问题。

2.3 高斯模糊

高斯模糊类似于平均模糊,但使用的不是简单的平均值,而是加权平均值,即更接近中心像素的邻域像素对平均值贡献更多的“权重”。

  • 高斯平滑用于去除近似服从高斯分布的噪声。M * N(均为奇数)的内核,取加权平均值,使得能够保持图像中更多的边缘,看起来更“自然模糊。”

-当内核的大小增加时,应用于输出图像的模糊量也会增加。但是,模糊看起来更“自然”,比简单的平均平滑更能保留图像中的边缘。

2.4 中值模糊

**中值模糊方法在去除椒盐噪声时是最有效的。**想象一下拍照,把它放在你的餐桌上,然后在上面撒盐和胡椒。使用中值模糊方法,可以从图像中去除椒盐。

  • M * M(均为奇数,正方形的内核),在均值模糊、高斯模糊中,核大小可以是矩形的,而中值模糊的核大小必须是方形的。不同于取平均值,而是用邻域的中值代替中心像素。
  • 中值模糊在去除图像中的椒盐噪声方面更有效的原因是,每个中心像素总是被存在于图像中的像素强度所取代。由于中位数对异常值具有鲁棒性,因此椒盐噪声对中位数的影响将小于另一种统计方法,如平均值。
  • 平均和高斯等方法计算邻域的平均值或加权平均值-该平均像素强度可能存在于邻域中,也可能不存在于邻域中。但根据定义,中间像素必须存在于邻域中。
  • 通过将中心像素替换为中值而不是平均值,可以大大降低噪声。但也会丢失更多的细节。

2.5 双边滤波

双边滤波能很好的弥补尚需三种模糊方法的缺陷,能显著平滑图像的细节和纹理,同时仍然保留边界和边缘。
是通过俩个高斯核实现的。

  • diameter:定义像素邻域的直径——直径越大,模糊计算中包含的像素就越多,是一个正方形的内核大小。
  • sigmaColor: 颜色标准差——值越大,表示在计算模糊度时,将考虑邻域中的更多颜色。足够大——则只有颜色相似的像素才会对模糊产生显著影响。
  • sigmaSpace: 空间标准差——值越大意味着远离中心像素直径的像素将影响模糊计算。
    blurred = cv2.bilateralFilter(image, diameter, sigmaColor, sigmaSpace)

3. 源代码

# USAGE
# python blurring.py --image images/flower.jpg
# 对图像执行简单平均模糊、高斯模糊、中值模糊;

# 导入必要的包
import argparse

import cv2
import imutils

# 构建命令行参数及解析
# --image 要执行平滑和模糊操作的图像路径
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", type=str, default="adrian.png",
                help="path to input image")
args = vars(ap.parse_args())

# 加载图像,展示它,初始化一个内核list,因此可以评估不同内核大小对模糊的影响
image = cv2.imread(args["image"])
image = imutils.resize(image, width=300)
cv2.imshow("Original", image)
kernelSizes = [(3, 3), (9, 9), (15, 15)]

# 遍历内核
# 可以看到图像随着内核大小的增加而变得模糊。内核越大,图像就会越模糊。
for (kX, kY) in kernelSizes:
    # 应用当前内核执行简单平均模糊
    # 图像,高斯内核
    blurred = cv2.blur(image, (kX, kY))
    cv2.imshow("Average ({}, {})".format(kX, kY), blurred)
    cv2.waitKey(0)

# 关闭所有窗口,清理屏幕
cv2.destroyAllWindows()
cv2.imshow("Original", image)

# 遍历内核
for (kX, kY) in kernelSizes:
    # 对图像应用高斯平滑
    # 图像,高斯内核,sigma(标准偏差,0表示根据内核自动计算)
    blurred = cv2.GaussianBlur(image, (kX, kY), 0)
    cv2.imshow("Gaussian ({}, {})".format(kX, kY), blurred)
    cv2.waitKey(0)

# 关闭所有窗口,清理屏幕
cv2.destroyAllWindows()
cv2.imshow("Original", image)

# 遍历内核
for k in (3, 9, 15):
    # 应用中值模糊
    # 图像,内核
    blurred = cv2.medianBlur(image, k)
    cv2.imshow("Median {}".format(k), blurred)
    cv2.waitKey(0)

# 关闭所有窗口,清理屏幕
cv2.destroyAllWindows()
cv2.imshow("Original", image)
params = [(11, 21, 7), (11, 41, 21), (11, 61, 39)]

# 遍历双边滤波器的直径、颜色标准差、空间标准差
# diameter:定义像素邻域的直径——直径越大,模糊计算中包含的像素就越多,是一个正方形的内核大小。
# sigmaColor: 颜色标准差——值越大,表示在计算模糊度时,将考虑邻域中的更多颜色。足够大——则只有颜色相似的像素才会对模糊产生显著影响。
# sigmaSpace: 空间标准差——值越大意味着远离中心像素直径的像素将影响模糊计算。
for (diameter, sigmaColor, sigmaSpace) in params:
    # 应用当前设置参数执行双边滤波
    blurred = cv2.bilateralFilter(image, diameter, sigmaColor, sigmaSpace)

    # 展示输出图像及关联参数
    title = "Blurred d={}, sc={}, ss={}".format(
        diameter, sigmaColor, sigmaSpace)
    cv2.imshow(title, blurred)
    cv2.waitKey(0)

cv2.destroyAllWindows()

参考

猜你喜欢

转载自blog.csdn.net/qq_40985985/article/details/117391998
今日推荐