在尽量保留图像原有信息的基础上,过滤掉图像的内部噪声,这一过程称为对图像的平滑处理,它会将图像周围像素值差异较大的值调整为周围像素的近似值。
图像平滑处理通常伴随着图像模糊操作,因此,图像平滑处理又被称为图像模糊处理。
常见的方法主要有:
(1):均值滤波
(2):方框滤波
(3):高斯滤波
(4):中值滤波
(5):双边滤波
(6):二维卷积(自定义滤波)
均值滤波是指用当前的像素点周围N*N个像素值的均值来代替当前像素值。然后使用该方法遍历图像内的每一个像素点,即可完成整幅图的均值滤波。
新值=((197+25+106+156+159)+
(149+40+107+5+71)+
(163+198+ 226+223+156)+
(222+37+68+193+157)+
(42+72+250+41+75)) / 25
=126
dst=cv2.blur(src, ksize, dst=None, anchor=None, borderType=None)
src:原始图像,可以是任意通道数,并能对每个通道单独处理
ksize:滤波核大小,如:(5,5),表示以5*5大小的领域均值作为图像均值滤波处理的结果,(卷积核越大,去噪效果越好,图片越模糊,计算量越大(即时间越久))
一般情况anchor与borderType默认即可
import cv2
img=cv2.resize(cv2.imread("D:/my project/opencv3/chapter_1/img/9.jpg"),(300,300))
dst=cv2.blur(src=img, ksize=(5,5),dst=None)
cv2.imshow("img",img)
cv2.imshow("dst",dst)
cv2.waitKey()
img为原图,dst为ksize=(3,3)的均值滤波图,dst1为ksize=(5,5)的均值滤波图,从图中可以看出,ksize越大,去噪效果越好,但图片越模糊
方框滤波原理和均值滤波原理基本一致,区别是需不需要均一化处理;需要均一化处理,则原理和均值滤波相同;如果不需要均一化处理,很容易发生溢出,溢出时均为白色,设置对应像素值为255,而对于均一化或者非均一化处理主要通过传递参数normalize来进行区别,当normalize=Ture时,表示需要均一化处理,而当normalize=Flase时,则表示不需要均一化处理(非均一化处理)。
dst=cv2.boxFilter(src, ddepth, ksize, dst=None, anchor=None, normalize=None, borderType=None)
src:原始图像,它可以是任意数量的通道,并能够对每个通道做独立的处理。
ksize:核大小
ddepth:处理结果图像的图像深度,一般使用-1表示与原始图像有相同的深度
anchor:锚点,默认(-1,-1),即当前计算的点位于核的中点
normalize:是否进行归一化(将计算结果规范化到当前像素范围内的值)该参数是一个逻辑值,可以为真(1,默认),假(0)
a:当normalize为1时表示要进行归一化,用邻域像素值之和除以面积
b:normalize为1时不需要归一化,直接使用邻域像素之和(超出部分被截断为最大值)
borderType:边界样式,定义以何种方式处理边界,默认即可
import cv2
img=cv2.resize(cv2.imread("D:/my project/opencv3/chapter_1/img/4.jpg"),(300,300))
dst=cv2.blur(src=img, ksize=(3,3))
dst1=cv2.boxFilter(img,-1,(3,3),normalize=1)
dst2=cv2.boxFilter(img,-1,(3,3),normalize=0)
cv2.imshow("img",img)
cv2.imshow("dst",dst)
cv2.imshow("dst1",dst1)
cv2.imshow("dst2",dst2)
cv2.waitKey()
由图可以看出,图dst与dst1相同,即normalize=1时,方框滤波和均值滤波是一致的。在图dst2中,normalize=0,没有进行归一化,邻域像素之和大于255的都别截断处理成255,故出现大片的白色。
在高斯滤波中,会将中心点的权重加大,远离中心点的权重减小,进而计算邻域内像素的加权和。
dst=cv2.GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)
src:可以为任意数量的通道,并能对每个通道单独处理
ksize:滤波核,在滤波过程中其邻域图像的高与宽度,该滤波核的值必须为奇数。
sigmaX:卷积核在水平方向(x轴方向)的标准差,控制的是权重比例,默认为0。该参数为必选参数,但可以设置为0,让函数自己去计算它的值。
sigmaY:可选参数,卷积核在垂直方向上(y轴方向)的标准差,如果该值为0(默认值),则只采用sigmaX的值,若sigmaX也为0,则通过ksize.width和ksize.height计算得到
a:sigmaX=0.3[(ksize.width-1)0.5-1]+0.8
b:sigmaY=0.3[(ksize.height-1)0.5-1]+0.8
import cv2
img=cv2.resize(cv2.imread("D:/my project/opencv3/chapter_1/img/5.jpg"),(300,300))
#默认sigmaX,sigmaX均为0,让其自己计算
dst=cv2.GaussianBlur(img,(11,11),0,0)
dst1=cv2.GaussianBlur(img,(11,11),3,3)
dst2=cv2.GaussianBlur(img,(11,11),10,3)
cv2.imshow("img",img)
cv2.imshow("dst",dst)
cv2.imshow("dst1",dst1)
cv2.imshow("dst2",dst2)
cv2.waitKey()
从上可以大致看出:
(1)在核大小固定的情况下,sigma值越大,权值分布越平缓。因此,邻域各个点的值对输出值的影响越大,最终结果造成图像越模糊。
(2)在核大小固定的情况下,sigma值越小,权值分布越突起。因此,邻域各个点的值对输出值的影响越小,图像变化也越小。假如中心点权值为1,其他点权值为0,那么最终结果是图像没有任何变化。
中值滤波不再采用加权求均值的方式计算滤波结果,它用邻域内所用像素的中间值代替当前像素点的像素值。
cv2.medianBlur(src, ksize, dst=None)
src:原图,任意通道数量
ksize:滤波核大小,必须为大于1的奇数,如:3,5,7等。
import cv2
img=cv2.resize(cv2.imread("D:/my project/opencv3/chapter_1/img/10.jpg"),(300,300))
dst=cv2.medianBlur(img, 5, dst=None)
cv2.imshow("img",img)
cv2.imshow("dst",dst)
cv2.waitKey()
由图可以看出,由于中值滤波器没有进行加权处理,它不会存在均值滤波器等带来的细节模糊问题,在中值滤波中,由于噪声不同于邻域的像素,故它很难被选上,所以几乎可以在不影响原有图像的情况下去除全部噪声。但由于要排序进行中值的选择,故运算量较大。
双边滤波是综合考虑空间信息和色彩信息的滤波方式(距离越远,权重越小,色彩差别越大,权重越小),在滤波过程中能够有效地保护图像内的边缘信息。
前面四种滤波器基本都只考虑了空间的权重信息,它们在边缘信息的处理上存在较大的问题。
dst=cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, dst=None, borderType=None)
src:可以为任意数量的通道,并能对每个通道单独处理
d:滤波是选取的空间距离参数,表示以当前像素点为中心的直径,该值越大,速度越慢,一般使用5即可,对于较大的离线噪声,可以选d=9。该值为负数时,会自动由sigmaSpace计算得到。
sigmaColor:滤波时选取的颜色差值范围,决定了周围那些像素点能参与到滤波中来。如sigmaColor=20时,表示在以d为直径的范围内,所有像素点与当前像素点的值小于20的参与滤波运算。当为0失去意义。
sigmaSpace:坐标空间中的sigma值,它越大,参与滤波的点越多。当d>0时,无论sigmaSpace大小,都由d指定邻域大小,否则,d与sigmaSpace成比例
borderType:边界样式,一般默认即可。
为方便,一般将sigmaColor与sigmaSpace设置为相同即可,如果它们较小,滤波不明显(参与运算的点较少),如果它们较大,滤波较明显,会产生卡通效果。
import cv2
img=cv2.resize(cv2.imread("D:/my project/opencv3/chapter_1/img/10.jpg"),(300,300))
dst=cv2.GaussianBlur(img,(5,5),0,0)
dst1=cv2.bilateralFilter(img,100,150,150)
cv2.imshow("img",img)
cv2.imshow("dst",dst)
cv2.imshow("dst1",dst1)
cv2.waitKey()
由图dst与dst1可知,经过双边滤波的dst1边缘信息保留得比较完整。
上面的滤波器大都具有一定的灵活性,能方便的设置卷积核的大小与数值。但在上述滤波器中并不是所有的卷积核都能实现,这时就可能需要用到自定义卷积核实现卷积(滤波)操作。
dst=cv2.filter2D(src, ddepth, kernel, dst=None, anchor=None, delta=None, borderType=None)
src:可以为任意数量的通道,并能对每个通道单独处理。
ddepth:必选值,处理结果图像的图像深度,一般使用-1表示与原始图像有相同的深度
kernel:自定义的卷积核,单通道的数组。
anchor:锚点,默认即可
delta:修正值,如果该值存在,会在基础滤波的结果上加上该值作为最终滤波结果。
import cv2
import numpy as np
img=cv2.resize(cv2.imread("D:/my project/opencv3/chapter_1/img/9.jpg"),(300,300))
kernel=np.array(range(0,100,4)).reshape(5,5)/sum(range(0,100,4))
print(kernel)
kernel_1=np.ones((5,5),np.float32)/25 #d等同于5*5的均值滤波
dst=cv2.filter2D(img,-1,kernel)
dst_1=cv2.filter2D(img,-1,kernel_1)
cv2.imshow("img",img)
cv2.imshow("dst",dst)
cv2.imshow("dst_1",dst_1)
cv2.waitKey()