本节主要记录OpenCV 两类五种常见的滤波方式:
线性滤波:方框滤波、均值滤波、高斯滤波
非线性滤波: 中值滤波、双边滤波
文章首先概括各种滤波方式的特点以及用法,最后给出相应的效果及demo;
滤波的目的:
滤波的目的有两个即:1.抽出对象的特征作为图像识别的特征模式;2.为适应图像处理要求,消除数字图像所混入的噪声 .
对图像滤波有两个要求:1.不能损坏图像的轮廓和边缘等重要信息;2.使图像清晰视觉效果更好.
为了进行图像平滑操作,通常在图像上加一个滤波器(filter),最常见的类型是线性的,输出像素值(g(i, j))最终由原像素值和加权值决定。其公式如下:
其中h(k, l)被称为核(kernel),是加到图像上滤波器(filter)的系数;
一.方框滤波BoxBlur:
这是所有滤波器中最简单的一种滤波方式。每一个输出像素的是内核邻域像素值的平均值得到。 也就意味着滤波核越大,滤波结果图像越平滑,也就越模糊;
通用的滤波kernel如下:
这里是一个长宽分别为Kwidth和Kheight的窗口函数,在此区域内邻域中像素值叠加求平均即可求出位于kernel中心点像素的像素值。opencv中提供了方框滤波函数boxFilter()
/! smooths the image using the box filter. Each pixel is processed in O(1) time
CV_EXPORTS_W void boxFilter( InputArray src, OutputArray dst, int ddepth,
Size ksize, Point anchor=Point(-1,-1),
bool normalize=true,
int borderType=BORDER_DEFAULT );
其中:
- InputArray src: 输入图像,可以是Mat类型 ;
- OutputArray dst: 经滤波后输出图像 ;
- int ddepth: 目标图像的深度,若设置为-1,则深度与原图像深度相同 ;
- Size ksize: Size类型,内核的大小,一般用Size(w, h)表示,如Size(3, 3);
- Point anchor:默认值为 Point(-1,-1), 标记进行滤波操作的点,如果是默认值(-1, -1)说明对上述窗口中心点所对应的像素点进行操作 ;
- bool normalize: 默认值true,标记内核是否被归一化处理,所谓归一化,简单说就是将结果控制在摸个范围之内;
- int borderType:默认值BORDER_DEFAULT,用于推断图像外部像素的某种便捷模式;
二.均值滤波 blur:
理解了方框滤波,再看均值滤波也就比较简单了,在方框滤波当中,若 normalize = false即为均值滤波;OpenCV对应函数:
//! a synonym for normalized box filter
CV_EXPORTS_W void blur( InputArray src, OutputArray dst,
Size ksize, Point anchor=Point(-1,-1),
int borderType=BORDER_DEFAULT );
其中:
- InputArray src:
- OutputArray dst:
- Size ksize:
- Point anchor=Point(-1,-1):
- int borderType=BORDER_DEFAULT :
参数均与方框滤波含义相同;
三.高斯滤波GaussianBlur()
高斯滤波是一种线性平滑滤波,对于除去高斯噪声(概率分布服从正态分布)有很好的效果。高斯滤波被形容为”Probably the most useful filter”,同时也指出高斯滤波并不是效率最高的滤波算法;高斯滤波是通过对输入数组的每个点与输入的高斯滤波模板执行卷积计算然后将这些结果一块组成了滤波后的输出数组,通俗的讲就是高斯滤波是对整幅图像进行加权平均的过程,每一个像素点的值都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。
高斯滤波和高斯模糊:高斯滤波和高斯模糊并非同一概念,二者的区别主要在于所采用的滤波器是高通还是低通;比如低通滤波器,像素能量低的通过,而对于像素能量高的部分将会采取加权平均的方法重新计算像素的值,将能量像素的值编程能量较低的值,我们知道对于图像而言其高频部分展现图像细节,所以经过低通滤波器之后整幅图像变成低频造成图像模糊,这就被称为高斯模糊;相反高通滤波是允许高频通过而过滤掉低频,这样将低频像素进行锐化操作,图像变的更加清晰,被称为高斯滤波;
简单说:高斯滤波是指用高斯函数作为滤波函数的滤波操作而高斯模糊是用高斯低通滤波器。
高斯函数如下:
OpenCV对应函数如下:
//! smooths the image using Gaussian filter.
CV_EXPORTS_W void GaussianBlur( InputArray src,
OutputArray dst, Size ksize,
double sigmaX, double sigmaY=0,
int borderType=BORDER_DEFAULT );
其中:
InputArray src:
OutputArray dst:输出图像,与输入图像有相同的类型和尺寸。
Size ksize: 高斯内核大小,这个尺寸与前面两个滤波kernel尺寸不同,ksize.width和ksize.height可以不相同但是这两个值必须为正奇数,如果这两个值为0,他们的值将由sigma计算。
double sigmaX: 高斯核函数在X方向上的标准偏差
double sigmaY=0:高斯核函数在Y方向上的标准偏差,如果sigmaY是0,则函数会自动将sigmaY的值设置为与sigmaX相同的值,如果sigmaX和sigmaY都是0,这两个值将由ksize.width和ksize.height计算而来。具体可以参考getGaussianKernel()函数查看具体细节。建议将size、sigmaX和sigmaY都指定出来。
int borderType=BORDER_DEFAULT : 有默认值BORDER_DEFAULT,如果没有特殊需要不用更改,具体可以参考borderInterpolate()函数。
四.中值滤波medianBlur()
中值滤波是一种典型的非线性滤波,是基于排序统计理论的一种能够有效抑制噪声的非线性信号处理技术,基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,让周围的像素值接近真实的值从而消除孤立的噪声点。该方法在取出脉冲噪声、椒盐噪声(二值图像上表现为使一些像素点变白,一些像素点变黑)的同时能保留图像的边缘细节。这些优良特性是线性滤波所不具备的。
中值滤波首先也得生成一个滤波模板,将该模板内的各像素值进行排序,生成单调上升或单调下降的二维数据序列,二维中值滤波输出为g(x, y)=medf{f(x-k, y-l),(k, l∈w)}
,其中f(x,y)
和g(x,y)
分别是原图像和处理后图像, w为输入的二维模板,能够在整幅图像上滑动,通常尺寸为3 * 3或5 * 5区域,也可以是不同的形状如线状、圆形、十字形、圆环形等。通过从图像中的二维模板取出奇数个数据进行排序,用排序后的中值取代要处理的数据即可。
中值滤波对消除椒盐噪声非常有效,能够克服线性滤波器带来的图像细节模糊等弊端,能够有效保护图像边缘信息,是非常经典的平滑噪声处理方法。在光学测量条纹图像的相位分析处理方法中有特殊作用,但在条纹中心分析方法中作用不大。
OpenCV对应函数如下:
//! smooths the image using median filter.
CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize );
其中:
- InputArray src: 输入图像,图像为1、3、4通道的图像,当模板尺寸为3或5时,图像深度只能为CV_8U、CV_16U、CV_32F中的一个,如而对于较大孔径尺寸的图片,图像深度只能是CV_8U;
- OutputArray dst:输出图像,尺寸和类型与输入图像一致,可以使用Mat::Clone以原图像为模板来初始化输出图像dst ;
- int ksize:滤波模板的尺寸大小,必须是大于1的奇数
五.双边滤波bilateralFilter()
双边滤波是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部处理的特点。之所以能够达到保边去噪的滤波效果是因为滤波器由两个函数构成:一个函数是由几何空间距离决定滤波器系数,另一个是由像素差值决定滤波器系数。
双边滤波器中,输出像素的值依赖于邻域像素的值的加权组合,其公式如下:
权重系数w(i,j,k,l)取决于定义域核
[站外图片上传中...(image-bf88e3-1515383334366)]
和值域核
的乘积,也就是
通俗来讲就是双边滤波模板主要有两个模板生成,第一个是高斯模板,第二个是以灰度级的差值作为函数系数生成的模板,然后这两个模板点乘就得到了最终的双边滤波模板,第一个模板是全局模板,所以只需要生成以西,第二个模板需要对每个像素都计算一次。双边滤波器比高斯滤波器多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素,这样就能对边缘附近的像素值予以保存,但是由于保存过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤除。
OpenCV中函数如下:
//! smooths the image using bilateral filter
CV_EXPORTS_W void bilateralFilter( InputArray src,
OutputArray dst, int d,
double sigmaColor, double sigmaSpace,
int borderType=BORDER_DEFAULT );
其中:
- InputArray src:输入图像,可以是Mat类型,图像必须是8位或浮点型单通道、三通道的图像。
- OutputArray dst:输出图像,和原图像有相同的尺寸和类型。
- int d:表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数,则函数会从第五个参数sigmaSpace计算该值。
- double sigmaColor:颜色空间过滤器的sigma值,这个参数的值越大,表明该像素邻域内有越宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
- double sigmaSpace:坐标空间中滤波器的sigma值,如果该值较大,则意味着颜色相近的较远的像素将相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当d>0时,d指定了邻域大小且与sigmaSpace无关,否则d正比于sigmaSpace.
- int borderType=BORDER_DEFAULT:
另一种形态:
//! smooths the image using adaptive bilateral filter
CV_EXPORTS_W void adaptiveBilateralFilter( InputArray src,
OutputArray dst, Size ksize,
double sigmaSpace, double maxSigmaColor = 20.0, Point anchor=Point(-1, -1),
int borderType=BORDER_DEFAULT );
双边滤波器可以很好的保存图像边缘细节而滤除掉低频分量的噪音,但是双边滤波器的效率不是太高,花费的时间相较于其他滤波器而言也比较长。
对于简单的滤波而言,可以将两个sigma值设置成相同的值,如果值<10,则对滤波器影响很小,如果值>150则会对滤波器产生较大的影响,会使图片看起来像卡通。