简介:本文深入探讨图像平滑处理技术,针对图像中存在的噪声问题,详细介绍了均值滤波、方框滤波、高斯滤波、中值滤波、双边滤波和 2D 卷积(自定义滤波)等多种滤波方法。阐述了各滤波方法的原理差异,如均值滤波求邻域像素平均值,方框滤波可选择是否归一化,高斯滤波邻域权重呈高斯分布,中值滤波取邻域中值,双边滤波避免边缘模糊等。通过对含噪摄影师图像等案例的实际代码演示与效果对比,展示了不同滤波方法在去噪效果与图像失真、边缘保持等方面的表现,帮助读者理解并选择合适的图像平滑处理手段。
如果您觉得我的文章对您有帮助,请您点赞收藏关注,我会持续为您创作更多有价值的文章
图像平滑处理
图像平滑处理是在尽量保留图片原有信息的情况下,过滤掉图像内部的噪声,含有噪声的图像是什么样的呢?下面这个摄影师的图像就存在着很多噪声
平滑处理就是对图像中与周围像素点 差异较大的像素点进行处理,处理为周围像素点的近似值。比如看下面这张图:他的周围都是140-150左右,就第三行第三列是一个27所以认为他是噪声,要取周围像素点的近似值。根据去近似值的方式不同,讲解 均值滤波 ,方框滤波 高斯滤波 中值滤波 双边滤波 2D卷积(自定义滤波)
均值滤波
均值滤波,就是把 kxk 大小的像素点求和然后计算平均值(k也叫作滤波核)。针对于图像边缘的像素点可以对图像进行扩容再 求均值。
dst = cv2.blur(需要处理的图像src,滤波核的大小ksize,锚点:滤波核处理的点在滤波核的位置默认是-1,-1就是在滤波核的中心anchor,边界样式boderType一般用不到)
我们现在就用最开始的摄影师的噪声图noise.JPG进行处理,这是我的文件夹结构,我用的是jupyter notebook ,用pycharm的也差不多,和代码放在同一个文件夹下就可以
import numpy as np
import cv2
noise_image = cv2.imread("noise.JPG")
mean_5_image = cv2.blur(noise_image,(5,5))
mean_30_image = cv2.blur(noise_image,(30,30))
cv2.imshow("original",noise_image)
cv2.imshow("mean_5",mean_5_image)
cv2.imshow("mean_30",mean_30_image)
cv2.waitKey()
cv2.destroyAllWindows()
观察一下这个运行结果,第一张图白点很多,第二张图白点少了一些,第三张图基本上看不到白点,但是这个图里的每一个点的灰度值太像了导致看不出来原来的图片轮廓了。
滤波核越大,去噪效果越好,但是失真越明显,要平衡二者之间
方框滤波
方框滤波与均值滤波的区别在于,可以选择是否取均值,默认是不取的,通过参数normalize = 1 来实现取均值(也有的地方说法叫做归一化)
我们这里要考虑一个问题,如果滤波核太大,他们的周围像素点之和会变成255也就是白色,所以要么做归一化,要么滤波核别太大
语法如下:
dst = cv2.boxFilter(待处理图像src,图像深度一般用-1表示与原图像一致ddepth,滤波核大小ksize,anchor锚点,normalize是否进行归一化)
我们在下面这个案例中展示滤波核太大没归一化成白色的案例和滤波核小一点没归一化正常的案例
import numpy as np
import cv2
noise_image = cv2.imread("noise.JPG")
filter_2 = cv2.boxFilter(noise_image,-1,(2,2))
filter_5 = cv2.boxFilter(noise_image,-1,(5,5),normalize = 0)
cv2.imshow("original",noise_image)
cv2.imshow("filter_2",filter_2)
cv2.imshow("filter_8",filter_5)
cv2.waitKey()
cv2.destroyAllWindows()
高斯滤波
高斯滤波与前两者的区别在于前两者所有邻域对应的权重都是1,而高斯滤波的越靠近滤波核中心的位置权重越大,高斯核的大小必须是奇数
语法如下:
dst = cv2.GaussianBlur(待处理图像src,ksize滤波核大小,sigmaX水平方向的标准差,sigmaY竖直方向的标准差,边界样式borderType一般不用)
import numpy as np
import cv2
noies_image = cv2.imread("noise.JPG")
gauss = cv2.GaussianBlur(noies_image,ksize = (5,5),sigmaX = 0 ,sigmaY = 0)
cv2.imshow("original",noise_image)
cv2.imshow("gaus",gauss)
cv2.waitKey()
cv2.destroyAllWindows()
中值滤波
中值滤波不是用加权的思路解决问题,他是把滤波核内的所有值进行排序,然后选取中间值,它的优势在于可以在几乎不影响原图像的情况下去除全部噪声,但是运算量比较大
dst = cv2.medianBlur(待处理图像src,滤波核大小ksize)
import numpy as np
import cv2
noies_image = cv2.imread("noise.JPG")
median = cv2.medianBlur(noies_image,ksize = 3)
cv2.imshow("original",noise_image)
cv2.imshow("med",median)
cv2.waitKey()
cv2.destroyAllWindows()
双边滤波
很多滤波都是用周围的像素点(即卷积核)的加权平均值来计算,他会导致如果这个核的一部分和另一部分如果色差比较大,一个是黑色 一个是白色,灰度值差255,这样子会导致边缘模糊。我写一段代码测试一下:
import numpy as np
import cv2
black_betw_white = np.zeros([300,300],dtype = np.uint8)
black_betw_white[0:150,0:300] = 255
gauss = cv2.GaussianBlur(black_betw_white,ksize = (5,5),sigmaX = 0 ,sigmaY = 0)
cv2.imshow("original",black_betw_white)
cv2.imshow("gaus",gauss)
cv2.waitKey()
cv2.destroyAllWindows()
可以明显观察到第二张图画蓝色圈的部分边缘出现了模糊。说明对轮廓产生了影响。
双边滤波把色彩差异较大的点的权值设为0,避免了轮廓模糊的情况产生
语法如下:
dst = cv2.bilateralFilter(原始图像src,当前像素点为中心的直径d,sigmaColor与当前像素点色差为多少以内的点能参与到计算中来,sigmaSpace他的值越大越有跟多的点参与,只要d大于0,他就无效,否则d与其成比例,边界样式borderType一般不用)
我们在下面这个案例用高斯和双边滤波的结果进行一个比较,这下充分证明了双边滤波在处理色差和轮廓的优势
import numpy as np
import cv2
black_betw_white = np.zeros([300,300],dtype = np.uint8)
black_betw_white[0:150,0:300] = 255
gauss = cv2.GaussianBlur(black_betw_white,ksize = (5,5),sigmaX = 0 ,sigmaY = 0)
double =cv2.bilateralFilter(black_betw_white,25,100,100)
cv2.imshow("original",black_betw_white)
cv2.imshow("gaus",gauss)
cv2.imshow("dob",double)
cv2.waitKey()
cv2.destroyAllWindows()
2D卷积
其实就是自己定义一个滤波核,参与运算就是了,语法方面我就不赘述了,看这个案例就好了。
import numpy as np
import cv2
image = cv2.imread("noise.JPG")
kernel = np.ones((9,9),dtype = np.float32)/81
r = cv2.filter2D(image,-1,kernel)
cv2.imshow("original",image)
cv2.imshow("fil",r)
cv2.waitKey()
cv2.destroyAllWindows()
致谢
本文参考了一些博主的文章,博取了他们的长处,也结合了我的一些经验,对他们表达诚挚的感谢,使我对图像平滑处理 有更深入的了解,也推荐大家去阅读一下他们的文章。纸上学来终觉浅,明知此事要躬行:
OpenCV实战系列:图像滤波详解
OpenCV(十一)图像滤波(平滑处理)(平均、中值、高斯、双边滤波)