【OpenCV图像处理】十五、图像空域滤波(上)

1.空域滤波介绍

空域滤波是一种邻域处理方法,通过直接在图像空间中对邻域内像素进行处理,达到平滑或锐化图像的作用。此外,在图像识别中,通过滤波还可以抽出图像的特征作为图像识别的特征模式。

空域滤波是图像处理领域中广泛使用的主要工具。空域滤波主要可以分为线性滤波和非线性滤波,其中,线性滤波和频域滤波存在一一对应的关系。但是,空域滤波可以用于非线性滤波,但是频域滤波不能用于非线性滤波

从根源上讲,滤波这一词语来自于频域,信号处理中频域滤波指的是允许或者限制一定的频率成分通过。但空域滤波直接在图像空间中增强图像的某些特征或者减弱图像的某些特征。

空域滤波的作用域是像素及其邻域,通常使用空域模板对邻域内的像素进行处理从而产生该像素的输出值。

线性空域滤波指的是像素的输出值是计算该像素邻域内像素值的线性组合,系数矩阵在这里我们称之为模板。由信号处理的原理可以得出,线性滤波可以用卷积来实现。因此,在数字图像处理中,线性滤波通常是利用滤波模板与图像的空域进行卷积来实现的,在线性滤波中滤波模板也称为卷积模板

根据空域卷积的定义可以知道,卷积首先需要将模板进行反褶,也就是将模板绕模板中心旋转180°,但是在数字图像处理中,卷积模板通常是关于原点对称的,因此通常不需要考虑反褶过程。模板卷积的主要步骤包括如下几个步骤,

