OpenCV学习(五)平滑滤波
在图像处理中,会用到对图像的平滑处理。平滑常常被用来消除图像的噪声,下面介绍几个常用于图像平滑处理的函数。
(1)blur
平滑处理常常用到的是线性滤波器。线性滤波器的数学基础建立在卷积的概念之上。对于一个线性滤波器,变换之后图像的输出值其实就是该点的某个邻域内各点输入像素值的加权求和。假如我们现在有一幅M*N的图像要进行线性滤波,我们采用的卷积核(kernel)的大小为m*n,那么处理之后的图像每一点的输出像素值由下面这个式子确定:
上面这个式子的分子其实就是源图像f(x,y)与我们所用的卷积核w做卷积运算,而分母是w中各个元素的求和结果,这样就为邻域内不同位置分配了不同的权重。需要注意的是,一旦w被确定,那么分母其实是一个常数,所以我们应该提前算出分母的值,避免直接代入上式造成的重复计算和不必要的时间浪费。
而OpenCV中的blur函数就是上面所提到的线性滤波中的一种。它和其他线性滤波算法的共性点自然在于它也是一个线性滤波器,满足叠加原理。
个性的地方在于这种线性滤波所用的卷积核的各个元素都是相等的,都是1,也就是它对该点邻域内的各个其他点“一视同仁”,“不分彼此”。所以这时候,分母的大小是m*n,分子呢?自然就是邻域内各点像素值求和。而这种“大锅饭”的坏处,便是消除噪声的同时也使得源图像的某些细节变得模糊不清。具体模糊的程度要看我们所选用的卷积核的大小(也就是m,n的大小)和图像细节处的像素范围。请看下面的例子(取自冈萨雷斯数字图像处理一书),这个例子分别展示了原图和经过blur函数处理后的图像,所用的卷积核的大小依次为3*3,5*5,9*9,15*15,35*35,从字母a和噪声区域以及几个圆形点的变化可以比较容易地看出图像模糊是如何受到卷积核大小和细节本身所影响的:
string name="image.tif"; Mat src=imread (name,CV_LOAD_IMAGE_GRAYSCALE); imshow ("Original",src); imwrite ("Original Image.tif",src); Mat dst; blur (src,dst,Size(3,3)); imshow ("size=3",dst); imwrite ("size=3.tif",dst);
(2)高斯滤波器
由于blur的“大锅饭”政策使得图像的模糊比较严重,所以人们又提出了其他的分配权重的方法,其中之一便是高斯滤波。高斯滤波的思想便是根据邻域内的点到中心点的距离来按照高斯函数分配权重。还记得那个钟形函数的曲线吗??
“假设图像是1维的,那么观察上图,不难发现中间像素的加权系数是最大的, 周边像素的加权系数随着它们远离中间像素的距离增大而逐渐减小。”
二维的Guass函数可以写成如下的形式:
值得一提的是,高斯函数作为一种很典型的函数,被广泛地应用于权重分配等一些场合,比如局部加权回归(locally wighted regression)。
同时要注意到,虽然高斯函数并不是一个线性函数,但是由于它的思想仍然是给不同区域的像素点分配不同的权重。本质上和blur并没有什么区别,它仍然是一种线性滤波。它的非线性体现在了权重的分配过程中,而这个分配过程是距离的函数,并不是像素值的函数!
同时标准差的不同,也会对滤波结果产生比较大的影响。实际过程中如何选择标准差,也是应该考虑的问题之一。可以知道,标准差越大,高斯函数的图像会越扁平,也就是说权重的下降速度会变慢,高斯滤波也就越接近于blur;标准差越小,高斯函数的图像会越高瘦,也就是认为数据集中程度较好,权重会随着距离的增大迅速衰减,这样模糊化程度会减弱,但是消除噪声的能力会下降。所以说,标准差的大小实际是对权重分配的再调整。
string name="image.tif"; Mat src=imread (name,CV_LOAD_IMAGE_GRAYSCALE); imshow ("Original",src); Mat dst; GaussianBlur (src,dst,Size(3,3),1); //x方向的标准差选为1 imshow ("高斯滤波",dst); imwrite ("高斯滤波结果.tif",dst);
(3)中值滤波
中值滤波是一种非线性滤波方法。顾名思义,这种滤波方法会将邻域内的像素值排序,选出中值赋给输出像素点。这种滤波方法模糊化较轻,尤其适用于被椒盐噪声污染的图像。
对比一下就可以发现中值滤波很好地去除了噪声。
string name="CircuitBoard.tif"; Mat src=imread (name,CV_LOAD_IMAGE_GRAYSCALE); //线性滤波 Mat blurFilter; blur(src,blurFilter,Size(3,3)); //中值滤波 Mat medianFilter; medianBlur (src,medianFilter,3); imshow("椒盐噪声污染的图像",src); imshow("线性滤波结果",blurFilter); imshow("中值滤波结果",medianFilter); imwrite ("线性滤波结果.tif",blurFilter); imwrite ("中值滤波结果.tif",medianFilter);
(4)双边滤波
双边滤波也是一种非线性滤波方法。出于减轻图象去噪后模糊的问题,双边滤波不仅考虑权重随着距离衰减,同样也认为像素值相差越多,所占的权重应该越小。“双边滤波器也给每一个邻域像素分配一个加权系数。 这些加权系数包含两个部分, 第一部分加权方式与高斯滤波一样,第二部分的权重则取决于该邻域像素与当前像素的灰度差值。”
由于权重的分配过程中不但涉及到距离信息,更涉及到了像素值,所以容易想到这是一种非线性滤波方法。
对于这种滤波方法,这个网址给出了一份比较详细的数学论证:双边滤波的数学原理。要注意一点,双边滤波不一定要靠高斯函数来实现,但是高斯函数是一种很常用的分配权重的方法。而且我个人认为,由于“中心极限定理”,高斯函数应该是一种比较好的分配方法。
这种方法的好处便是能够在去噪和抗模糊化中取得一种比较好的折中效果。
这个函数的调用格式为(这里参考了邻域滤波:方框、高斯、中值、双边滤波这篇博客和图像平滑处理这个教程的内容):
bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );
d 表示滤波时像素邻域直径,d为负时由 sigaColor计算得到;d>5时不能实时处理。