[数字图像学笔记] 6.几种常见的空间滤波器(均值滤波器、中值滤波器)

OpenCV与数字图像处理 专栏收录该内容
14 篇文章 0 订阅

在上一章里,简要的介绍了空间滤波器,在这一章节中将实现几种常见的空间滤波器函数。

什么是滤波

滤波的概念主要出自信号学领域,指的是过滤我们不感兴趣的信号频段。最早使用滤波技术的,应该最早出自无线电领域,通过可调电容来完成滤波。大家比较熟悉的一种物理滤波应用,就是收音机了,学习数字图像领域的朋友倒是不太需要了解电容对于信号的滤波作用,所以这里也不必过多的展开。

空间滤波(Spatial Filtering)

虽然都是滤波,但是在图像领域有两类比较重要的滤波技术,一种是空间滤波,另一种是频域滤波。而对于视频图像分析,则有另外一类被称为时域滤波的技术。不过数字图像处理主要介绍到空间和频率。

在之前的章节里,我已经简单的介绍了一些图像增强技术,你可以简单的理解为对输入的像素 I i I_i Ii,套用某个公式或者算法 f s f_s fs,然后得到一个输出 I o I_o Io的过程,写作一个公式的话,就表示为:

I o = I i ⨀ f s I_o = I_i \bigodot f_s Io=Iifs

对像素点的逐点计算,与矩阵概念上的 哈达玛积(hadamard product) 很相似。只不过与Hadamard product不一样的地方在于,空间滤波函数通常不是一次性的把全部像素点放入到 f s f_s fs 里进行处理,而是每次取出一小块,再逐次地拿到 f s f_s fs 处理函数里进行计算。

我在 Wikipedia 上看到一张有意思的动图,它是一个均值滤波函数,左边是原始数据,中间是滤波核,右边则是处理后的结果,它很好的解释了什么是空间滤波,以及空间滤波函数的计算过程。

在这里插入图片描述
你或许已经注意到在这里定义了一个核函数,也就是中间 3 × 3 3 \times 3 3×3 的部分,它包含9个值,每个值都是1/9。在原图像进行处理的时候,我们让这个被定义的核函数,依次平滑地扫过每一个点,然后从红框所包含的像素里,分别读取9个像素值,然后和我们定义的核函数相乘,再把每一个结果相加起来,写做数学公式,简单一点,就成了:

P 1 ⋅ K 1 + P 2 ⋅ K 2 + P 3 ⋅ K 3 + ⋯ + P 9 ⋅ K 9 = P i j ∗ P_1 \cdot K_1 + P_2 \cdot K_2 + P_3 \cdot K_3 + \cdots + P_9 \cdot K_9 = P_{ij}^{*} P1K1+P2K2+P3K3++P9K9=Pij

这里的K,表示的是每个原始像素对新像素值的贡献值,或者称为权重,而P则是9个不同的像素点的值。

简化一下这个表达过程,于是再次推导出我们的一个通用计算公式: I o = I i ⨀ f s I_o = I_i \bigodot f_s Io=Iifs

而为了表示红框逐像素点处理的过程,在很多教材上你会看到它的这样一个表示方式:

I o = ∑ ∑ I i , j ⨀ f s I_o = \sum \sum I_{i,j} \bigodot f_s Io=Ii,jfs

它的核心思想就是,想要得到某种效果的输出矩阵(图像),它是由原始图像,与某种操作共同组合而成,而且这个操作必然需要逐点(逐快)扫描,这个过程有点像你拿放大镜观察物体的过程,而负责处理这个最终像素生成的过程就是所谓的空间滤波器了。

这里的 f s f_s fs 即空间滤波器的核函数,它可以是某个数学函数,也可以是我们自己用代码实现的具备某种特殊处理方法,比如对于数值大于15的输入一律输出为0。看到这里,你是不是跃跃欲试,想自己开发一种特别的数据处理方法?

