OpenCV入门(十)快速学会OpenCV 9 图像平滑处理
作者:Xiou
1.图像平滑基础
在尽量保留图像原有信息的情况下,过滤掉图像内部的噪声,这一过程称为对图像的平滑处理,所得的图像称为平滑图像。例如,图7-1是含有噪声的图像,在图像内存在噪声信息,我们通常会通过图像平滑处理等方式去除这些噪声信息。
一幅图像在获取传输等过程中会受到各种各样的噪声干扰。图像噪声来自多方面,有来自系统外部的干扰,如电磁波或经电源串进系统内部而引起的外部噪声;也有来自系统内部的干扰,如摄像机的热噪声、电器的机械运动而产生的抖动噪声等。这些噪声干扰使图像退化,质量下降,表现为图像模糊、特征淹没、对图像分析不利。因此,去除噪声、恢复原始图像是图像处理中的一个重要内容。消除噪声的工作称为图像平滑。
图像平滑 (image smoothing) 是一种区域增强算法. 可以帮助我们去除早点改善图片质量。
滤波器 (Filter) 可以帮助我们来降低噪声, 均值滤波器的主要应用是去除图像中的不相关细节。
图像平滑是一种实用的数字图像处理技术。一个较好的平滑处理方法应该既能消除图像噪声,又不使图像边缘轮廓和线条变模糊,这是数字图像平滑处理要追求的目标。因为噪声源众多,噪声种类复杂,所以相应的平滑方法也多种多样。我们可以将图像平滑分为空间域图像平滑技术和频率域图像平滑技术。
空间域的图像平滑技术有邻域平均法、空间低通滤波、多图像平均、中值滤波等。
在频率域,由于噪声频谱通常在高频部分,因此可以采用各种形式的低通滤波器的方法减少噪声。
滤波的意思就是对原图像的每个像素周围一定范围内的像素进行运算,运算的范围就称为掩膜或领域。运算分为两种(如上图),如果运算只是对各像素灰度值进行简单处理(如乘一个权值)最后求和,就称为线性滤波;
如果对像素灰度值的运算比较复杂,而不是最后求和的简单运算,则是非线性滤波。例如,求一个像素周围3×3范围内的最大值、最小值、中值、均值等都不是简单的加权,都属于非线性滤波。
测试原图:
2.均值滤波
均值滤波是指用当前像素点周围N·N个像素值的均值来代替当前像素值。使用该方法遍历处理图像内的每一个像素点,即可完成整幅图像的均值滤波。
语法格式:
dst = cv2.blur( src, ksize, anchor, borderType )
● dst是返回值,表示进行均值滤波后得到的处理结果。
● src是需要处理的图像,即原始图像。它可以有任意数量的通道,并能对各个通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F或者CV_64F中的一种。
● ksize是滤波核的大小。滤波核大小是指在均值处理过程中,其邻域图像的高度和宽度。例如,其值可以为(5, 5),表示以5×5大小的邻域均值作为图像均值滤波处理的结果,如下式所示。
● anchor是锚点,其默认值是(-1, -1),表示当前计算均值的点位于核的中心点位置。该值使用默认值即可,在特殊情况下可以指定不同的点作为锚点。
● borderType是边界样式,该值决定了以何种方式处理边界,其值如表7-1所示。一般情况下不需要考虑该值的取值,直接采用默认值即可。
代码实例:
import cv2
# 读取图片
img = cv2.imread("test.jpg")
# 均值滤波器 (3 X 3)
blur = cv2.blur(img, (3, 3))
# 图片展示
cv2.imshow("test",img)
cv2.imshow("blur", blur)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
3.方框滤波
OpenCV还提供了方框滤波方式,与均值滤波的不同在于,方框滤波不会计算像素均值。在均值滤波中,滤波结果的像素值是任意一个点的邻域平均值,等于各邻域像素值之和除以邻域面积。而在方框滤波中,可以自由选择是否对均值滤波的结果进行归一化,即可以自由选择滤波结果是邻域像素值之和的平均值,还是邻域像素值之和。
语法格式:
dst = cv2.boxFilter( src, ddepth, ksize, anchor, normalize, borderType )
● dst是返回值,表示进行方框滤波后得到的处理结果。
● src是需要处理的图像,即原始图像。它能够有任意数量的通道,并能对各个通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F 或者CV_64F中的一种。
● ddepth是处理结果图像的图像深度,一般使用-1表示与原始图像使用相同的图像深度。
● ksize是滤波核的大小。滤波核大小是指在滤波处理过程中所选择的邻域图像的高度和宽度。例如,滤波核的值可以为(3,3),表示以3×3大小的邻域均值作为图像均值滤波处理的结果,如下式所示。
● anchor是锚点,其默认值是(-1, -1),表示当前计算均值的点位于核的中心点位置。该值使用默认值即可,在特殊情况下可以指定不同的点作为锚点。
● normalize表示在滤波时是否进行归一化(这里指将计算结果规范化为当前像素值范围内的值)处理,该参数是一个逻辑值,可能为真(值为1)或假(值为0)。
代码实例:
import cv2
# 读取图片
img = cv2.imread("test.jpg")
# 方框滤波器 (3 X 3)
box = cv2.boxFilter(img, -1, (3, 3), normalize=True)
# 图片展示
cv2.imshow("test",img)
cv2.imshow("box", box)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
4.高斯滤波
在进行均值滤波和方框滤波时,其邻域内每个像素的权重是相等的。在高斯滤波中,会将中心点的权重值加大,远离中心点的权重值减小,在此基础上计算邻域内各个像素值不同权重的和。
高斯滤波器 (Gauss Filter) 是一种线性平滑滤波, 适用于高斯噪声。
高斯噪声 (Gaussian Noise) 是概率密度函数服从高斯分布的一类噪声。
语法格式:
cv2.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)
src: 需要滤波的图片
ksize: 卷积核大小
sigmaX: 高斯核函数在 X 方向的的标准偏差
sigmaY: 高斯核函数在 Y 方向的的标准偏差
实例代码:
import cv2
# 读取图片
img = cv2.imread("test.jpg")
# 高斯滤波器 (3 X 3)
gaussian = cv2.GaussianBlur(img, (3, 3), 1)
# 图片展示
cv2.imshow("gaussian", gaussian)
cv2.imshow("test",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
5.中值滤波
中值滤波与前面介绍的滤波方式不同,不再采用加权求均值的方式计算滤波结果。它用邻域内所有像素值的中间值来替代当前像素点的像素值。
语法格式:
dst = cv2.medianBlur( src, ksize)
● dst是返回值,表示进行中值滤波后得到的处理结果。
● src是需要处理的图像,即源图像。它能够有任意数量的通道,并能对各个通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F或者CV_64F中的一种。
● ksize是滤波核的大小。滤波核大小是指在滤波处理过程中其邻域图像的高度和宽度。需要注意,核大小必须是比1大的奇数,比如3、5、7等。
代码实例:
import cv2
# 读取图片
img = cv2.imread("test.jpg")
# 中值滤波器 (3 X 3)
median = cv2.medianBlur(img, 3)
# 图片展示
cv2.imshow("median", median)
cv2.imshow("test",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
6.双边滤波
双边滤波是综合考虑空间信息和色彩信息的滤波方式,在滤波过程中能够有效地保护图像内的边缘信息。
前述滤波方式基本都只考虑了空间的权重信息,这种情况计算起来比较方便,但是在边缘信息的处理上存在较大的问题。
例如,在图中,图像左侧是黑色,右侧是白色,中间是很明显的边缘。
在均值滤波、方框滤波、高斯滤波中,都会计算边缘上各个像素点的加权平均值,从而模糊边缘信息。如图所示是高斯滤波处理的结果图像。
可以看到,经过高斯滤波处理后,边缘信息变得很模糊,均值滤波处理也会造成类似的问题。边界模糊是滤波处理过程中对邻域像素取均值所造成的结果,上述滤波处理过程单纯地考虑空间信息,造成了边界模糊和部分信息的丢失。
双边滤波在计算某一个像素点的新值时,不仅考虑距离信息(距离越远,权重越小),还考虑色彩信息(色彩差别越大,权重越小)。双边滤波综合考虑距离和色彩的权重结果,既能够有效地去除噪声,又能够较好地保护边缘信息。
语法格式:
dst = cv2.bilateralFilter( src, d, sigmaColor, sigmaSpace, borderType )
● dst是返回值,表示进行双边滤波后得到的处理结果。
● src是需要处理的图像,即原始图像。它能够有任意数量的通道,并能对各个通道独立处理。图像深度应该是CV_8U、CV_16U、CV_16S、CV_32F或者CV_64F中的一种。
● d是在滤波时选取的空间距离参数,这里表示以当前像素点为中心点的直径。如果该值为非正数,则会自动从参数sigmaSpace计算得到。如果滤波空间较大(d>5),则速度较慢。因此,在实时应用中,推荐d=5。对于较大噪声的离线滤波,可以选择d=9。
● sigmaColor是滤波处理时选取的颜色差值范围,该值决定了周围哪些像素点能够参与到滤波中来。与当前像素点的像素值差值小于sigmaColor的像素点,能够参与到当前的滤波中。该值越大,就说明周围有越多的像素点可以参与到运算中。该值为0时,滤波失去意义;该值为255时,指定直径内的所有点都能够参与运算。
● sigmaSpace是坐标空间中的sigma值。它的值越大,说明有越多的点能够参与到滤波计算中来。当d>0时,无论sigmaSpace的值如何,d都指定邻域大小;否则,d与sigmaSpace的值成比例。
● borderType是边界样式,该值决定了以何种方式处理边界。一般情况下,不需要考虑该值,直接采用默认值即可。
代码实例:
import cv2
# 读取图片
img = cv2.imread("test.jpg")
# 双边滤波
bilateralFilter = cv2.bilateralFilter(img, 25,100,100)
# 图片展示
cv2.imshow("bilateralFilter", median)
cv2.imshow("test",img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出结果:
本文正在参加 人工智能创作者扶持计划。