(a.将模板在图像中进行遍历,将模板中心和各个像素位置重合;

(b.将模板的各个系数与模板对应像素值进行相乘;

(c.将所有的乘积相加,并将求和结果赋值于模板中心对应的像素

对于尺寸为m*n的模板,线性滤波在图像中像素(x,y)处的相应输出g(x,y)的一般表达式如下:


上式中,w(s,t)和f(x+s,y+t)分别为模板系数和模板对应像素,其中,为了保证唯一坐标s和t是整数,要求m和n是奇数。在一般情况下,线性滤波选取尺寸为奇数的正方形模板。

为了方便进行描述,设模板的尺寸为mxn,线性滤波在像素(x,y)处的相应输出R的另一种简单化表示为:
【OpenCV图像处理】十五、图像空域滤波(上)_第1张图片

上式中wi表示的是模板系数,zi表示与模板系数对应的像素值,这里i = 1,2,3,...,mn,mn这里指的是模板对应的像素总数。

在非线性空域滤波中也是采用基于邻域的处理,而且模板滑过一幅图像的机理和线性空域滤波是一致的。非线性滤波处理也取决于模板对应的邻域内的像素,然而,因为不能直接利用上面g(x,y)的表达式计算乘积求和。例如非常有用的中值滤波,它是将模板对应的邻域内的像素值进行排序,然后查找中间值。利用这种方法可以有效地去除椒盐噪声,但是因为非线性滤波涉及到了像素值的排序操作,因此它的时间开销要比线性滤波的大。

对于实现空域滤波的最后一个问题是对于图像边界像素邻域的处理。对于尺寸为n*n的空域模板,当模板中心距离图像边界为(n-1)/2像素时,该模板正好在图像的内部。如果模板的中心继续像图像外边界靠近,那么模板的行或列就会超出图像之外。因此常常采用延拓的方式解决外边界问题。常用的方法有四种,分别是补零、重复、对称和循环方式,补零是指通过补零来扩展图像。重复是指通过复制外边界的值来扩展图像,对称是指通过镜像反射外边界的值来扩展图像,循环是指将图像看成二维周期函数的一个周期来扩展。在空域滤波完成后,从处理后的图像裁剪出与源图像对应的部分,使处理后的图像与源图像的尺寸相等。


2.图像平滑

图像平滑的作用是对图像进行模糊和降噪。其中图像平滑的模糊处理经常用于图像的预处理阶段,例如,为了提取较大的目标,通过模糊处理平滑一些细节和纹理、桥接直线和曲线的缝隙。因为噪声的特性造成图像灰度的突变,因此,图像的平滑处理也可以起到降低噪声的作用,但是,在模糊和降噪的同时,图像中的边缘和细节的锐度也都丢失了,也就是说,在平滑的过程中,使得图像的一部分细节信息丢失。在通常情况下,图像的平滑有两种主要的方法:

线性平滑滤波和统计排序平滑滤波。其中线性平滑滤波适用于降低图像中的高斯噪声,而统计排序平滑滤波对滤除脉冲噪声非常有效。   

其中,线性滤波是现实将空域模板对应邻域内像素的灰度值加权之和作为邻域内中心像素的相应输出。线性平滑模板的权系数全为正值而且系数之和等于1,因此这种方法不会增加图像中总体的灰度程度。也就是说在灰度一致的区域,线性平滑滤波的相应输出不变。此外,可以知道,线性平滑滤波等效于低通滤波。

最简单的线性平滑滤波使用的模板是均值平滑模板。如下图所示均值模板的尺寸为3x3,权系数全为1,为了让权系数之和等于1,模板系数需要再乘以归一化因子1/9

【OpenCV图像处理】十五、图像空域滤波(上)_第2张图片

但是,通过对上面这个模板进行频域分析可以知道,均值平滑模板具有旁瓣泄漏效应,反应在图像中就是振铃效应,且模板尺寸越大,振铃效应也就越明显。

另一种更为重要的平滑模板是加权平均模板,指的是模板中不同的位置对应的像素具有不同的权值数,其中,最常用的就是高斯平滑模板。对应模板中心像素的响应输出,显然中心像素的灰度值比周围图像像素的灰度值更重要,因此给模板中心对应的像素赋予最大的权系数,随着模板对应的像素到中心位置的距离增大而减小权系数。下图是3x3的高斯平滑模板。

【OpenCV图像处理】十五、图像空域滤波(上)_第3张图片

如上图,中心像素的权系数是4,由于4邻域的像素到中心位置的距离为1,而对角邻域的像素到中心位置的距离为√2,对角邻域的像素比4邻域的像素到中心位置的距离更远,因此,4邻域像素的权系数为2,而对角邻域像素的权系数为1。最后乘以1/16是为了对模板进行归一化。

下面分别介绍一下在OpenCV中各种空域滤波函数的使用和实现。

①方框滤波:boxFilter()

方框滤波函数的作用是使用方框滤波(box filter)来模糊一张图片,原理是指定一个XY的矩阵大小,目标像素的周围XY矩阵内的像素全部相加作为目标像素的值,方框滤波所用到的核如下:

【OpenCV图像处理】十五、图像空域滤波(上)_第4张图片

其中,α为

【OpenCV图像处理】十五、图像空域滤波(上)_第5张图片


当normalize为true时,方框滤波也就成了均值滤波。也就是说均值滤波是方框滤波归一化后的特殊情况。归一化就是将要处理的量缩放到一定范围,比如(0,1),以便统一处理和直观量化。而非归一化的方框滤波用于计算每个像素邻域内的积分特性,比如光流法中用到的图像倒数的协方差矩阵。如果要在可变窗口中计算像素总和,可以使用integral()函数。

因此它在OpenCV中的内部实现借鉴了积分图像的原理思想,在快速积分图像求解中,将计算某个矩阵像素间的和值运算转换为求矩阵对应边角点的求和差值运算。在实现中最关键的步骤就是初始化起始数组S,数组D的每个值是存放的像素邻域内的像素和值,在求解某矩形块中的像素和时,只需要索引对应区域的位置存放的和值就可以完成计算。

函数原型如下:

void boxFilter( InputArray src, OutputArray dst, int ddepth, Size ksize, Point anchor=Point(-1,-1), bool normalize=true,
                             int borderType=BORDER_DEFAULT );
相关参数意义如下:

第一个参数 src表示输入图像,使用Mat类的对象即可。这个图像对通道是独立处理的,而且可以处理任意通道数的图像。但是需要注意的是,待处理的图像深度应该为CV_8U、CV_16U、CV_16S、CV_32F以及CV_64F之一。

第二个参数dst表示目标图像,需要和原图像有一样的尺寸和类型。

第三个参数是int类型的ddepth,表示的是输出图像的深度,-1代表的是使用源图像的深度,也就是src.depth()。

第四个参数是Size类型的ksize,表示的是内核的大小,我们一般使用size(w,h)来表示内核的大小,其中w是像素的宽度,h是像素的高度

第五个参数是Point类型的anchor,表示锚点(目标点,也就是此刻被滤波处理的点)。有默认值(-1,-1)。如果这个点的坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在这个核的中心。

第六个参数是bool类型的normalize,有默认值true,表示的是是否对内核进行归一化处理。

最后一个参数是int类型的borderType,表示的是扩展边界的类型,有默认值BORDER_DEFAULT,通常直接使用默认值即可。

以下为相关使用范例

//使用boxFilter实现方框滤波
#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;

int main()
{
	Mat srcImage = imread("2345.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片有误!" << endl;
		system("pause");
		return -1;
	}
	imshow("原始图像", srcImage);
	//进行滤波相关处理
	Mat dstImage(srcImage.size(), srcImage.type());
	boxFilter(srcImage, dstImage, -1, Size(5, 5));
	//显示效果
	imshow("方框滤波效果图", dstImage);
	waitKey();
	return 0;
}
执行后的效果如下:

【OpenCV图像处理】十五、图像空域滤波(上)_第6张图片

如上,因为在方框滤波中将参数normalize设置为使用默认参数true,此时方框滤波的效果等同于均值滤波。图像整体上达到了平滑的效果,滤除了部分高频信息,使得部分细节丢失。


②均值滤波

均值滤波是指使用模板核算子覆盖区域内所有像素的加权平均,它用一个点邻域内像素的平均灰度值来代替这个点的灰度,常见的核算子有3x3,此时模板区域内的元素有9个,均值滤波就是也就是指当前中心像素点的值用1/9(a1+a2+...+a9)来代替。

均值滤波处理比较简单,因此计算速度比较快,但是均值滤波本身存在着固有的缺陷(振铃效应明显),因此不能很好地保护图像的细节,在图像去噪的同时也破坏了图像的细节部分,从而使得图像变得模糊,导致不能很好地去除噪声点。

OpenCV中使用blur()函数来实现均值滤波,也称为归一化滤波器,函数的声明如下:

void blur( InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT );
可以看出,blur函数的定义和boxFilter函数十分类似,只是缺少了一个参数ddepth,其余参数表示的意义和boxFilter函数中参数表示的意义相同。在这里就不再做过多赘述。

相关使用范例如下:

//使用blur函数实现图像均值滤波
#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;

int main()
{
	Mat srcImage = imread("2345.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片有误!" << endl;
		system("pause");
		return -1;
	}
	imshow("原始图像", srcImage);
	//进行滤波相关处理
	Mat dstImage(srcImage.size(), srcImage.type());
	blur(srcImage, dstImage, Size(5, 5), Point(-1, -1), 1);
	//显示效果
	imshow("方框滤波效果图", dstImage);
	waitKey();
	return 0;
}
执行程序后的效果如下:

【OpenCV图像处理】十五、图像空域滤波(上)_第7张图片

可以看出,滤波的效果和上面的方框滤波效果相同。


③高斯滤波

因为高斯滤波是将输入数组的每一个像素点和高斯内核进行卷积运算,再将卷积和当做输出的像素值。高斯滤波后图像被平滑的程度取决于使用高斯函数的标准差。它的输出是邻域的加权平均,因此相对于均值滤波来说,高斯滤波的平滑效果更加柔和,而且边缘保留的也更好。在图像处理中,高斯滤波一般有两种实现方式,一种是用离散化窗口进行滑窗卷积,另一种是利用傅里叶变换。通常直接使用第一种滑窗实现的方法,只有当离散化的窗口非常大时,导致用滑窗计算量非常大(即使用可分离的滤波器实现)的情况下,可能会考虑傅里叶变化的实现方法。高斯滤波是最有用的滤波器,具有下面的性质:

(a.高斯函数是单值函数,高斯滤波使用像素邻域加权均值来代替该点的像素值,像素权重会随着距离的变化而单调递减,以此来减少失真现象。

(b.高斯函数具有旋转对称性,高斯滤波在各个方向上的平滑程度是相同的,对于存在的噪声很难估计其方向性,保证平滑性能不会偏向任何方向。

(c.高斯函数的傅里叶频谱是单瓣的,使得平滑图像不会被不需要的高频信号所影响,同时保留了大部分所需要的信号。

(d.高斯滤波的平滑程度是由方差σ决定的,σ越大,频带也就越宽,从而平滑的程度也就越大,对于图像中的噪声有可以控制的参数进行设置。

(e.高斯函数具有可分离性,二维高斯函数卷积可以分为两步来进行,首先将图像和一维高斯函数进行卷积运算,然后将卷积结果和方向垂直的相同一维高斯函数进行卷积。

在OpenCV中使用GuassianBlur()函数来实现高斯平滑,函数的声明如下:

void GaussianBlur( InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0, int borderType=BORDER_DEFAULT );

这里需要说明的参数是第四个参数,double类型的sigmaX,表示的是高斯核函数在X方向上的标准偏差。

第五个参数double类型的sigmaY有默认值0,参数的意义是表示高斯核函数在Y方向上的标准偏差,如果这个参数使用默认值0,就将这个参数设置为sigmaX,如果sigmaX和sigmaY都设置为0,那么就使用ksize.width和ksize.height计算出来。为了计算的正确性,通常都是把第三个参数Size,第四个参数sigmaX和第五个参数sigmaY全部指定出来。

具体的使用程序如下:

//使用blur函数实现图像均值滤波
#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;

int main()
{
	Mat srcImage = imread("2345.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片有误!" << endl;
		system("pause");
		return -1;
	}
	imshow("原始图像", srcImage);
	//进行滤波相关处理
	Mat dstImage(srcImage.size(), srcImage.type());
	GaussianBlur(srcImage, dstImage, Size(3, 3),0,0);
	//显示效果
	imshow("高斯滤波效果图", dstImage);
	waitKey();
	return 0;
}

执行程序后的结果如下:

【OpenCV图像处理】十五、图像空域滤波(上)_第8张图片

可以看出,使用高斯核函数进行平滑处理能比用均值滤波保留更多的细节信息。


④双边滤波

双边滤波(Bilateral Filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素相似度的的一种折中处理。它是一种保持边缘的非迭代平滑滤波方法。它的权系数由空域(Spatial domain)S和值域(Range domain)R平滑函数的乘积给出。随着中心像素的距离和灰度差值的增大,邻域像素的权系数逐渐减小。具有简单、非迭代和局部性的特点。

双边滤波的好处是可以进行边缘保存(Edge preserving)。以往常用维纳滤波或者高斯滤波进行去降噪,但是二者都会比较明显的模糊边缘,对于高频细节的保护效果并不明显。双边滤波顾名思义,它比高斯滤波多了一个高斯方差sigma——d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离得较远的像素不会对边缘上的像素值影响太多,这样也就保证了边缘附近像素值的保存。但是由于彩色图像里存在的高频噪声,双边滤波不能够干净地进行滤除,只能对低频信息进行较好的滤波

具体说明如下:

我们假设高斯函数的表达式如下:

【OpenCV图像处理】十五、图像空域滤波(上)_第9张图片

其中W是权重,i和j表示像素的索引,K是归一化的常量,相当于√2πσ,指数分母的部分相当于2σ^2,从上面的公式中可以很明显的看出,权重只和像素之间的空间距离有关系,无论图像的内容是什么,都有相同的滤波效果。

对比下面给出的双边滤波器,它只是在原有高斯函数的基础上增加了一项

【OpenCV图像处理】十五、图像空域滤波(上)_第10张图片

其中,I是像素的灰度值,根据指数函数的特点,e^(f(x))应该是一个关于f(x)的单调递减函数,所以在灰度差距大的地方(例如边缘)权重反而会变小,从而滤波效应也就变小。总体上来讲,在像素灰度过度缓和的区域,双边滤波有类似于高斯滤波的效果,而在图像边缘等梯度较大的地方,则有保持的效果。

对于数字图像而言,滤波处理最终体现为一种利用模板来进行卷积运算的形式,二者其实就表明输出像素的值依赖于邻域像素的值得加权组合,可以用下面式子来进行描述:

【OpenCV图像处理】十五、图像空域滤波(上)_第11张图片

其中,权重系数ω(i,j,k,l)取决于定义域核

【OpenCV图像处理】十五、图像空域滤波(上)_第12张图片

和值域核

【OpenCV图像处理】十五、图像空域滤波(上)_第13张图片

的乘积


如下图,图(a)表示的是两个各自过渡缓和的区域(每个区域中都包含有噪声),交接处有一条尖锐的边缘。图(b)表示的是一个双边滤波器(它的一般看起来就像一个高斯滤波器的半边),利用这样一个滤波器对图(a)进行处理。

而之所以将这种滤波器称之为“双边滤波器”,是因为其实它是空间位置和灰度差距两种滤波器的组合。在使用双边滤波器进行滤波处理时,在处理非边缘区域时,小邻域内的像素值都是彼此差距不大的,这时双边滤波器等同于一个标准的空域高斯滤波器,进而平滑掉那些由于噪声引起的弱的相关值,也就是利用图中双边滤波器的右半边来处理非边缘区域内的噪声。而面对灰度值变换剧烈的边缘区域时,则使用双边滤波器的左半边来进行处理,这时边缘信息就能够较好的保存下来。

【OpenCV图像处理】十五、图像空域滤波(上)_第14张图片

下面举一个定义域滤波和值域滤波的例子

【OpenCV图像处理】十五、图像空域滤波(上)_第15张图片【OpenCV图像处理】十五、图像空域滤波(上)_第16张图片

下面介绍在OpenCV中使用双边滤波的方法

OpenCV中使用bilateralFilter()函数对图像进行双边滤波,函数的声明如下:

void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );
第一个参数src表示输入的图像,也就是源图像,需要是8位或者浮点型单通道、三通道的图像。

第二个参数dst表示输出的图像,也就是目标图像,需要和源图像有一样的尺寸和类型。

第三个参数是int类型的d,表示在过滤过程中每个像素邻域的直径,如果这个参数被设定为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它。

第四个参数是double类型的sigmaColor,是颜色空间滤波器sigma的值,这个参数的值越大,也就表示该像素邻域内有越宽广的颜色会被混合到一起,会产生较大的半径相等颜色区域。
第五个参数sigmaSpace表示坐标空间中滤波器sigma的值,这个参数的值越大,就表明越远的像素会互相影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当d>0时,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。

第六个参数是int类型borderType,用于腿短图像外部像素的某种边界模式,有默认值BORDER_DEFAULT


具体使用程序如下:

//使用bilateralFilter函数实现对图像的双边滤波
#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;

int main()
{
	//载入原图
	Mat srcImage = imread("2345.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片有误!" << endl;
		system("pause");
		return 0;
	}
	imshow("原始图像", srcImage);
	//进行双边滤波操作
	Mat dstImage(srcImage.size(), srcImage.type());
	bilateralFilter(srcImage, dstImage, 25, 25 * 2, 25 / 2);
	imshow("双边滤波效果图", dstImage);
	waitKey();
	return 0;
}

程序执行后的效果如下:

【OpenCV图像处理】十五、图像空域滤波(上)_第17张图片

可以看出,在滤除原图像中平整部分的噪声的同时,也较好的保留了原图像中的边缘信息。

在OpenCV中,除了bilateralFilter()函数外,还有另一个与双边滤波相关的函数,即adaptiveBilateralFilter(),这个函数的作用是实现自适应双边滤波器,在这里简单介绍一下。函数的声明如下:

adaptiveBilateralFilter( InputArray src, OutputArray dst, Size ksize, double sigmaSpace, double maxSigmaColor = 20.0,
                           Point anchor=Point(-1, -1), int borderType=BORDER_DEFAULT );
src为输入原图像;dst为滤波后的图像;ksize为滤波内核的大小;sigmaSpace为距离权值公式中的方差;maxSigmaColor为相似度权值公式中的方差(σr)的最大值,自适应双边滤波的相似度方差是通过公式计算得到,但如果计算的结果太大,超过了该值,则以该值为准;anchor为内核锚点;borderType表示用什么方式来处理加宽后的图像四周边界。

⑤中值滤波

中值滤波是一种典型的非线性滤波技术,它是统计排序滤波的一种。统计排序滤波是一种非线性滤波方法,它是将模板对应的邻域内像素的灰度值进行排序,然后将统计排序结果作为模板中心对应像素的输出值。其中最常见的就是中值滤波,顾名思义,它是使用排序后的中值对对应的像素进行赋值,除此之外,还有最大值滤波,最小值滤波,自适应中值滤波,α剪裁滤波等等。这里主要介绍一下中值滤波,其余的统计排序滤波做简要介绍。

设Sxy表示以像素(x,y)为中心的邻域的集合,中值滤波在像素(x,y)处的输出g(x,y)为:


上式中,median{·}表示中间查找操作。对一幅图像进行中值滤波的步骤如下:

(a.将模板在图像中遍历

(b.将模板对应的邻域内像素的灰度值排序

(c.查找中间值,将其赋于模板中心对应的像素

例如,在3x3的邻域中,中间值是灰度值排序后的第5个值,在5x5的邻域中,中间值是第13个值。当邻域中具有多个相同灰度值的像素时,可以选取其中任何一个作为中间值。由于中值滤波需要对像素值进行排序,因此他的计算时间一般比线性滤波要长,尤其是对于较大尺寸的模板。

中值滤波是一种去除噪声的非线性处理方法,一般情况下,中值滤波的结果要优于线性滤波,线性平滑滤波具有低通滤波的特性,在降噪的同时也会模糊图像的边缘细节。但是中值滤波不会改变信号中的阶跃变化,因此能够平滑信号中的噪声,同事又不会模糊信号的边缘信息,这个性质使得它能够很好的使用与图像空域滤波的相关应用。当噪声的特性未知时,中值滤波又具有较强的鲁棒性,能够很好地适应各种数据的平滑处理。特别的,中值滤波的冲激响应为0,这个性质使得中值滤波在抑制脉冲噪声方面非常有有效。

中值滤波的直观解释就是使模板中心位置对应像素的灰度值更加接近它周围像素的灰度值,依次来消除孤立的亮点或暗点。由于脉冲噪声的形式是以孤立的黑白像素叠加在图像上,在图像处理中常称为椒盐噪声,为了完全滤除椒盐噪声,n x n的模板的中值滤波处理要求邻域内孤立亮点或暗点的像素数小于n^2/2,很明显,也就是要求噪声像素的数量要小于邻域内像素数的一半,中值滤波的模板形状和尺寸应该根据图像的特性和处理目的来确定,下面给出了几种常用的中值滤波模板形状,其中,模板尺寸为5。


在OpenCV中使用函数medianBlur()来实现中值滤波操作,其声明如下:

void medianBlur( InputArray src, OutputArray dst, int ksize );
第一个参数src表示输入的源图像,可以使用1,3或者4通道的Mat类型的图像。当ksize=3或5时,图像的深度需为CV_8U、CV_16U、CV_32F其中之一,而对于较大孔径尺寸的图片,它只能是CV_8U。

第二个参数dst表示输出的目标图像,也就是滤波后的图像,和源图像有一样的尺寸和类型。

第三个参数ksize表示中值滤波所使用的孔径的线性尺寸,需要注意的是,这个参数必须是大于1的奇数。

具体使用程序如下:

//利用medianBlur函数对图像进行去噪
#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;

int main()
{
	Mat srcImage = imread("salt_pepper_Image.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片有误!" << endl;
		system("pause");
		return 0;
	}
	imshow("原始图像", srcImage);
	//进行中值滤波处理
	Mat dstImage;
	medianBlur(srcImage, dstImage, 7);
	imshow("中值滤波后图像", dstImage);
	waitKey();
	return 0;
}

程序执行后的效果如下:

【OpenCV图像处理】十五、图像空域滤波(上)_第18张图片

可以看出,经过中值滤波处理后,被椒盐噪声污染的图像得到了明显的改善。


下面简单的介绍一下其他的统计排序滤波方法

(1.最大值滤波与最小值滤波

中值滤波是统计排序滤波的一个特例,所谓中值就是一序列像素值排序中第50%个值。显然,统计排序滤波也可以选取排序中其他位置的像素。将模板对应的邻域内像素值按照递增的顺序进行排列,选取第100%个值就是最大值滤波,设Sxy表示以像素(x,y)为中心的邻域像素集合,最大值滤波在像素(x,y)处的输出g(x,y)为:


显然,最大值滤波的输出值是邻域内像素的最亮点,因此,最大值滤波能够有效地滤除椒噪声。相反的选取处于0%的值就是最小值滤波器,最小值滤波器在像素(x,y)处的输出g(x,y)为


最小值滤波输出是邻域内像素的最暗点,因此,最小值滤波能够有效地滤除盐噪声


(2.自适应中值滤波

中值滤波在任何情况下都将固定储存模板对应的图像中邻域内像素的中间灰度值作为模板中心对应像素的输出值,可能引起的问题是边缘细节的失真。而自适应中值滤波是在中值滤波的过程中自适应的调整中值滤波的输出值。自适应中值滤波能够去除较大概率的脉冲噪声名并平滑非脉冲噪声,与此同时又能够保持图像中的边缘和细节,这是中值滤波所做不到的。

设f(x,y)表示输入图像在像素(x,y)处的灰度值,g(x,y)表示输出图像在像素(x,y)处的灰度值,Sxy表示中心在像素(x,y)处的邻域像素几何,Zmin、Zmax和Zmed分别表示邻域像素几何Sxy中的灰度最小值,灰度最大值和灰度中值,Smax表示允许的最大模板尺寸,自适应中值滤波包括两个阶段:阶段A和阶段B

阶段A:

( A1 = Zmed - Zmin;

( A2 = Zmed - Zmax;

(若A1>0而且A2<0,则转到阶段B,否则,增大模板的尺寸;

阶段B:

(B1 = f(x,y) - Zmin;

(B2 = f(x,y) - Zmax;

(若B1>0且B2<0,则输出g(x,y) = f(x,y);否则,输出g(x,y) = Zmed;

说明:

阶段A计算中值滤波的输出Zmed并判断其是否为脉冲噪声。若条件A1>0且A2<0成立,Zmin < Zmed 0且B2<0成立,Zmin < f(x,y) < Zmax,则f(x,y)不是脉冲噪声,在这种条件下,输出的灰度值保持不变,也就是g(x,y) = f(x,y)。通过不改变这些非脉冲噪声的像素来降低边缘和细节的失真。若条件B1> 0且B2 <0不成立,f(x,y) = Zmin或f(x,y) = Zmax,也就是说f(x,y)为脉冲噪声,在这种条件下,输出为阶段A中计算的中间值Zmed,即g(x,y) = Zmed,也就是中值滤波的输出,通过赋予邻域内像素的中间值来消除脉冲噪声。从A阶段可以看出,Zmed不是脉冲噪声。

若A阶段中的条件A1>0或A2<0不成立,则终止滤波的输出Zmed为脉冲噪声,在这种条件下,增大模板的尺寸并重复执行阶段A,继续阶段A的循环知道邻域内像素的中间值Zmed并非脉冲噪声从而可以转到阶段B,或者达到允许的最大模板尺寸Smax。若达到了最大模板尺寸Smax,则将Zmed作为像素(x,y)的输出。在这种情况下,不能保证这个输出值为非脉冲噪声。显然,随着噪声概率的增大,影增大允许的最大模板尺寸Smax。图像受干扰的噪声概率越小,或者允许的最大模板尺寸越大,自适应中值滤波过程发生提前终止的可能性越大。


(3.α剪裁均值滤波

α剪裁均值滤波是一种结合中值滤波和均值平滑滤波的非线性滤波方法,它是将模板对应的邻域内像素的灰度值进行排序,排除一定数量的处于排序中首尾位置的灰度值,然后计算其余像素的平均灰度值。

设模板尺寸为mxn,Sxy表示中心在像素(x,y)处的邻域像素集合,fr(s,t)表示排除邻域像素集合Sxy中前d/2个灰度最大值和前d/2个灰度最小值而剩余的mn-d个像素值,α剪裁滤波在像素(x,y)处的输出g(x,y)为:

【OpenCV图像处理】十五、图像空域滤波(上)_第19张图片

其中,d为[0,mn-1]之间的偶数。当d=0时,α剪裁滤波退化成为均值滤波,当d=mn-1时,α剪裁滤波被退化为中值滤波。当d取其他值时,α剪裁滤波在包括多种噪声的抢矿下很有效,例如高斯噪声和椒盐噪声混合的情况。


你可能感兴趣的:(OpenCV,图像处理)