在这里插入图片描述
尽管不排除可以自己设计某种特殊滤波器的天才,不过通常情况下,我们普通人都会用数学家、或者信号学家发明的一系列工具,用于图像细节增强、降噪,或者提取特征,除了有时会觉得这样做调参很麻烦,但是终归利大于弊。

均值滤波器(Mean Filter)

均值滤波器,其核函数经常写成如下的解析式:

K = 1 K w × K h ∑ f ( x , y ) ⋅ W ( x , y ) K = \frac{1}{K_w \times K_h} \sum f(x, y) \cdot W(x, y) K=Kw×Kh1f(x,y)W(x,y)

这里的 K w K_w Kw K h K_h Kh 表示的是核函数的长和宽,后面表示待处理的部分各像素的贡献权重,并求和。它的实现代码可以简单的写成如下形式

def mean_kernel(image):
    mean = 9
    width, height = image.shape
    backup = np.zeros(image.shape, np.uint8)

    for i in range(1, width - 1):
        for j in range(1, height - 1):
            px000 = int(image[i - 1][j - 1])
            px001 = int(image[i][j - 1])
            px002 = int(image[i + 1][j - 1])

            px010 = int(image[i - 1][j])
            px011 = int(image[i][j])
            px012 = int(image[i + 1][j])

            px100 = int(image[i - 1][j + 1])
            px101 = int(image[i][j + 1])
            px102 = int(image[i + 1][j + 1])

            sigma = px000 + px001 + px002 +\
                    px010 + px011 + px012 +\
                    px100 + px101 + px102

            backup[i][j] = round(sigma / mean)

    return backup

输出的图像效果如下:

在这里插入图片描述
仔细观察妹子身上衣服的纹样,可以发现模糊了很多;把核函数的平均尺寸如果设置为5x5甚至更大,那么平滑效果(模糊效果)也就越明显了。例如使用5x5的平均核,得到的效果就是这样的了。

在这里插入图片描述

需要注意一点的是,从像素读取中读取的数据类型为byte,长度为8,直接让像素跟像素加和,很容易出现 Bit-flip 的现象,导致计算结果失败,所以安全的方法是读取数据后做一道数值格式转换。

中值滤波器(Median Filter)

与均值滤波器相似,只不过在赋值环节,有所不同。它要求

首先 将读取的像素值按照大小进行排序
然后 选取排序后中间的数值,或者中间数值的平均

这是一种常用的,用于处理类似椒盐噪音那样,孤点信号的特殊方法。举例来说,对于 3 × 3 3 \times 3 3×3 滤波核来说,假如读取了一组信号,它是

在这里插入图片描述
对数据进行排列后为
[ 0 , 2 , 3 , 3 , 4 , 6 , 10 , 15 , 97 ] [0, 2, 3, 3, 4, 6,10,15, 97] [0,2,3,3,4,6,10,15,97]

那么处理后,中间97的值就应该表示为4
在这里插入图片描述
其代码实现为:

def adjustable_median_kernel(image, size, i, j):
    if size % 2 == 0:
        size = size - 1

    mid = int((size - 1) / 2)
    numbs_list = []

    for subtile_x in range(size):
        for subtile_y in range(size):
            numbs_list.append(image[i + subtile_x - mid][j + subtile_y - mid])

    if len(numbs_list) % 2 == 0:
        numbs_list = np.sort(numbs_list)
        n1 = numbs_list[int(len(numbs_list) / 2)]
        n2 = numbs_list[int(len(numbs_list) / 2 - 1)]

        return int((n1 + n2) / 2)
    else:
        numbs_list = np.sort(numbs_list)
        return numbs_list[int(len(numbs_list) / 2)]

那么,我们生成一副带椒盐噪音的照片后,再用这个滤波函数处理一下,看看效果如何

在这里插入图片描述

当然,仔细观察还原后的图像,任然会发现一些细节出现了模糊,其实这里,选择合适的kernel size就显得非常关键,我用的是5x5,如果用3x3会好一点,不过这也要看图像包含的噪音情况是不是很严重就是了。

  • 1
    点赞
  • 2
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2020 CSDN 皮肤主题: 程序猿惹谁了 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值