[Python图像处理] 四.图像平滑之均值滤波、方框滤波、高斯滤波、中值滤波及双边滤波

2021-12-02 21:09:33 浏览数 (1)

该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门、OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子、图像增强技术、图像分割等,后期结合深度学习研究图像识别、图像分类、目标检测应用。

前一篇文章介绍Python调用OpenCV获取图像属性,截取感兴趣ROI区域,处理图像通道。这篇文章详细讲解讲解Python调用OpenCV实现图像平滑,包括五种算法:均值滤波、方框滤波、高斯滤波、中值滤波和双边滤波。希望文章对您有所帮助,如果有不足之处,还请海涵~

  • 一.图像平滑
  • 二.均值滤波
  • 三.方框滤波
  • 四.高斯滤波
  • 五.中值滤波
  • 六.双边滤波

该系列在github所有源代码:

  • https://github.com/eastmountyxz/ ImageProcessing-Python

在图像产生、传输和应用过程中,通常会由于一些原因导致图像数据丢失或被噪声干扰的现象,从而降低了图像的质量。这就需要通过图像平滑方法来消除这些噪声并保留图像的边缘轮廓和线条清晰度,本文将详细介绍五种图像平滑的滤波算法,包括均值滤波、方框滤波、高斯滤波、中值滤波和双边滤波。

一.图像平滑

1.图像增强

图像增强是对图像进行处理,使其比原始图像更适合于特定的应用,它需要与实际应用相结合。对于图像的某些特征如边缘、轮廓、对比度等,图像增强是进行强调或锐化,以便显示、观察或进一步分析。

图像增强的方法是因应用不同而不同的,研究内容包括:(参考左飞老师的《数字图像处理》)


2.图像平滑

图像平滑是一项简单且使用频率很高的图像处理方法,可以用来压制、弱化或消除图像中的细节、突变、边缘和噪声,最常见的是用来减少图像上的噪声。

何为图像噪声?噪声是妨碍人的感觉器官所接受信源信息理解的因素,是不可预测只能用概率统计方法认识的随机误差。从图中,可以观察到噪声的特点:位置随机、大小不规则,将这种噪声称为随机噪声,这是一种常见的噪声类型。

图像平滑是一种区域增强的算法,平滑算法有邻域平均法、中指滤波、边界保持类滤波等。在图像产生、传输和复制过程中,常常会因为多方面原因而被噪声干扰或出现数据丢失,降低了图像的质量(某一像素,如果它与周围像素点相比有明显的不同,则该点被噪声所感染)。这就需要对图像进行一定的增强处理以减小这些缺陷带来的影响。


3.邻域平均法

图像简单平滑是指通过邻域简单平均对图像进行平滑处理的方法,用这种方法在一定程度上消除原始图像中的噪声、降低原始图像对比度的作用。它利用卷积运算对图像邻域的像素灰度进行平均,从而达到减小图像中噪声影响、降低图像对比度的目的。

但邻域平均值主要缺点是在降低噪声的同时使图像变得模糊,特别在边缘和细节处,而且邻域越大,在去噪能力增强的同时模糊程度越严重。


4.常见图像平滑算法

接下来将详细介绍OpenCV中常用的一些滤波器,包括均值滤波、方框滤波、高斯吕波、中值滤波等,如表所示。

下图为这五种滤波的效果对比,从滤波的结果可以看出各种滤波算法对图像的作用非常不同,有些变化非常大,有些甚至跟原图一样。在实际应用时,应根据噪声的特点、期望的图像和边缘特征等来选择合适的滤波器,这样才能发挥图像滤波的最大优点。

首先给出为图像增加噪声的代码。

代码语言:javascript复制
# -*- coding:utf-8 -*-
import cv2
import numpy as np

#读取图片
img = cv2.imread("test.jpg", cv2.IMREAD_UNCHANGED)
rows, cols, chn = img.shape

#加噪声
for i in range(5000):    
    x = np.random.randint(0, rows) 
    y = np.random.randint(0, cols)    
    img[x,y,:] = 255

cv2.imshow("noise", img)
           
#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下所示,用作者的傻照。


二.均值滤波

1.原理

