深度学习计算机视觉实战
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.1 线性滤波

图像滤波是指在尽可能少地破坏图片细节特征的条件下,降低目标图像的噪声的方法,在对图像数据进行预处理的时候经常会用到。图像滤波的效果直接决定了后续图像分析处理的效果。

在一幅图像中,高频部分是指图像中像素值落差很大的部分,如图像边缘。对于展示,高频部分图像的关键信息数据起到了重要的作用。低频部分是指像素值与旁边的像素值差异较小甚至没有差异的部分,如一幅图像中一片都是某种颜色的区域,对图像信息展示的影响较小。

在现实生活中,图片的信息或能量大部分集中在幅度谱的低频和中频段,而噪声多分布于较高的频段,因此图像中高频段的有用的信息经常被噪声淹没。图像处理的目的在于抽取图像中的有效特征,滤除图像中混入的噪声。在使用滤波器滤除噪声的时候,最重要的就是不能损坏图像中的重要信息,如边缘或轮廓,需要保持图像清晰的视觉效果。因此,降低高频段的噪声是设计图像滤波器的关键。

图像滤波器就是一个矩阵,矩阵的系数就是滤波器的权重,在滤波过程中使滤波器的矩阵与图像矩阵的对应点做乘加运算,得到滤波后的最终结果。

滤波器的处理过程可以表示为公式(3.1)。

其中, hkl)表示滤波核的函数(kernel), fxy)表示需要处理的源图像, gxy)表示处理之后的结果。

例如,一个4×4的图像与一个3×3的kernel相乘,计算结果如公式(3.2)所示。

将4×4图像左上角的3×3矩阵部分与kernel矩阵对应的数字相乘,将相乘后的结果相加,得到的结果是92。接着将kernel矩阵向右滑动一个像素,计算的结果是110,然后向下滑动一个单位计算下边三行与kernel的乘积,从左边开始计算,结果分别是86和104。

kernel的尺寸一般选择奇数,这样计算的结果就是kernel的中心点对应的位置。

根据核函数与原始图像运算的方式不同,分为线性滤波和非线性滤波。

线性滤波的原始图像与窗口的权重值之间通过加减乘除等线性运算得到目标图像;而非线性滤波则通过逻辑运算,如选取窗口区域内的最大值或中值作为目标图像的结果。

本节主要讲解线性滤波方法,如方框滤波、均值滤波和高斯滤波,非线性滤波将会在下一节介绍。

3.1.1 案例1:使用方框滤波

方框滤波是指计算核函数区域中像素的平均值,方框滤波的核函数表示为公式(3.3)。

其中,参数α表示为公式(3.4)。

公式(3.4)是一个高为Kheight ,宽为Kwidth的窗口函数,在此区域内的邻域中对像素值叠加求平均值,即可求出位于kernel中心点像素的像素值。

OpenCV提供了方框滤波函数boxFilter()。

C++版本对应的函数如下:

Python版本对应的函数如下:

对比发现,不同语言版本的接口是完全一样的,C++语言版本中需要将处理后的结果存储到参数dst中,而Python语言版本对应的处理结果可以直接返回,也可以存储到参数dst中。深度学习的算法开发以Python语言为主,因此在后续的OpenCV接口函数的讲解中,重点讲解Python语言版本,案例分享也以Python语言为主。

boxFilter函数对应的参数及其含义如表3.1所示(参数顺序以Python语言版本为准,下同,不再重复说明)。

表3.1

其中,borderType定义各种边界类型,由枚举类型BorderTypes定义,BorderTypes的定义如下:

下面介绍方框滤波的使用案例,本案例使用的源图像如图3.1所示。

图3.1

为了便于对比,需要用户手动给图片增加椒盐噪声,增加噪声的代码如下:

在 Python 中,经常需要使用已经封装好的模块或库,如 OpenCV 库。在 Python 中使用OpenCV库就需要引入cv2,引入方法就是通过import关键字。

同理可以引入随机数生成模块random。

对于有的模块,若觉得模块名称较长,输入不便,则可以取一个别名。例如,numpy模块在导入之后,重新命名为np,这样在后续使用中就不需要写numpy,只需要写np,其效果和调用numpy一样。

