基于空间相领像素点的平滑算法是图像处理里面经常用到的去噪算法。
它的核心思想是:选择当前像素点c和其周围的一些像素{c, n1, n2, ..., nN}(共N+1个像素点),根据他们与c的距离和/或与c的像素差值,赋予他们不同的权重{w0, w1, w2, ..., wn}(要求0<wi<=1并且w0+w1+w2+...+wN=1, w0是当前点c的权重值),那么平滑后当前点的像素值为C‘ = w0*c + w1*n1 + ... + wN*nN.这种运算方式可以称为加权平均,也可以称为卷积。
空域平滑算法就是不同权重值的卷积运算,卷积运算需要注意的问题1是计算量,2是数据搬移量。3x3的卷积运算,一个像素会被其周边9个点的计算过程用到,在有较大Cache的体系里面还好,如果没有cache或者cache比较小,那么就会造成重复的数据在内外存之间搬移。因此要尽量减少卷积运算核的大小,尤其是垂直方向上的纬度大小(图像数据绝大部分都是按照水平方向存储的)。
不同的空域平滑算法就是在N值和wi的选择上不同而已。
1. 均值滤波
N取周边的3x3或者5x5或者更大的或者不是矩形的模板,C‘是模板内所有点的平均值。
各点的权重wi相同都为1/(N+1)。均值滤波算法简单,但滤波效果不好,还模糊的了图像细节,一般都不采用。
2. 中值滤波
N取周边的3x3或者5x5或者更大的或者不是矩形的模板,C‘是模板内所有点的中间值。
wi = ni是排序后中值点 ? 1 : 0。中值滤波对孤立点的椒盐噪声特别有效,而且可以保护图像边缘,是一种经典的平滑滤波算法。但对其他的一些噪声,效果并不太好,所以也很少采用。
3. 高斯滤波
N取周边的3x3或者5x5或者更大的或者不是矩形的模板,C‘是模板内所有点高斯加权的结果。
wi的取值特征是考虑ni点与c点的距离。离c点越近的点,赋予的权重越大,反之越远的点,权重越低。在2维空间上类似一个钟形,符合高斯函数的特征。因此这类的滤波算法统称为高斯滤波。高斯滤波的计算量适中,对于各种噪声都能有一个不一定是最好但可以接受的结果,因此在图像处理大量采用。
高斯滤波的核心是高斯核,参考博文高斯图像滤波原理及其编程离散化实现方法(blog.csdn.net/likezhaobin/article/details/6835049)。
OpenCV里面定义的3x3高斯核是:
0.0625 0.1250 0.0625
0.1250 0.2500 0.1250
0.0625 0.1250 0.0625
matlab里面3x3高斯核是
0.0751 0.1238 0.0751
0.1238 0.2042 0.1238
0.0751 0.1238 0.0751
高斯核一般都是x,y两个轴对称的。OpenCV里面也可以定义不对称。
在很多应用里面定义了高斯核的大小,例如3x3或者5x5,根据高斯核直径D(大于1的奇数),可以对应计算出高斯分布σ的值,参考OpenCV的代码,σ=(D/2-1)*0.3+0.8,σ得到后就可以计算高斯核各个参数,然后卷积运算进行滤波。这个计算过程其实是不符合应用场景的。决定高斯核的因素有两个:1.核直径(大于1的奇数),2.当前噪声级别σ。D与σ之间是有约束关系的,按照高斯分布的特点,要求数值分布在(μ—3σ, μ+3σ)中的概率几乎为1,因此D最好是大于6σ的最小奇数。即 D=round(6*σ+1)|1。取更大的D值,只会增加计算量,效果并不会提升。取小于这个值的直径,会由于采样点数太少,滤波效果不好。因此应该是根据当前图像的噪声级别σ来确定采用的高斯核直径,只有这样才能使用最小的高斯核滤波得到最好的结果。只是在很多时候图像的噪声级别σ很难准确的得到,噪声级别估计也是一个复杂且重要的图像算法。
优化高斯卷积的方法主要有:1.在满足噪声级别的情况下,尽量减小高斯核直径;2.整数化高斯核系数,浮点数操作所需要的指令周期远大于整数操作;3.调整高斯核系数向2的整数倍靠拢,用左右移位来代替乘除法,这时候的高斯核已经不符合高斯分布曲线,但大致趋势相类似(例如OpenCV的3x3高斯核)。
4. 双边滤波(Bilateral filter)
高斯滤波考虑ni与c的距离关系,近的分权重大些。而双边滤波不仅考虑距离,还考虑ni与c的像素值差别,差别小的分的权重更大些,相反如果c与ni像素值差别很大,那么ni的权重会相应降低。
基于距离的权重 wdi=Guass(Dis(c-ni));
基于像素的权重 wpi=Guass(|P(c)-P(ni)|);
wi = wdi*wpi
双边滤波可以很好的保护图像边界,对于噪声点有如高斯滤波的效果,因此滤波效果优于高斯滤波,只是它的计算量比高斯滤波要大,高斯核需要实时计算,不能对于高斯核做先验优化。