均值滤波是最简单的一种线性滤波算法,它是指在原始图像上对目标像素给一个模板。该模板包括了其周围的临近像素(以目标像素为中心的周围8个像素,构成一个滤波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来的像素值。

换句话说,均值滤波输出图像的每一个像素值是其周围M×M个像素值的加权平均值。例如下图中,中心红色点的像素值为蓝色背景区域像素值求和的均值。5×5的矩阵称之为模糊内核,针对原始图像内的像素点,均值滤波采用核对其像素逐个进行均值处理,并得到最终的效果图。

其中红色区域的像素值均值滤波处理过程为:

公式中,5*5的矩阵称为核,针对原始图像内的像素点,采用核处理,得到结果图像。

提取1/25可以将核转换为如下形式:


2.函数原型

Python调用OpenCV中的cv2.blur()函数实现均值滤波处理,其函数原型如下所示,输出的dst图像与输入图像src具有相同的大小和类型。

常见的模糊内核包括(3,3)和(5,5),如公式所示:


3.代码实现

Python调用OpenCV实现均值滤波的核心函数如下:

  • result = cv2.blur(原始图像,核大小)

图像均值滤波的Python实现代码如下所示,需要注意,代码中使用的是3×3的模板,plt.rcParams是用于设置中文汉字正常显示。

代码语言:javascript复制
#encoding:utf-8
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#读取图片
img = cv2.imread('test01.png')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
 
#均值滤波
result = cv2.blur(source, (5,5))
 
#显示图形
titles = ['Source Image', 'Blur Image']  
images = [source, result]  
for i in range(2):  
   plt.subplot(1,2,i 1), plt.imshow(images[i], 'gray')  
   plt.title(titles[i])  
   plt.xticks([]),plt.yticks([])  
plt.show()  

输出结果如下图所示:

核设置为(10,10)和(20,20)会让图像变得更加模糊。

如果设置为(1,1)处理结果就是原图,核中每个权重值相同,称为均值。


三.方框滤波

1.原理

方框滤波又称为盒式滤波,它利用卷积运算对图像邻域的像素值进行平均处理,从而实现消除图像中的噪声。方框滤波和和均值滤波的模糊内核基本一样,区别为是否需要进行均一化处理。

Python调用OpenCV中的cv2.boxFilter()函数实现方框滤波处理,其函数原型如下所示:

  • result = cv2.boxFilter(原始图像, 目标图像深度, 核大小, normalize属性)

其中,目标图像深度是int类型,通常用“-1”表示与原始图像一致;核大小主要包括(3,3)和(5,5),如下所示。

参数normalize表示是否对目标图像进行归一化处理。当normalize为true时需要执行均值化处理,当normalize为false时,不进行均值化处理,实际上为求周围各像素的和,很容易发生溢出,溢出时均为白色,对应像素值为255。

在图像简单平滑中,算法利用卷积模板逐一处理图像中每个像素,这一过程可以形象地比作对原始图像的像素一一进行过滤整理,在图像处理中把邻域像素逐一处理的算法过程称为滤波器。平滑线性滤波器的工作原理是利用模板对邻域内像素灰度进行加权平均,也称为均值滤波器。


2.代码实现

图像方框滤波的Python实现代码如下所示。

代码语言:javascript复制
#encoding:utf-8
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#读取图片
img = cv2.imread('test01.png')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
 
#方框滤波
result = cv2.boxFilter(source, -1, (5,5), normalize=1)
 
#显示图形
titles = ['Source Image', 'BoxFilter Image']  
images = [source, result]  
for i in range(2):  
   plt.subplot(1,2,i 1), plt.imshow(images[i], 'gray')  
   plt.title(titles[i])  
   plt.xticks([]),plt.yticks([])  
plt.show()  

代码中使用5*5的核,normalize=1表示进行归一化处理,此时与均值滤波相同,输出结果如下图所示:

下面是图像左上角处理前后的像素结果:

代码语言:javascript复制
print(source[0:3, 0:3, 0])
#[[115 180 106]
# [ 83 152  72]
# [ 55  58  55]]
print(result[0:3, 0:3, 0])
#[[92 90 78]
# [92 89 77]
# [82 80 72]]

如果省略参数normalize,默认是进行归一化处理。normalize=0则不进行归一化处理,像素值为周围像素之和,图像多为白色。

代码语言:javascript复制
#encoding:utf-8
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#读取图片
img = cv2.imread('test01.png')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
 
#方框滤波
result = cv2.boxFilter(source, -1, (5,5), normalize=0)
 
#显示图形
titles = ['Source Image', 'BoxFilter Image']  
images = [source, result]  
for i in range(2):  
   plt.subplot(1,2,i 1), plt.imshow(images[i], 'gray')  
   plt.title(titles[i])  
   plt.xticks([]),plt.yticks([])  
plt.show() 

输出结果如下图所示:

上图很多像素为白色,因为图像求和结果几乎都是255。如果设置的是2*2矩阵,只取四个像素结果要好些。

  • result=cv2.boxFilter(source, -1, (2,2), normalize=0)

四.高斯滤波

1.原理

为了克服简单局部平均法的弊端(图像模糊),目前已提出许多保持边缘、细节的局部平滑算法。它们的出发点都集中在如何选择邻域的大小、形状和方向、参数加平均及邻域各店的权重系数等。

图像高斯平滑也是邻域平均的思想对图像进行平滑的一种方法,在图像高斯平滑中,对图像进行平均时,不同位置的像素被赋予了不同的权重。高斯平滑与简单平滑不同,它在对邻域内像素进行平均时,给予不同位置的像素不同的权值。

下图是 3 * 3 和 5 * 5 内核的高斯模板。

高斯滤波引入了数学中的高斯函数(正态分布函数),一个二维高斯函数如下公式所示,其中σ为标准差。

高斯加权平均中,最重要是σ的选取,标准差代表数据离散程度,如果σ较小,则高斯分布中心区域将更加聚集,平滑效果更差;反之,如果σ较大,高斯分布中心区域将更离散,平滑效果更明显。

高斯滤波的核心思想是对高斯函数进行离散化,以离散点上的高斯函数值为权值,对图像中的每个像素点做一定范围邻域内的加权平均,从而有效地消除高斯噪声。

高斯滤波让临近的像素具有更高的重要度,对周围像素计算加权平均值,较近的像素具有较大的权重值。如下图所示,中心位置权重最高为0.4。


2.代码实现

Python中OpenCV主要调用GaussianBlur函数,如下:

  • dst = cv2.GaussianBlur(src,ksize, sigmaX)

其中,src表示原始图像,ksize表示核大小,sigmaX表示X方向方差。注意,核大小(N, N)必须是奇数,X方向方差主要控制权重。

代码如下:

代码语言:javascript复制
#encoding:utf-8
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#读取图片
img = cv2.imread('test01.png')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
 
#高斯滤波
result = cv2.GaussianBlur(source, (3,3), 0)

#显示图形
titles = ['Source Image', 'GaussianBlur Image']  
images = [source, result]  
for i in range(2):  
   plt.subplot(1,2,i 1), plt.imshow(images[i], 'gray')  
   plt.title(titles[i])  
   plt.xticks([]),plt.yticks([])  
plt.show()  

输出结果如下所示:

如果使用15*15的核,则图形将更加模糊。


五.中值滤波

1.原理

中值滤波通过计算每一个像素点某邻域范围内所有像素点灰度值的中值,来替换该像素点的灰度值,从而让周围的像素值更接近真实情况,消除孤立的噪声。

在使用邻域平均法去噪的同时也使得边界变得模糊。而中值滤波是非线性的图像处理方法,在去噪的同时可以兼顾到边界信息的保留。选一个含有奇数点的窗口W,将这个窗口在图像上扫描,把窗口中所含的像素点按灰度级的升或降序排列,取位于中间的灰度值来代替该点的灰度值。

例如选择滤波的窗口如下图,是一个一维的窗口,待处理像素的灰度取这个模板中灰度的中值,滤波过程如下:

如上图所示,将临近像素按照大小排列,取排序像素中位于中间位置的值作为中值滤波的像素值。


2.代码实现

OpenCV主要调用medianBlur()函数实现中值滤波。图像平滑里中值滤波的效果最好。

  • dst = cv2.medianBlur(src, ksize)

其中,src表示源文件,ksize表示核大小。核必须是大于1的奇数,如3、5、7等。

代码如下所示:

代码语言:javascript复制
#encoding:utf-8
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#读取图片
img = cv2.imread('test01.png')
 
#高斯滤波
result = cv2.medianBlur(img, 3)

#显示图像
cv2.imshow("source img", img)
cv2.imshow("medianBlur", result)

#等待显示
cv2.waitKey(0)
cv2.destroyAllWindows()

输出结果如下图所示:

常用的窗口还有方形、十字形、圆形和环形。不同形状的窗口产生不同的滤波效果,方形和圆形窗口适合外轮廓线较长的物体图像,十字形窗口对有尖顶角状的图像效果好。

中值滤波对于消除孤立点和线段的干扰十分有用,尤其是对于二进噪声,但对消除高斯噪声的影响效果不佳。对于一些细节较多的复杂图像,可以多次使用不同的中值滤波。


六.双边滤波

1.原理

双边滤波(Bilateral filter)是由Tomasi和Manduchi在1998年发明的一种各向异性滤波,它一种非线性的图像平滑方法,结合了图像的空间邻近度和像素值相似度(即空间域和值域)的一种折中处理,从而达到保边去噪的目的。

双边滤波的优势是能够做到边缘的保护,其他的均值滤波、方框滤波和高斯滤波在去除噪声的同时,都会有较明显的边缘模糊,对于图像高频细节的保护效果并不好。

双边滤波比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数。所以在图像边缘附近,离的较远的像素点不会过于影响到图像边缘上的像素点,从而保证了图像边缘附近的像素值得以保存。

在双边滤波器中,输出的像素值依赖于邻域像素值的加权值组合,对输入图像进行局部加权平均得到输出图像f的像素值,其公式如下所示:

式中表示中心点(x,y)的(2N 1)×(2N 1)的领域像素,f(x,y)值依赖于领域像素值的加权平均。权重系数取决于空间域核(domain)和值域核(range)的乘积。

在图像变化平缓的区域,邻域内亮度值相差不大,双边滤波器转化为高斯低通滤波器;在图像变化剧烈的区域,邻域内像素亮度值相差较大,滤波器利用边缘点附近亮度值相近的像素点的亮度平均值替代原亮度值。因此,双边滤波器既平滑了图像,又保持了图像边缘,其原理图如图所示。


2.代码实现

OpenCV将中值滤波封装在bilateralFilter()函数中,其函数原型如下所示:

下面是调用bilateralFilter()函数实现双边滤波的代码,其中d为15,sigmaColor设置为150,sigmaSpace设置为150。

代码语言:javascript复制
# -*- coding: utf-8 -*-
import cv2  
import numpy as np  
import matplotlib.pyplot as plt
 
#读取图片
img = cv2.imread('test01.jpg')
source = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
 
#双边滤波
result = cv2.bilateralFilter(source, 15, 150, 150)
 
#用来正常显示中文标签
plt.rcParams['font.sans-serif']=['SimHei']
 
#显示图形
titles = ['原始图像', '双边滤波']  
images = [source, result]  
for i in range(2):  
   plt.subplot(1,2,i 1), plt.imshow(images[i], 'gray')  
   plt.title(titles[i])  
   plt.xticks([]),plt.yticks([])  
plt.show()  

输出结果如下图所示:


七.总结

写到这里,这篇毒基础性文章就介绍结束了。希望文章对大家有所帮助,如果有错误或不足之处,还请海涵。本文首发于CSDN专栏,为了帮助更多同学故在公众号同步更新,一起加油!

  • 一.图像平滑
  • 二.均值滤波
  • 三.方框滤波
  • 四.高斯滤波
  • 五.中值滤波
  • 六.双边滤波

参考文献:

  • [1] 罗子江. Python中的图像处理[M]. 科学出版社,2020.
  • [2] https://blog.csdn.net/eastmount/category_9278090.html
  • [3] 冈萨雷斯. 数字图像处理(第3版)[M]. 电子工业出版社,2013.
  • [4] 阮秋琦. 数字图像处理学(第3版)[M]. 电子工业出版社,2008.
  • [5]毛星云,冷雪飞. OpenCV3编程入门[M]. 电子工业出版社,2015.
  • [6]张铮. 数字图像处理与机器视觉——Visual C 与Matlab实现.
  • [7]网易云课堂_高登教育. Python OpenCV图像处理

0 人点赞