提示:numpy是矩阵操作的重要库,在深度学习中有着重要的作用。

此处用户定义了添加椒盐噪声的函数——add_sp_noise,该函数有两个参数,用于添加噪声的图像image和添加噪声的比例prob。

使用for循环遍历图像,若随机出来的值小于prob,则将该处像素值置为0(黑色),若随机出来的值大于1-prob,则将像素值置为255(白色),最后将得到的图像返回。

现在就可以读取如图3.1所示的输入图像,添加椒盐噪声了,代码如下:

添加椒盐噪声后的结果如图3.2所示。

图3.2

由图3.2可以看到,图片上有一些椒盐状的点,这些就是图片的噪声。

使用方框滤波,对上面这张有噪声的图片进行处理,代码如下:

以上代码中传给方框滤波函数boxFilter的参数有三个:

(1)noise,表示前面增加了椒盐噪声的图片对象。

(2)-1是ddepth的值,表示处理后的目标图像的深度,此处设置ddepth为-1,即目标图像深度与源图像深度相同。

(3)(3,3),表示滤波的核(kernel)的大小,这里使用的是3×3的kernel。

这三个参数是必不可少的,其他参数都使用默认值。使用3×3的kernel进行方框滤波后得到的图像结果如图3.3所示。

图3.3

可以发现,噪声点得到了一些抑制,但是图片也相对模糊了。

若使用的kernel为1×1,则输出的图像就是源图像。使用的kernel越大,图片模糊的情况越严重。按如下代码设置方框滤波使用15×15的kernel。

使用15×15的kernel的方框滤波得到的图像结果如图3.4所示。

图3.4

这是因为,对于3×3的kernel,方框滤波计算的是以计算点为中心,大小为3×3范围内的像素值的平均值,这自然会使得目标点(或锚点)的像素值被周边的像素值平均化,细节就不那么清晰了。当kernel的大小选择为15×15的时候,线条等细节已经被完全模糊,所以方框滤波也可以用于图像的模糊。

3.1.2 案例2:使用均值滤波

均值滤波是方框滤波的一种,即对滤波核使用标准化操作。在接口调用时,其效果和调用boxFilter()并将normalize设置为true是一样的。

OpenCV提供了均值滤波函数blur()。

C++版本对应的函数如下:

Python版本对应的函数如下:

blur函数对应的参数及其含义如表3.2所示。

表3.2

下面介绍均值滤波的使用案例。

其中添加椒盐噪声的方法可以参见3.1.1节,使用3×3的kernel进行均值滤波后的图像结果如图3.5所示。

图3.5

使用15×15的kernel进行均值滤波后的图像结果如图3.6所示。

图3.6

方框滤波和均值滤波在使图像的噪声得到滤除时,也使图像的细节变得模糊。

3.1.3 案例3:使用高斯滤波

高斯滤波使用高斯函数作为滤波器的核。高斯核的计算比方框滤波和均值滤波复杂得多,需要根据核的大小和高斯函数中的方差σ由二维高斯核函数计算出高斯核。具体的计算过程这里不做深入讲解,有兴趣的用户可以自行研究其实现细节。常见的高斯核的参数是固定的,公式(3.5)和公式(3.6)介绍了3×3和5×5的高斯核。

常见的3×3的高斯核为

常见的5×5的高斯核为

OpenCV提供了高斯滤波函数GaussianBlur()。

C++版本对应的函数如下:

Python版本对应的函数如下:

GaussicnBlur函数对应的参数及其含义如表3.3所示。

表3.3

由表3.3可以看出,sigmaY 可以使用默认值,如果调用时不指定 sigmaY,那么它的值就设置为和sigmaX相同。如果sigmaX和sigmaY都设置为0.0,那么会通过高斯核的大小进行计算。

下面介绍高斯滤波的使用案例。

其中添加椒盐噪声的方法可以参见3.1.1节,使用3×3的kernel进行高斯滤波后的图像结果如图3.7所示。

图3.7

使用15×15的kernel进行高斯滤波后的图像结果如图3.8所示。

对比方框滤波,高斯滤波在对图像进行滤波的时候,能够保留更多的图像细节信息。因此对于图像去噪,高斯滤波的效果更好,而方框滤波则更多用于图像模糊。

图3.8