前言

在介绍滤波之前先简单的说下图像噪音和卷积。

图像噪声:是指存在于图像数据中的不必要的或多余的干扰信息。各类图像处理系统在图像的采集、获取、传送和转换(如成像、复制扫描、传输以及显示等)过程中,均处在复杂的环境中,光照、电磁多变,所有的图像均不同程度地被可见或不可见的噪声干扰,导致图像质量的下降,掩盖图片重要细节

而图像噪声的去除在数字图像处理技术中的重要性越来越明显,如高放大倍数航片的判读,X射线图像系统中的噪声去除等已经成为不可缺少的技术步骤。

卷积:其实就是一个带权值的n维矩阵(这里也叫滤波器)在图像的像素图上滚来滚去对每个像素点进行加权运算,滚完了滤波也就做完了,如下图:

python去除图像的噪声 图像去噪opencv_高斯滤波

模糊图像

众所周知,图片其实是有千万个像素组成的,而每个像素点,其实就是表示图像的二维数组中的每个房间地址。灰度值,就是每个房间中的值。在图像的生成过程中,由于不可控因素,会造成临近灰度值所形成的函数的导数过大——也就是噪声,让其与真实颜色产生误差,掩盖图片细节,之后的各种后期图像处理便会不断放大这种误差。而滤波则是对图片预处理时消除噪音的一种重要方式。

模糊操作时图像处理中最简单和常用的操作之一,使用该操作的原因之一就为了给图像预处理时减低噪声。

使用模糊操作的背后是数学的卷积计算:

python去除图像的噪声 图像去噪opencv_高斯滤波_02


其中权重核h(k,l)h(k,l)为“滤波系数”。上面的式子可以简记为:

python去除图像的噪声 图像去噪opencv_python去除图像的噪声_03


通常这些卷积算子计算都是线性操作,所以又叫线性滤波。

4种模糊技术

均值滤波(blut):
中值滤波(medianBlurr):非常适合去除椒盐噪声或者斑点噪声。
高斯滤波(GaussianBlur):适合边缘检测的预处理阶段。
双边滤波(bilateralFilter):可以做边缘保存(edge preserving)(如果用高斯滤波去降噪,会较明显地模糊边缘)但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。

均值滤波

这是通过将图像与标准化的盒式过滤器进行卷积来完成的。它只取内核区域下所有像素的平均值并替换中心元素。这是由函数cv.blur()或cv.boxFilter()完成的。我们应该指定内核的宽度和高度。3x3标准化的盒式过滤器如下所示:

python去除图像的噪声 图像去噪opencv_卷积_04


以(2,2)像素点为例。

python去除图像的噪声 图像去噪opencv_python去除图像的噪声_05


则滤波后的结果为:

python去除图像的噪声 图像去噪opencv_python去除图像的噪声_06


滤波后(2,2)像素点的值由 10 变为 3

最终结果:

python去除图像的噪声 图像去噪opencv_卷积_07


**由于图像边框上的像素无法被模板覆盖,所以不做处理。 这当然造成了图像边缘的缺失 **

代码举例:

img = cv.imread('opencv-logo-white.png')
blur = cv.blur(img,(5,5))
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title(' blur ')
plt.xticks([]),plt.yticks([])
plt.show()

结果:

python去除图像的噪声 图像去噪opencv_高斯滤波_08

高斯滤波

概念

高斯滤波在图像处理概念下,将图像频域处理和时域处理相联系,作为低通滤波器使用,可以将低频能量(比如噪声)滤去,起到图像平滑作用。

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值用。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。

高斯模糊:
我们常说的高斯模糊就是使用高斯滤波器完成的,高斯模糊是低通滤波的一种,也就是滤波函数是低通高斯函数,但是高斯滤波是指用高斯函数作为滤波函数,至于是不是模糊,要看是高斯低通还是高斯高通,低通就是模糊,高通就是锐化。

算法步骤

在图像处理中,高斯滤波一般有两种实现方式,一是用离散化窗口滑窗卷积,另一种通过傅里叶变换。最常见的就是第一种滑窗实现,只有当离散化的窗口非常大,用滑窗计算量非常大(即使用可分离滤波器的实现)的情况下,可能会考虑基于傅里叶变化的实现方法。

由于高斯函数可以写成可分离的形式,因此可以采用可分离滤波器实现来加速。所谓的可分离滤波器,就是可以把多维的卷积化成多个一维卷积。具体到二维的高斯滤波,就是指先对行做一维卷积,再对列做一维卷积。这样就可以将计算复杂度从O(M * M * N * N)降到O(2 * M * M * N),M,N分别是图像和滤波器的窗口大小。

高斯模糊是一个非常典型的图像卷积例子,本质上,高斯模糊就是将(灰度)图像 I 和一个高斯核进行卷积操作:

python去除图像的噪声 图像去噪opencv_卷积_09


其中 * 表示卷积操作; Gσ 是标准差为σ 的二维高斯核,定义为:

