本文参考了《OpenCV图像处理编程实例》
图像平滑是指直接对源图像的每个像素数据做邻域运算以达到平滑图像的目的。实质上主要就是通达卷积核算子实现的,卷积核算子的相关知识大家可以参考我写的博文http://blog.csdn.net/wenhao_ir/article/details/51691410
图像平滑也称为模糊或滤波,是图像处理中常用的技术之一,进行平滑处理时需要用到滤波器核(其实就是卷积核算子),根据滤波器核函数来实现不同的滤波技术。下面介绍几种 常用的图像平滑方法的大概原理及OpenCV下的实现代码。
一、盒滤波(均值滤波)
OpenCV提供boxFilter函数和blur函数来实现图像盒滤波(均值滤波)操作。两个函数的功能是一样的哈。
均值滤波是指用模板核算子(卷积核算子)计算点领域像素的平均灰度值来代替该点的灰度。均值滤波算法比较简单,计算速度较快,但是均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏也图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。
均值滤波是线性滤波,线性滤波易于实现,且易于从频率响应的角度分析,但如果噪声是颗粒噪声(比如椒盐噪声)而非高斯噪声时,线性滤波不能去除噪声。如果图像出现极值点,比如椒盐噪声产生的噪点,线性滤波只是将噪声转换为平缓但仍可见的散粒,最佳的解决方式是通过非线性滤波(比如本文中后面要介绍的中值滤波)来滤除噪声。
上面的叙述将在下面提供的代码的运行结果中得到验证哦!
OpenCV提供boxFilter函数和blur函数来实现图像盒滤波(均值滤波)操作,boxFilter函数原型如下:
void boxFilter(InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), bool normalize=true, int borderType=BORDER_DEFAULT )
官方文档对参数的解释如下:
Parameters:
src – Source image.
dst – Destination image of the same size and type as src .
ksize – Smoothing kernel size.
anchor – Anchor point. The default value Point(-1,-1) means that the anchor is at the kernel center.
normalize – Flag specifying whether the kernel is normalized by its area or not.
borderType – Border mode used to extrapolate pixels outside of the image.
我来进一步说明下这些参数的含义:
src:源图像
dst :目标图像
ddepth:这个参数连官方文档都没解释,从下面的例子来看取-1即可,具体是什么含义我也不清楚。
ksize:卷积核算子的大小,就像我在博文http://blog.csdn.net/wenhao_ir/article/details/51691410中说的那样,通常取3阶嘛,具体的卷积核矩阵已经由盒滤波算法定好了,所以这里你只需要填大小即可。
anchor:指点锚点位置,即每次用卷积核算子计算完成后,哪个位置上的点被计算值替换。如果是取负值,那么就是位于正中间的那个点被替换。如果不明白我说的这句话,可以看下博文http://blog.csdn.net/wenhao_ir/article/details/51691410中提到的卷积核的运算法则。
normalize:卷积核是否被归一化,我的理解是这样的:比如三阶算子,那么如果要归一化,就要对每个元素乘以一个九分之一,因为九个元素嘛。(当然,仅是我的理解,我也不敢确认)
borderType:图像边界处理方法。在用卷积核算子在对图像作处理前,要先把源图像的边界扩大一点,才能保证源图像中的每一个像素都被核算子处理,这个问题产生的原因我在博文http://blog.csdn.net/wenhao_ir/article/details/51691410中作了详细的说明,大家可以参考。这个borderType就是指定边界处理方式:
在OpenCV的imgproc.hpp中定义了这个参数的可选择值,如下:
//! various border interpolation methods
enum { BORDER_REPLICATE=IPL_BORDER_REPLICATE, BORDER_CONSTANT=IPL_BORDER_CONSTANT,
BORDER_REFLECT=IPL_BORDER_REFLECT, BORDER_WRAP=IPL_BORDER_WRAP,
BORDER_REFLECT_101=IPL_BORDER_REFLECT_101, BORDER_REFLECT101=BORDER_REFLECT_101,
BORDER_TRANSPARENT=IPL_BORDER_TRANSPARENT,
BORDER_DEFAULT=BORDER_REFLECT_101, BORDER_ISOLATED=16 };
作下精简,实际上是下面这样的:
BORDER_REPLICATE
BORDER_CONSTAN
BORDER_REFLECT
BORDER_WRAP
BORDER_REFLECT_101
BORDER_REFLECT101
BORDER_TRANSPARENT
这些参数的意义在OpenCV的filter.cpp中作了解释如下:
/*
Various border types, image boundaries are denoted with '|'
* BORDER_REPLICATE: aaaaaa|abcdefgh|hhhhhhh
* BORDER_REFLECT: fedcba|abcdefgh|hgfedcb
* BORDER_REFLECT_101: gfedcb|abcdefgh|gfedcba
* BORDER_WRAP: cdefgh|abcdefgh|abcdefg
* BORDER_CONSTANT: iiiiii|abcdefgh|iiiiiii with some specified 'i'
*/
注意,以我的理解,上面的解释中第一个 '|'表示左边界,第二个 '|'表示右边界,左边界扩充了6个像素,右边界扩充了7个像素。
官方文档对blur函数的解释如下:
The call blur(src, dst, ksize, anchor, borderType) is equivalent to boxFilter(src, dst, src.type(), anchor, true, borderType)
所以两个函数实现同样的功能,即均值滤波!我也实际测试了,最终的结果确实是一致的。
好,接下来上使用两个函数的源码:
源码中用到的图像下载链接分别为:
http://pan.baidu.com/s/1kUEDw5x
http://pan.baidu.com/s/1gfCuMgb
http://pan.baidu.com/s/1o8aSIuQ
//OpenCV版本2.4.9 //交流QQ2487872782 2016-8-4日注:很报歉,此代码目前不能公开发表在博客上,已经删除,希望大家理解!
运行结果如下图所示:
从运行结果来看,确实boxFilter函数和blur函数的作用是一样的,确实均值滤波对椒噪声的处理效果不好,但对高斯噪声的处理效果还可以。
二 中值滤波
中值滤波是指用模板核算子(什么叫模板核算子?请参考我的博文http://blog.csdn.net/wenhao_ir/article/details/51691410)覆盖区域内所有像素值的排序,位置处在中间的像素值用来更新当前像点的值。如常见的核算子3×3,模板区域内的元素有9个,排序后为a1,a2,a3,a4,a5,a6,a7,a8,a9,中值滤波是指将当前像素点的值用9个元素排序后第5个位置a5的值来替代当前像素点的值。中值滤波就不像均值滤波那样是线性滤波了,它是非线性滤波,均值滤波对椒盐噪声的处理效果不好,但是中值滤波却非常有效。
OpenCV提供了medianBlur函数来实现图像的中值滤波,其实现原理可通过Simon Perreault等人在论文“Median Filtering in Constant Time”中提出的基本常数时间优化算法得到。后续经过改进与发展,Priy adarshan Kolte等人在论文“A Fast Median Filter using AltiVec”中提出了速度更快的的中值滤波实现算法。需要注意的是,因为要取中间值,所以很明显模板算子的阶子应该为奇数。
下面附使用medianBlur函数进行中值滤波的源码:
源码中用到的图像下载链接分别为:
http://pan.baidu.com/s/1gfCuMgb
http://pan.baidu.com/s/1o8aSIuQ
//OpenCV版本2.4.9 //交流QQ2487872782 2016-8-4日注:很报歉,此代码目前不能公开发表在博客上,已经删除,希望大家理解!
运行结果如下图所示:
从运行结果中可以看出中值滤波确实对椒盐噪声的滤除效果很好,原因其实只要知道中值滤波的原理就很容易想到~
三 高斯滤波
高斯滤波是将输入数组的每一个像素点与高斯内核进行卷积运算,将卷积和当作输出像素值。高斯滤波后图像被平滑的程序取决于标准差。它的输出是邻域像素的加权平均,同时离中心越近的像素权重越高。因此,相对于均值滤波,它的平滑效果更好。在图像处理中,高斯滤波一般有两种实现方式,一是用离散化窗口滑窗卷积(说白了就是利用卷积核算子的方法),另一种是利用傅里叶变换(详见我的博文 OpenCV下利用傅里叶变换和逆变换实现图像卷积算法,并附自己对于卷积核/模板核算子的理解!),最常见的就是第一种滑窗实现,只有当离散化的窗口非常大时,用滑窗计算量非常大的情况下,可能会考虑基于傅里叶变换的实现方法。高斯滤波是最有用的滤波器之一,优点通常来说有如下五点:
⑴高斯函数是单值函数,高斯滤波用像素邻域加权均值来代替替该点的像素值,像素权重会随着距离的变化而单调递减,以减少失真。
⑵高斯函数具有旋转对称性,高斯滤波在各个方向上的平滑程度是相同的,对于存在的噪声我们很难估计其方向性,这样就保证了平滑性能不会偏向任何方向。
⑶高斯函数的傅里叶变换频谱是单瓣的,高斯滤波使得平滑图像不会被不需要的高频信号所影响,同时保留了大部分所需信号。
⑷高斯滤波平滑程度是由方差σ决定的,σ越大,频带越宽,平滑程度越好,对于图像中的噪专用有可控参数可设置。
⑸高斯函数具有可分离性,二维高斯函数卷积可以分两步来进行,首先将图像与一维高斯函数函数进行卷积运算,然后将卷积结果与方向垂直的相同一维高斯函数卷积。
上面五点,目前我只能明白⑴、⑷、⑸点,而第2点和第3点真心不知道为什么。还有第⑷点中的“频带越宽,平滑程度越好” 这一点我也不明白。第⑸点其实随机过程理论里有讲的到的哦。
OpenCV提供了GaussianBlur函数来实现图像的高斯滤波,函数原型如下所示:
void GaussianBlur( InputArray src,OutputArray dst, Size ksize, double sigmaX, double sigmaY=0,int borderType=BORDER_DEFAULT );
前三个参数和最后一个参数我就不说了,和上面已经将绍的滤波函数一样的。第四个参数表示x方向上的标准方差,如果是0,则由内核的阶数自动计算得到,第五个参数表示y向上的标准方差,如果是0,则由内核的阶数自动计算得到。
GaussianBlur函数示例源码如下:
源码中用到的图像下载链接分别为:
http://pan.baidu.com/s/1gfCuMgb
http://pan.baidu.com/s/1o8aSIuQ
//OpenCV版本2.4.9 //交流QQ2487872782 2016-8-4日注:很报歉,此代码目前不能公开发表在博客上,已经删除,希望大家理解!
运行结果如下图所示:
从运行结果中我们可以看出,高斯滤波对椒盐噪声效果不好,但对高斯噪声效果还不错!
四 双边滤波
双边滤是一种非线性的滤波方法。双边滤波给每一个邻域像素分配了两部分加权系数,第一部分加权系数与高斯滤波一样,第二部分的权重则取决于该领域像素与当前像素的灰度差值。这就是双边的含义,也就是在给权重时考虑了两方面。
双边滤波器保存了过多的高频信息(你要问我为什么?我也不清楚啊),所以双边滤波器不能够干净地滤掉彩色图像里的高频噪声,只能够对低频信息进行较好的滤波。所以对于脉冲噪声,双边滤波器是滤除不了的。
OpenCV中提供bilateralFilter函数来实现双边滤波,函数原型如下所示:
void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );
官方解释如下:
Parameters:
src – Source 8-bit or floating-point, 1-channel or 3-channel image.
dst – Destination image of the same size and type as src .
d – Diameter of each pixel neighborhood that is used during filtering. If it is non-positive, it is computed from sigmaSpace .
sigmaColor – Filter sigma in the color space. A larger value of the parameter means that farther colors within the pixel neighborhood (see sigmaSpace ) will be mixed together, resulting in larger areas of semi-equal color.
sigmaSpace – Filter sigma in the coordinate space. A larger value of the parameter means that farther pixels will influence each other as long as their colors are close enough (see sigmaColor ). When d>0 , it specifies the neighborhood size regardless of sigmaSpace . Otherwise, d is proportional to sigmaSpace .
我试着翻译如下:
src-源图像
dst-目标图像
d-计算的半径,半径之内的像数都会被纳入计算,如果提供-1,会从后面的参数sigmaSpace中自动计算。
sigmaColor-这个参数实际上就是上面提到的“差值“所涉及到的像素邻域范围,我上面的原话是“第二部分的权重则取决于该领域像素与当前像素的灰度差值”,那么这个邻域取多大,就由这个参数决定!
sigmaSpace-这个参数和高斯滤波函数中的σ意义一样。如果d值大于0,那么这个值将不会影响计算结果,当然如果d<=0,那么d的值由这个sigmaSpace参数决定。
PS:最后两个参数截止到我发博文时我也不敢确定是不是那个意思,所以仅供大家参考~等以后有需要彻底搞清楚了原理再来修改博文补充。
2016-6-21日补充:今天在看一段对双边滤波介绍的资料时发现了一句话,我觉得应该和这两个参数有关,摘录如下:
参数σ_s和σ_r代表空间相似度及颜色范围相似度的灵敏性!
bilateralFilter示例代码如下:
源码中用到的图像下载链接分别为:
http://pan.baidu.com/s/1gfCuMgb
http://pan.baidu.com/s/1o8aSIuQ
//OpenCV版本2.4.9 //交流QQ2487872782 2016-8-4日注:很报歉,此代码目前不能公开发表在博客上,已经删除,希望大家理解!
运行结果如下图所示:
从运行结果来,显然双边滤波是不能处理椒噪声的,但是貌似对高斯噪声效果也一般嘛!
------------------------------------------
欢迎大家加入图像识别技术交流群:271891601,另外,特别欢迎成都从事图像识别工作的朋友交流,我的QQ号2487872782