在OpenCV里实现双边滤波
前面学习了高斯平滑、均值平滑,在一些图像处理里非常有效果,但是它在去除噪声同时,也把图像的边缘进行模糊。现在就得考虑有没有这样方法,既可以平滑图像,又可以保留图像边缘的信息。我们来回顾一下前面使用的高斯平滑,其实是构造一个正态分布的矩阵,以中心点像素为主,周边距离远的像素为次,这样是按距离进行加权平滑,因此距离中心点近的像素权值越大,距离远的像素权值越小。现在要增加一个领域里像素值的考虑,与中心点的像素值差别,因此在每一个像素点计算卷积时,都需要重新计算相乘的卷积核。与高斯平滑相比,高斯平滑是一个固定的卷积核,而双边滤波是一个动态的卷积核,这个卷积核根据每个像素点的像素值进行计算。由此可见双边滤波比高斯平滑要多计算一步,速度上要比高斯平滑要慢得多。其原理大体如下图所示:
左边是输入图像,中间是高斯卷积核与像素值权重核进行对应位置相乘(点乘),从而构造了一个新的卷积核,经过这个卷积核处理后输出右边的图片。
其数学的公式如下:
在这里C是表示靠近距离的高斯函数,S是表示像素相似程度的高斯函数。
其中 I 是像素的强度值,所以在强度差距大的地方(边缘),权重会减小,滤波效应也就变小。总体而言,在像素强度变换不大的区域,双边滤波有类似于高斯滤波的效果,而在图像边缘等强度梯度较大的地方,可以保持梯度。
由这里可知,双边滤波的算法分成以下几步:
- 计算高斯平滑的卷积核G。
- 计算每个像素点的相似性卷积核S。
- K=G*S,把K归一化。
- K与窗口大小的像素进行卷积,即求出该像素点值。
在OpenCV里可以采用下面函数bilateralFilter来计算:
#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import cv2
import numpy as np
#图片的路径
imgname = "gauss1.jpg"
#读取图片
image = cv2.imread(imgname, cv2.IMREAD_GRAYSCALE)
#图片的高度和宽度
h,w = image.shape[:2]
print('imagesize={}-{}'.format(w,h))
#显示原图
cv2.imshow("Image",image)
#平滑
out = cv2.bilateralFilter(image,9,75,75)
out = out.astype(np.uint8)
cv2.imshow("out",out)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果输出如下:
输入图片
输出图片
其中函数定义如下:
dst=cv.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])
参数解释:
src:输入图像
d:过滤时周围每个像素领域的直径
sigmaColor:在color space中过滤sigma。参数越大,临近像素将会在越远的地方mix。
sigmaSpace:在coordinate space中过滤sigma。参数越大,那些颜色足够相近的的颜色的影响越大。
dst是返回结果。