这篇博客将介绍如何使用OpenCV对图片进行平滑和模糊操作。
具体包括:
平滑和模糊是计算机视觉和图像处理中最常见的预处理步骤之一。
模糊是当相机拍摄的照片失去焦点时发生的事情。图像中更清晰的区域会丢失其细节。模糊意味着图像中的每个像素与其周围的像素强度混合。邻居中的一个“混合”像素成为模糊像素。
平滑能够减少高频内容,帮助忽略图像中较小的细节,而留下更多图像结果的内容。首先对图像平滑或模糊后,会使得阈值化、边缘检测能取得更好的效果。
简单均值模糊——原始图 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 效果图如下:
可以看到既模糊了图像,又极大的保持了边缘。
pip install opencv-contrib-python
opencv安装可参考
平均值过滤器:采用M* N(均为奇数)的标准化滤波器对图像进行卷积,取一个中心像素周围的像素区域,将所有这些像素平均在一起,并用平均值替换中心像素。
对于输入图像中的每个像素,这个内核将从左到右,从上到下滑动。要计算内核中心的像素(必须使用奇数,否则就不会有真正的“中心”)被设置为它周围所有其他像素的平均值。
高斯模糊类似于平均模糊,但使用的不是简单的平均值,而是加权平均值,即更接近中心像素的邻域像素对平均值贡献更多的“权重”。
-当内核的大小增加时,应用于输出图像的模糊量也会增加。但是,模糊看起来更“自然”,比简单的平均平滑更能保留图像中的边缘。
**中值模糊方法在去除椒盐噪声时是最有效的。**想象一下拍照,把它放在你的餐桌上,然后在上面撒盐和胡椒。使用中值模糊方法,可以从图像中去除椒盐。
双边滤波能很好的弥补尚需三种模糊方法的缺陷,能显著平滑图像的细节和纹理,同时仍然保留边界和边缘。
是通过俩个高斯核实现的。
- diameter:定义像素邻域的直径——直径越大,模糊计算中包含的像素就越多,是一个正方形的内核大小。
- sigmaColor: 颜色标准差——值越大,表示在计算模糊度时,将考虑邻域中的更多颜色。足够大——则只有颜色相似的像素才会对模糊产生显著影响。
- sigmaSpace: 空间标准差——值越大意味着远离中心像素直径的像素将影响模糊计算。
blurred = cv2.bilateralFilter(image, diameter, sigmaColor, sigmaSpace)
# 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()