噪点的消除
1 概念
首先介绍一些概念:
噪声:指图像中的一些干扰因素,通常是由图像采集设备、传输信道等因素造成的,表现为图像中随机的亮度,也可以理解为有那么一些点的像素值与周围的像素值格格不入。常见的噪声类型包括高斯噪声和椒盐噪声。高斯噪声是一种分布符合正态分布的噪声,会使图像变得模糊或有噪点。椒盐噪声则是一些黑白色的像素值分布在原图像中。
滤波器:也可以叫做卷积核,与自适应二值化中的核一样,本身是一个小的区域,有着特定的核值,并且工作原理也是在原图上进行滑动并计算中心像素点的像素值。滤波器可分为线性滤波和非线性滤波,线性滤波对邻域中的像素进行线性运算,如在核的范围内进行加权求和,常见的线性滤波器有均值滤波、高斯滤波等。非线性滤波则是利用原始图像与模板之间的一种逻辑关系得到结果,常见的非线性滤波器中有中值滤波器、双边滤波器等。
滤波与模糊联系与区别:
- 它们都属于卷积,不同滤波方法之间只是卷积核不同(对线性滤波而言)
- 低通滤波器是模糊,高通滤波器是锐化
- 低通滤波器就是允许低频信号通过,在图像中边缘和噪点都相当于高频部分,所以低通滤波器用于去除噪点、平滑和模糊图像。高通滤波器则反之,用来增强图像边缘,进行锐化处理。
注意:椒盐噪声可以理解为斑点,随机出现在图像中的黑点或白点;高斯噪声可以理解为拍摄图片时由于光照等原因造成的噪声。
本实验中共提供了五种滤波的方式,分别为(1.均值滤波,2.方框滤波,3.高斯滤波,4.中值滤波,5.双边滤波)下面进行一一介绍。
2.均值滤波(cv2.blur)
均值滤波是一种最简单的滤波处理,它取的是卷积核区域内元素的均值,如3×3的卷积核:
k
e
r
n
e
l
=
1
9
[
1
1
1
1
1
1
1
1
1
]
k e r n e l={\frac{1}{9}}{\Bigg[}\begin{array}{l l l}{1}&{1}&{1}\\{1}&{1}&{1}\\{1}&{1}&{1}\end{array}{\Bigg]}
kernel=91[111111111]
在滤波算法组件中,当参数filtering_method选为均值滤波,参数component_param为ksize,代表卷积核的大小,eg:ksize=3,则代表使用3×3的卷积核。
比如有一张4*4的图片,现在使用一个3*3的卷积核进行均值滤波时,其过程如下所示:
对于边界的像素点,则会进行边界填充,以确保卷积核的中心能够对准边界的像素点进行滤波操作。在OpenCV中,默认的是使用BORDER_REFLECT_101的方式进行填充,下面的滤波方法中除了中值滤波使用的是BORDER_REPLICATE进行填充之外,其他默认也是使用这个方式进行填充,因此下面就不再赘述。通过卷积核在原图上从左上角滑动计算到右下角,从而得到新的4*4的图像的像素值。
代码格式如下:
cv2.blur(img,kernel)
参数说明:
- img:要进行滤波处理的原图
-kernel:卷积核(用元组表示)
下面是均值滤波处理椒盐噪点的代码:
'''均值滤波'''
img=cv2.imread(r"../15day4.10/src/lvbo3.png")
img2=cv2.blur(img,(3,3))
cv2.imshow("img",img)
cv2.imshow("Img2",img2)
cv2.waitKey(0)
如图所示:
- 图像中的噪点变模糊了
- 但是模糊的噪点变大了
2. 方框滤波(cv2.boxFilter())
方框滤波跟均值滤波很像,如3×3的滤波核如下:
k
e
r
n
e
l
=
a
[
1
1
1
1
1
1
1
1
1
]
k e r n e l={a}{\Bigg[}\begin{array}{l l l}{1}&{1}&{1}\\{1}&{1}&{1}\\{1}&{1}&{1}\end{array}{\Bigg]}
kernel=a[111111111]
在滤波算法组件中,当参数filtering_method选为方框滤波时,参数component_param为ksize,ddepth,normalize。下面讲解这3个参数的含义:
ksize:代表卷积核的大小,eg:ksize=3,则代表使用3×3的卷积核。
ddepth:输出图像的深度,-1代表使用原图像的深度。
normalize:当normalize为True的时候,方框滤波就是均值滤波,上式中的a就等于1/9;normalize为False的时候,a=1,相当于求区域内的像素和。
其滤波的过程与均值滤波一模一样,都采用卷积核从图像左上角开始,逐个计算对应位置的像素值,并从左至右、从上至下滑动卷积核,直至到达图像右下角,唯一的区别就是核值可能会不同。
代码格式如下:
cv2.boxFilter(img,ksize,ddepth,normalize)
参数说明:
-
ksize:代表卷积核的大小,eg:ksize=3,则代表使用3×3的卷积核。
-
ddepth:输出图像的深度,-1代表使用原图像的深度。
-
normalize:当normalize为True的时候,方框滤波就是均值滤波,上式中的a就等于1/9;normalize为False的时候,a=1,相当于求区域内的像素和。
代码如下:
'''方框滤波'''
img=cv2.imread(r"../15day4.10/src/lvbo3.png")
img2=cv2.boxFilter(img,ksize=(3,3),ddepth=-1,normalize=True) #normalize=True表示均值滤波3*3的核每个的权重为1/9
img2=cv2.boxFilter(img,ksize=(3,3),ddepth=-1,normalize=False) #normalize=False表示均值滤波3*3的核每个的权重为1,再将每个值加起来
cv2.imshow("img",img)
cv2.imshow("Img2",img2)
cv2.waitKey(0)
normalize=True的图像
normalize=False的图像
3. 高斯滤波(cv2.GaussianBlur())
前面两种滤波方式,卷积核内的每个值都一样,也就是说图像区域中每个像素的权重也就一样。 高斯滤波的卷积核权重并不相同:中间像素点权重最高,越远离中心的像素权重越小。 还记得我们在自适应二值化里是怎么生成高斯核的吗?这里跟自适应二值化里生成高斯核的步骤是一样的,都是以核的中心位置为坐标原点,然后计算周围点的坐标,然后带入下面的高斯公式中。
g
(
x
,
y
)
=
1
2
π
σ
2
e
−
(
x
2
+
y
2
)
2
σ
2
g(x,y)=\frac{1}{2\pi\sigma^{2}}e^{-\frac{(x^{2}+y^{2})}{2\sigma^{2}}}
g(x,y)=2πσ21e−2σ2(x2+y2)
其中的值也是与自适应二值化里的一样,当时会取固定的系数,当kernel大于7并且没有设置时,会使用固定的公式进行计算
σ
\sigma
σ的值:
σ
=
0.3
∗
(
(
k
s
i
z
e
−
1
)
∗
0.5
−
1
)
+
0.8
\sigma=0.3*\left((k s i z e-1)*0.5-1\right)+0.8
σ=0.3∗((ksize−1)∗0.5−1)+0.8
我们还是以3*3的卷积核为例,其核值如下所示:
k
e
r
n
e
l
=
[
0.0625
0.125
0.0625
0.125
0.25
0.125
0.0625
0.125
0.0625
]
=
[
1
16
1
8
1
16
1
8
1
4
1
8
1
16
1
8
1
16
]
\ k e r n e l=\left[\begin{array}{c}{{0.0625~~~~0.125~~~~0.0625}}\\{{0.125~~~~0.25~~~~0.125}}\\{{0.0625~~~~0.125~~~~0.0625}} \end{array}\right]=\left[\begin{array}{c c c}{\frac{1}{16}~~~\frac{1}{8}~~~\frac{1}{16}}\\{\frac{1}{8}~~~\frac{1}{4}~~~\frac{1}{8}}\\{\frac{1}{16}~~~\frac{1}{8}~~~\frac{1}{16}}\end{array}\right]
kernel=
0.0625 0.125 0.06250.125 0.25 0.1250.0625 0.125 0.0625
=
161 81 16181 41 81161 81 161
得到了卷积核的核值之后,其滤波过程与上面两种滤波方式的滤波过程一样,都是用卷积核从图像左上角开始,逐个计算对应位置的像素值,并从左至右、从上至下滑动卷积核,直至到达图像右下角,唯一的区别就是核值不同。
在滤波算法组件中,当参数filtering_method选为高斯滤波,参数component_param为ksize,sigmaX。下面讲解这2个参数的含义:
代码格式如下:
cv2.GaussianBlur(img,ksize,sigmaX)
参数说明:
-
ksize:代表卷积核的大小(用元组表示)
-
sigmaX:就是高斯函数里的值,σx值越大,模糊效果越明显。高斯滤波相比均值滤波效率要慢,但可以有效消除高斯噪声,能保留更多的图像细节,所以经常被称为最有用的滤波器。均值滤波与高斯滤波的对比结果如下(均值滤波丢失的细节更多)
下面是高斯滤波处理高斯噪点的代码:
'''高斯滤波'''
img=cv2.imread(r"../15day4.10/src/lvbo2.png") #高斯噪点的原图
img2=cv2.GaussianBlur(img,ksize=(3,3),sigmaX=10)
cv2.imshow("img",img)
cv2.imshow("Img2",img2)
cv2.waitKey(0)
4. 中值滤波(cv2.medianBlur())
中值又叫中位数,是所有数排序后取中间的值。中值滤波没有核值,而是在原图中从左上角开始,将卷积核区域内的像素值进行排序,并选取中值作为卷积核的中点的像素值,其过程如下所示:
中值滤波就是用区域内的中值来代替本像素值,所以那种孤立的斑点,如0或255很容易消除掉,适用于去除椒盐噪声和斑点噪声。中值是一种非线性操作,效率相比前面几种线性滤波要慢。
比如下面这张斑点噪声图,用中值滤波显然更好:
代码格式如下:
cv2.medianBlur(img,ksize)
代码如下:
img=cv2.imread(r"../15day4.10/src/lvbo3.png") #读取的是椒盐噪点的图
img2=cv2.medianBlur(img,ksize=3)
cv2.imshow("img",img)
cv2.imshow("Img2",img2)
cv2.waitKey(0)
如图所示中值滤波处理椒盐噪点时几乎没有噪点,这是因为这些噪点分布不均匀,而在一个卷积核中噪点,要么是最小值或者最大值,根本取不到噪点的值作为中位数
注意:
- 中值滤波适用于处理椒盐噪点,高斯噪点因为噪点分布比较均匀中值滤波处理效果也不是很好
- 中值滤波因为需要排序,所以执行效率比较低
5. 双边滤波(cv2.bilateralFilter())
模糊操作基本都会损失掉图像细节信息,尤其前面介绍的线性滤波器,图像的边缘信息很难保留下来。然而,边缘(edge)信息是图像中很重要的一个特征,所以这才有了双边滤波。
双边滤波的原理
代码格式如下:
cv2.bilateralFilter(img,d,sigmacolor,sigmaspace)
参数说明:
- d:过滤时周围每个像素领域的直径
- sigmaColor:在color space中过滤sigma。参数越大,临近像素将会在越远的地方mix。
- sigmaSpace:在coordinate space中过滤sigma。参数越大,那些颜色足够相近的的颜色的影响越大。
关于2个sigma参数:
简单起见,可以令2个sigma的值相等;
如果他们很小(小于10),那么滤波器几乎没有什么效果;
如果他们很大(大于150),那么滤波器的效果会很强,使图像显得非常卡通化。
关于参数d:
过大的滤波器(d>5)执行效率低。
对于实时应用,建议取d=5;
对于需要过滤严重噪声的离线应用,可取d=9;
代码如下:
'''双边滤波'''
img=cv2.imread(r"../15day4.10/src/lvbo2.png") #高斯噪点的原图
img2=cv2.bilateralFilter(img,5,150,150)
cv2.imshow("img",img)
cv2.imshow("Img2",img2)
cv2.waitKey(0)
6. 小结
在不知道用什么滤波器好的时候,优先高斯滤波,然后均值滤波。
斑点和椒盐噪声优先使用中值滤波。
要去除噪点的同时尽可能保留更多的边缘信息,使用双边滤波。
线性滤波方式:均值滤波、方框滤波、高斯滤波(速度相对快)。
非线性滤波方式:中值滤波、双边滤波(速度相对慢)。