方框滤波、均值滤波、高斯滤波,原始数据和滤波结果是一种线性的算术运算,即用加减乘除等运算实现所以称之为线性滤波。
中值滤波、双边滤波。原始数据和滤波结果是一种逻辑关系,即通过比较一定邻域内的灰度值大小来实现的。
将模板内的像素数据,按从小到大的顺序排列,取中间的像素替换原始像素的卷积操作。
注:如果数量为偶数那么中位数则是中间两数的均值。中值滤波是一种可以非常有效去除少量异常像素值的滤波方法。
中值滤波在一定的条件下可以克服常见线性滤波器如方框滤波器、均值滤波等带来的图像细节模糊,而且对滤除脉冲干扰及图像扫描噪声非常有效,也常用于保护边缘信息, 保存边缘的特性使它在不希望出现边缘模糊的场合也很有用,是非常经典的平滑噪声处理方法。
但是中值滤波的缺点也很明显,因为要进行排序操作,所以处理的时间长,是均值滤波的5倍以上。
void medianBlur( InputArray src, OutputArray dst, int ksize );
输入图像src,输出图像dst,以及核的大小ksize。注意这里的ksize必须为正奇数1,3,5,7……否则程序会出错。
求取模板内的像素均值替代像素值。
均值模糊+中值模糊+自定义模糊:
#均值模糊、中值模糊、自定义模糊
#模糊操作的基本原理
#1、基于离散卷积
#2、定义好每个卷积核
#3、不同卷积核得到不同的卷积效果
#4、模糊是卷积的一种表现
def blur_demo(image):
#均值模糊
dst=cv2.blur(image,(1,10))
cv2.imshow("blur_demo",dst)
def median_blur_demo(image):
#中值模糊
dst=cv2.medianBlur(image,5)#奇数
cv2.imshow("medianBlur",dst)
def custom_blur_demo(image):
#自定义模糊
kernel=np.array([[0,-1,0],[-1,5,-1],[0,-1,0]],np.float32)
#dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
#ddepth:目标图像所需深度
#kernel:卷积核(或相当于相关核),单通道浮点矩阵;如果要将不同的内核应用于不同的通道,请使用拆分将图像拆分为单独的颜色平面,然后单独处理它们。
#anchor:内核的锚点,指示内核中过滤点的相对位置;锚应位于内核中;默认值(-1,-1)表示锚位于内核中心。
#detal:在将它们存储在dst中之前,将可选值添加到已过滤的像素中。类似于偏置。
#borderType:像素外推法,参见BorderTypes
dst=cv2.filter2D(image,-1,kernel=kernel)
cv2.imshow("custom_blur_demo",dst)
if __name__ == '__main__':
image=cv2.imread('../opencv-python-img/lena.png')
#blur_demo(image)
#median_blur_demo(image)
custom_blur_demo(image)
cv2.waitKey(0)
高斯滤波是最常用的图像去噪方法之一,它能很好地滤除掉图像中随机出现的高斯噪声,高斯滤波是一种低通滤波,它在滤除图像中噪声信号的同时,也会对图像中的边缘信息进行平滑,表现出来的结果就是图像变得模糊。高斯滤波之所以会导致图像变得模糊,是因为它在滤波过程中只关注了位置信息。
在滤波窗口内,距离中心点越近的点的权重越大;这种只关注距离的思想在某些情况下是可行的,例如在平坦的区域,距离越近的区域其像素分布也越相近,自然地,这些点的像素值对滤波中心点的像素值更有参考价值。但是在像素值出现跃变的边缘区域,这种方法会适得其反,损失掉有用的边缘信息。此时就出现了一类算法——边缘保护滤波方法,双边滤波就是最常用的边缘保护滤波方法(另一种常用来与双边滤波对比的边缘保护滤波方法——引导滤波)。
高斯噪声+高斯模糊:
def clamp(pv):
if pv>255:
return 255
elif pv<0:
return 0
else:
return pv
def gaussian_noise(image):
h,w,c=image.shape
for row in range(h):
for col in range(w):
s=np.random.normal(0,20,3)
b=image[row,col,0]
g=image[row,col,1]
r=image[row,col,2]
image[row,col,0]=clamp(b+s[0])
image[row,col,1]=clamp(g+s[1])
image[row,col,2]=clamp(r+s[2])
cv2.imshow("noise image",image)
if __name__ == '__main__':
image=cv2.imread("../opencv-python-img/lena.png")
t1=cv2.getTickCount()
gaussian_noise(image)
#dst=cv2.GaussianBlur(image,(0,0),15)
#cv2.imshow('dst',dst)
t2=cv2.getTickCount()
time=(t2-t1)/cv2.getTickFrequency()
print(time)
cv2.waitKey(0)
#说明:
#自定义函数高斯模糊耗时3.4s
#调用opencv高斯模糊函数耗时0.1s
双边滤波的思想很简单,在高斯滤波的基础上加入了像素值权重项,也就是说既要考虑距离因素,也要考虑像素值差异的影响,像素值越相近,权重越大。
Python: cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) → dst
函数中的参数依次表示
src:输入图像,
d:滤波窗口的直径(函数注释中使用的是Diameter,那么很可能函数中选取的窗口是圆形窗口),
sigmaColor:像素值域方差,颜色空间的标准差,即灰度值相似性高斯函数标准差,一遍尽可能大。
sigmaSpace:空间域方差,以及边缘处理方式。一般尽可能小,参数越大,邻近像素将会在越远的地方mix
#---------------------------------边缘保留滤波EPF
#1、高斯双边
#2、均值迁移
#双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部处理的特点。之所以能够达到保边去噪的滤波效果是因为滤波器由两个函数构成:一个函数是由几何空间距离决定滤波器系数,另一个是由像素差值决定滤波器系数.
def bi_demo(image):
dst=cv2.bilateralFilter(image,0,100,33)
#image 输入图像
#0:过滤时周围每个像素邻域的直径
#100:颜色空间的标准差,即灰度值相似性高斯函数标准差,一遍尽可能大。
#33:空间高斯函数标准差。一般尽可能小,参数越大,邻近像素将会在越远的地方mix
cv2.imshow("bi_demo",dst)
def shift_demo(image):#使用均值边缘保留滤波时,可能会导致图像过度模糊
dst=cv2.pyrMeanShiftFiltering(image,10,50)
#src:原图像
#sp:空间窗的半径
#sr:色彩窗的半径
cv2.imshow("shift_demo",dst)
if __name__ == '__main__':
image=cv2.imread('../opencv-python-img/lena.png')
#bi_demo(image)
shift_demo(image)
cv2.waitKey(0)
引导滤波与双边滤波相似,同样具有保持边缘的特性,在引导滤波中,用到了局部线性模型,用如下图进行简单理解:
某函数上一点与其临近部分的点成线性关系,一个复杂的函数就可以用很多局部的线性函数来表示,当需要求该函数上某一点的值时,只需要计算所有包含该点的线性函数的值做平均即可。这种模型,在表示非解析函数上非常有用。
在滤波效果上,引导滤波和双边滤波差不多,在一些细节上,引导滤波较好。
引导滤波最大的优势在于,可以写出时间复杂度与窗口大小无关的算法,因此在使用大窗口处理图片时,其效率更高。
在图像去雾、图像抠图上均有相应的应用。
参考
1、高斯噪声和椒盐噪声_FireBird的专栏-CSDN博客_高斯噪声
2、导向滤波(Guided Filter)公式详解_Zetropy-CSDN博客_导向滤波
3、数字图像处理之椒盐噪声和中值滤波_tsfx051435adsl的博客-CSDN博客_椒盐噪声图像