OpenCV-Python图像滤波(平滑处理)(平均、中值、高斯、双边滤波)
“平滑”(滤波)通常又称“模糊”,是一种简单常用的图像处理操作。进行平滑处理的原因有很多,但通常是用来去除噪声和相机失真,平滑在按照一定的原理来降低图像分辨率中也有重要应用。
根据空间滤波增强目的可分为:平滑滤波和锐化滤波;
根据空间滤波的特点可分为:线性滤波和非线性滤波。
(1)平滑滤波,能减弱或消除图像中的高频分量,但不影响低频分量。因为高频分量对应图像中的区域边缘等灰度值具有较大、较快变化的部分,平滑滤波将这些分量绿区可减少局部灰度的起伏,使图像变得比较平滑。实际应用中,平滑滤波即可以用来消除噪声,又可以用在提取较大的目标前过滤去除较小的细节或将目标内的小间断连接起来。
(2)锐化滤波,能减弱或消除图像中的低频分量,但不影响高频分量。因为低频分量对应图像中灰度值缓慢变化的区域,因而与图像的整体特性如整体对比度和平均灰度值等有关。锐化滤波将这些分量滤去可使图像反差增加,边缘明显。实际应用中,锐化滤波可用于增强图像中被模糊的细节或景物的边缘。
(1)线性滤波:运算只是对各像素灰度值进行简单处理(如乘一个权值)最后求和。
(2)非线性滤波:如果对像素灰度值的复杂运算,而不是最后求和的简单运算。
下面介绍几种OpenCV中几种滤波。
一、均值滤波
均值滤波是典型的线性滤波算法,主要方法为邻域平均法,即用一片图像区域的各个像素的均值来代替原图像中的各个像素值。一般需要在图像上对目标像素给出一个模板(内核),该模板包括了其周围的临近像素(比如以目标像素为中心的周围8(3x3-1)个像素,构成一个滤波模板,即去掉目标像素本身)。再用模板中全体像素的平均值来代替原来像素值。即对待处理的当前像素点(x,y),选择一个模板,该模板由其邻近的若干像素组成,求模板中所有像素的均值,再把该均值赋予当前像素点(x,y),作为处理后图像在该点上的灰度点g(x,y),即g(x,y)=1/m求和f(x,y),其中m为该模板中包含当前像素在内的像素总个数。
示例
import cv2
import numpy as np
noise_img = cv2.imread("noise- 1%.jpg", cv2.IMREAD_UNCHANGED) #选用了一个加了噪声的图片
cv2.imshow("noise_img", noise_img)
blur_img = cv2.blur(noise_img, (6, 6))
cv2.imshow("blur_img", blur_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
从两张图可以看出,均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。
二、方框滤波
方框滤波和均值滤波的原理是类似的,因为均值滤波是方框滤波的归一化表现。
dst = cv2.boxFilter(src,
ddepth,
ksize,
anchor,
normalize,
bordType)
- dst为返回值,进行滤波后得到的结果图像
- src为原始图像,它可以有任意数量的通道,并可以对各个通道进行独立处理。图像深度应该是CV_8U, CV_16U, CV_16S, CV_32F或者CV_64F中的一种
- ddepth为处理结果的图像深度,一般用-1表示与原始图像相同的图像深度
- ksize为滤波核的大小。滤波核的大小是指在在均值处理过程中其邻域图像的高度和宽度
- anchor为锚点,其默认值为(-1, -1),表示当前计算均值的点位于核中心点位置(使用默认即可)
- normalize表示在滤波的时候是否进行归一化(此处指将计算结果规范化为当前像素范围内的值)处理,该参数为一逻辑值且默认为True。
当其为True时,表示要进行归一化处理,即要用邻域像素除以面积
当其为False时,表示不需要进行归一化处理,直接使用邻域像素值的和
特别的,针对5x5邻域,当normalize=True时函数cv2.bosFilter()的作用与函数cv2.blur()的作用是一样的 - borderType是边界样式,改置决定了以何种方式处理边界,其取值一般取默认值即可
设置:normalize=True,表示进行归一化处理,就和均值滤波结果一样
import cv2
import numpy as np
noise_img = cv2.imread("noise- 1%.jpg", cv2.IMREAD_UNCHANGED)
cv2.imshow("noise_img", noise_img)
blur_img = cv2.boxFilter(noise_img, -1, (6, 6), normalize=True)
cv2.imshow("blur_img", blur_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
设置:normalize=False,表示不进行归一化处理
import cv2
import numpy as np
noise_img = cv2.imread("noise- 1%.jpg", cv2.IMREAD_UNCHANGED)
cv2.imshow("noise_img", noise_img)
blur_img = cv2.boxFilter(noise_img, -1, (6, 6), normalize=False)
cv2.imshow("blur_img", blur_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
这样,图片大部分都是白色,在6×6的像素点之和大部分都会大于255,所以就会出现上述结果,那么我们可以将核的大小缩小:
import cv2
import numpy as np
noise_img = cv2.imread("noise- 1%.jpg", cv2.IMREAD_UNCHANGED)
cv2.imshow("noise_img", noise_img)
blur_img = cv2.boxFilter(noise_img, -1, (2, 2), normalize=False) #将核大小缩小成2×2
cv2.imshow("blur_img", blur_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
三、高斯滤波
在进行均值滤波和方框滤波时,其邻域内每个像素点的权重是相等的。在高斯滤波中会将中心点的权重加大,远离中心点的权重值减小,再此基础上计算邻域内各个像素值不同权重的和。在高斯滤波中,核的宽度和高度可以不相同,但是它们必须均为奇数。
dst = cv2.GaussianBlur(src,
ksize,
sigmaX,
sigmaY,
bordType)
- dst为返回值,进行滤波后得到的结果图像
- src为原始图像,它可以有任意数量的通道,并可以对各个通道进行独立处理。图像深度应该是CV_8U, CV_16U, CV_16S, CV_32F或者CV_64F中的一种
- ksize为滤波核的大小。滤波核的大小是指在在均值处理过程中其邻域图像的高度和宽度
- sigmaX为卷积核在水平方向(X轴方向)上的标准差,其控制的是权重比例
- sigmaY为卷积核在水平方向(Y轴方向)上的标准差,如果将该值设置为0,则只能采用sigmaX的值,如果sigmaX和sigmaY均为0,则其值则通过ksize.wigth和ksize.height计算得到,其中
- sigmaX = 0.3 x [(ksize.width - 1) x 0.5 - 1] +0.8
- sigmaY = 0.3 x [(ksize.height - 1) x 0.5 - 1] +0.8
- borderType是边界样式,改置决定了以何种方式处理边界,其取值一般取默认值即可
示例:
import cv2
noise_img = cv2.imread("noise- 1%.jpg", cv2.IMREAD_UNCHANGED)
cv2.imshow("noise_img", noise_img)
blur_img = cv2.GaussianBlur(noise_img, (5, 5), 0)
cv2.imshow("blur_img", blur_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
四、中值滤波
中值滤波法是一种非线性平滑技术,中值滤波会取当前的像素点及其周围临近的像素点(一共奇数个像素点)的像素值,将这些像素值排序然后将位于中间位置的像素值作为当前像素点的像素值。
dst = cv2.medianBlur(src,
ksize)
- dst为返回值,进行滤波后得到的结果图像
- src为原始图像,它可以有任意数量的通道,并可以对各个通道进行独立处理。图像深度应该是CV_8U, CV_16U, CV_16S, CV_32F或者CV_64F中的一种
- ksize为滤波核的大小。滤波核的大小是指在在均值处理过程中其邻域图像的高度和宽度
示例:
import cv2
noise_img = cv2.imread("noise- 1%.jpg", cv2.IMREAD_UNCHANGED)
cv2.imshow("noise_img", noise_img)
blur_img = cv2.medianBlur(noise_img, 3)
cv2.imshow("blur_img", blur_img)
cv2.waitKey(0)
cv2.destroyAllWindows()