python去除图像的噪声 图像去噪opencv_高斯滤波_10


平均的过程:对于图像来说,进行平滑和模糊,就是利用周边像素的平均值:

python去除图像的噪声 图像去噪opencv_权重_11


“中间点”取”周围点”的平均值,就会变成1。在数值上,这是一种”平滑化”。在图形上,就相当于产生”模糊”效果,”中间点”失去细节。显然,计算平均值时,取值范围越大,”模糊效果”越强烈。

python去除图像的噪声 图像去噪opencv_权重_12


上面分别是原图、模糊半径3像素、模糊半径10像素的效果。模糊半径越大,图像就越模糊。从数值角度看,就是数值越平滑。

如果使用简单平均,显然不是很合理,因为图像都是连续的,越靠近的点关系越密切,越远离的点关系越疏远。因此,加权平均更合理,距离越近的点权重越大,距离越远的点权重越小。

而正态分布显然是一种可取的权重分配模式。由于图像是二维的,所以需要使用二维的高斯函数:

一维高斯函数:

python去除图像的噪声 图像去噪opencv_高斯滤波_13


中心点就是原点,μ等于0:

python去除图像的噪声 图像去噪opencv_卷积_14


二维高斯函数(中心为原点):

python去除图像的噪声 图像去噪opencv_python去除图像的噪声_15


计算平均值的时候,我们只需要将”中心点”作为原点,其他点按照其在正态曲线上的位置,分配权重,就可以得到一个加权平均值,而这就是上述的与二维高斯核进行卷积的过程。计算权重矩阵的过程:

假定中心点的坐标是(0,0),那么距离它最近的8个点的坐标如下:

python去除图像的噪声 图像去噪opencv_卷积_16


假定σ=1.5,则模糊半径为1的权重矩阵如下:

python去除图像的噪声 图像去噪opencv_opencv_17


这9个点的权重总和等于0.4787147,如果只计算这9个点的加权平均,还必须让它们的权重之和等于1,因此上面9个值还要分别除以0.4787147,得到最终的权重矩阵:

python去除图像的噪声 图像去噪opencv_python去除图像的噪声_18


有了权重矩阵,就可以计算高斯模糊的值了。

中心点以及周边n个点,每个点乘以自己的权重值并将这些值相加,就是中心点的高斯模糊的值。对所有点重复这个过程,就得到了高斯模糊后的图像。

如果原图是彩色图片,可以对RGB三个通道分别做高斯模糊。

对于边界点来说,周边没有足够的点,一个变通方法是把已有的点拷贝到另一面的对应位置,模拟出完整的矩阵。

代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('opencv-logo-white.png')
blur = cv.GaussianBlur(img,(5,5),0)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()

结果:

python去除图像的噪声 图像去噪opencv_高斯滤波_19

中值滤波

中值,中间值,将数据从小到大排序后的中间值

用 3×3 大小模板进行中值滤波。

python去除图像的噪声 图像去噪opencv_权重_20


以(2,2)像素点为例。

python去除图像的噪声 图像去噪opencv_权重_21


对模板中的 9 个数进行从小到大排序:1,1,1,2,2,5,6,6,10。中间值为 2.所有,中值滤波后(2,2)位置的值变为 2. 同理对其他像素点。

处理结果:

python去除图像的噪声 图像去噪opencv_高斯滤波_22


代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('opencv-logo-white.png')
median = cv.medianBlur(img,5)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()

结果:

python去除图像的噪声 图像去噪opencv_高斯滤波_23

双边滤波

在降低噪音方面非常有效,同时保持边缘清晰。但与其他过滤器相比,操作速度较慢。我们已经看到高斯滤波器采用像素周围的邻域并找到其高斯加权平均值。该高斯滤波器仅是空间的函数,即,在滤波时考虑附近的像素。它没有考虑像素是否具有几乎相同的强度。它不考虑像素是否是边缘像素。所以它也模糊了边缘,我们不想这样做。

双边滤波器在空间中也采用高斯滤波器,但是还有一个高斯滤波器是像素差的函数。空间的高斯函数确保仅考虑附近的像素用于模糊,而强度差的高斯函数确保仅具有与中心像素相似强度的那些像素被认为是模糊的。因此它保留了边缘,因为边缘处的像素将具有较大的强度变化。

均值模糊无法克服边缘像素信息丢失缺陷。原因是均值模糊是基于平均权重。
高斯模糊部分克服了该缺陷,但是无法完全避免,因为没考虑到像素值的不同。
双边滤波是保留边缘的滤波方法,避免了边缘信息的丢失,保留了图像轮廓不变。
代码:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('opencv-logo-white.png')
blur = cv.bilateralFilter(img,9,75,75)
plt.subplot(121),plt.imshow(img),plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred')
plt.xticks([]), plt.yticks([])
plt.show()

结果:

python去除图像的噪声 图像去噪opencv_高斯滤波_24