2019-10-24 21:51:50 wujuxKkoolerter 阅读数 84

01-图像降噪-平滑滤波-模板操作

1 模板操作

模板操作实现一种邻域运算,即某个像素点的结果不仅和本图像的灰度有关,而且和其邻域点的值有关。模板运算在数学上其实就是卷积运算。卷积处理的过程如下:

在这里插入图片描述
卷积运算中的卷积核就是模板运算中的模板,卷积就是做加权求和的过程。邻域中的每个像素分别与卷积核中的每一个元素相乘,乘积求和所得结果即为中心像素的新值。卷积核中的元素称作加权系数(亦称为卷积系数),改变卷积核中的加权系数会影响到总和的数值与符号,从而影响到所求像素的新值。

2 掩模消噪法

掩模消噪法可以用于消除随机噪声,是一种常用的线性低通滤波器,也称为均值滤波器。常见的模板有:

$
H_1 = \frac{1}{10} \begin{bmatrix}
1 & 1 & 1 \
1 & 2 & 1 \
1 & 1 & 1
\end{bmatrix}
$,
$
H_2 = \frac{1}{16} \begin{bmatrix}
1 & 2 & 1 \
2 & 4 & 2 \
1 & 2 & 1
\end{bmatrix}
$,
$
H_3 = \frac{1}{8} \begin{bmatrix}
1 & 1 & 1 \
1 & 0 & 1 \
1 & 1 & 1
\end{bmatrix}
$

如果模板的作用域越大,平滑作用就越明显,图像越模糊。

Python实现的代码如下:

import numpy as np
import scipy.signal as signal
%matplotlib inline
import matplotlib.pyplot as plt
import imageio
def convolve2d(img,fil,mode = 'same'):                #分别提取三个通道
    
    if mode == 'fill':
        h = fil.shape[0] // 2
        w = fil.shape[1] // 2
        img = np.pad(img, ((h, h), (w, w),(0, 0)), 'constant')
    conv_b = _convolve2d(img[:,:,0],fil)              #然后去进行卷积操作
    conv_g = _convolve2d(img[:,:,1],fil)
    conv_r = _convolve2d(img[:,:,2],fil)

    dstack = np.dstack([conv_b,conv_g,conv_r])      #将卷积后的三个通道合并
    return dstack                                   #返回卷积后的结果

def _convolve2d(img,fil):         
    
    fil_heigh = fil.shape[0]                        #获取卷积核(滤波)的高度
    fil_width = fil.shape[1]                        #获取卷积核(滤波)的宽度
    
    conv_heigh = img.shape[0] - fil.shape[0] + 1    #确定卷积结果的大小
    conv_width = img.shape[1] - fil.shape[1] + 1

    conv = np.zeros((conv_heigh,conv_width),dtype = 'uint8')
    
    for i in range(conv_heigh):
        for j in range(conv_width):                 #逐点相乘并求和得到每一个点
            conv[i][j] = wise_element_sum(img[i:i + fil_heigh,j:j + fil_width ],fil)
    return conv
    
def wise_element_sum(img,fil):
    res = (img * fil).sum() 
    if(res < 0):
        res = 0
    elif res > 255:
        res  = 255
    return res
src = imageio.imread('../../../../resources/images/f1.jpg')
kernel = np.array([[1.0,1.0,1.0],[1.0,2.0,1.0],[1.0,1.0,1.0]]) / 10.0

result = convolve2d(src,kernel,'fill')

原图像

plt.imshow(src)

在这里插入图片描述

程序运行结果

plt.imshow(result)

在这里插入图片描述

2019-09-05 09:11:50 botao_li 阅读数 173

中值滤波去噪

中值滤波是一种算法简单,效果较好的“高性价比”去噪算法。

算法原理是使用图像内二维滑窗的中值(全部像素点数值排序位于中间位置的数值为中值)代替当前像素点值。

如下图的 3×33\times 3 滑窗内,处于滑窗中心的当前像素点值为 8,滑窗内全部 9 个像素点的中值为 5,中值滤波即用数值 5 代替当前像素点值 8:

在这里插入图片描述

3×33\times 3 中值滤波为例,首先将图像数据送入 3×33\times 3 二维缓冲,再将并行输出的 9 个像素点进行冒泡排序找到中值后输出:

在这里插入图片描述

冒泡排序的基本原理是多个数值间两两顺序比较找到最大值,称为一轮冒泡。

两数值比较模块设计如下:

在这里插入图片描述

将模块作 Subsystem 封装后组成冒泡模块:

在这里插入图片描述

经过 8 次比较后,最大值出现在输出端口 9。

5 个冒泡模块串联,5 轮冒泡之后在输出端口 5 找到中值 median:

在这里插入图片描述

实际上图中的方法出现了部分逻辑资源浪费,bubble0 的输出中 out9 已是最大值,在 bubble1 中只要找到 in1 至 in8 的最大值即可,同理,下级的 bubble 模块都可以减少一次两两比较,一直到 bubble4 中只要找到 in1 至 in5 之间的最大值即可。但是为了设计直观,仍然使用上图的设计方法。

注意整个冒泡排序找中值的延迟为5级冒泡完整的时延 8×5=408\times 5=40

2019-10-14 16:34:18 qq_24965393 阅读数 75

滤波目的:消除图像中混入的噪声。为图像识别抽取出图像特征。
滤波要求:不能损坏图像轮廓及边缘 。图像视觉效果应当更好。

图像滤波,即在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像预处理中不可缺少的操作,其处理效果的好坏将直接影响到后续图像处理和分析的有效性和可靠性。消除图像中的噪声成分叫作图像的平滑化或滤波操作。

信号或图像的能量大部分集中在幅度谱的低频和中频段是很常见的,而在较高频段,感兴趣的信息经常被噪声淹没。因此一个能降低高频成分幅度的滤波器就能够减弱噪声的影响。平滑滤波是低频增强的空间域滤波技术。

它的目的有两类:一类是模糊;另一类是消除噪音。空间域的平滑滤波一般采用简单平均法进行,就是求邻近像元点的平均亮度值。邻域的大小与平滑的效果直接相关,邻域越大平滑的效果越好,但邻域过大,平滑会使边缘信息损失的越大,从而使输出的图像变得模糊,因此需合理选择邻域的大小。

关于滤波器,一种形象的比喻法是:我们可以把滤波器想象成一个包含加权系数的窗口,当使用这个滤波器平滑处理图像时,就把这个窗口放到图像之上,透过这个窗口来看我们得到的图像。

1、方框滤波(盒式滤波)

方框滤波(盒式滤波)是一种线性滤波技术,它的实现借鉴了积分图像的原理思想,在快速积分图像求解中,将计算某个矩阵像素间的和值运算,转化为求矩阵对应边角点的求和差值运算。盒式滤波的实现最关键的步骤就是初始化数组S,数组S的每个值是存放像素邻域内的像素和值,在求解某矩形块中的像素和时,只需要索引对应区域的位置存放的和值就可以完成计算。

原理:先给出内核,用内核各点的值与对应的图像像素值相乘:

在这里插入图片描述

在这里插入图片描述
OpenCV将盒式滤波封装在boxFilter()函数中,作用是输入一副图像对其进行盒式滤波。感兴趣的同学可以看看其源代码。下面来看下boxFilter()函数的定义:

void boxFilter( InputArray src, OutputArray dst, int ddepth, Size ksize,
Point anchor=Point(-1,-1), bool normalize=true, int borderType=BORDER_DEFAULT );

参数说明:

参数1:输入要处理的图像。

参数2:得到处理后的的输出图像。

参数3:图像的深度。-1代表使用原图深度,即src.depth()。

参数4:内核的大小。一般用Size(w,h)来表示内核大小,其中w为像素宽度,h为像素高度,正奇数或0。例:Size(3,3)就代表3×3的核大小。

参数5:表示锚点,即被平滑的那个点。如果这个点坐标是负值的话,就表示取核的中心点为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。

参数6:默认值为true,一个标识符,表示内核是否被其区域归一化了,具体见下面介绍。

参数7:用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT,我们一般不用管它。

boxFilter()函数盒式滤波所用的核表示如下:
在这里插入图片描述
对参数6具体解释:

当normalize = true 时,盒式滤波就变成了均值滤波。也就是说,均值滤波是盒式滤波归一化(normalized)后的特殊情况。其中,归一化就是把要处理的量都缩放到一个范围内,比如(0,1),以便统一处理和直观量化。

当normalize = false时,为非归一化的盒式滤波,用于计算每个像素邻域内的积分特性,比如密集光流算法(dense optical flow algorithms)中用到的图像倒数的协方差矩阵(covariance matrices of image derivatives)。

显示结果

非归一化情况
在这里插入图片描述
归一化情况
在这里插入图片描述 可以发现,非归一化的时候,得到图像就是一片白色,对源图像毁坏太大,根本无法使用。
而归一化的时候,得到图像是一种模糊的效果,此时与均值滤波一样。

2、均值滤波

均值滤波,是最简单的一种线性滤波操作,输出图像的每一个像素是核窗口内输入图像对应像素的像素的平均值( 所有像素加权系数相等),其实说白了它就是归一化后的方框滤波。

均值滤波算法比较简单,计算速度快,但是均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时,也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。但均值滤波对周期性的干扰噪声有很好的抑制作用。

blur()函数——均值滤波

OpenCV将均值滤波封装在blur()函数中,作用是输入一副图像对其进行均值滤波。感兴趣的同学可以看看其源代码。下面来看下blur()函数的定义:

void blur( InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT );

参数说明:

参数1:输入要处理的图像。

参数2:得到处理后的输出图像。

参数3:内核的大小。一般用Size(w,h)来表示内核大小,其中w为像素宽度,h为像素高度,正奇数或0。

参数4:表示锚点,即被平滑的那个点。如果这个点坐标是负值的话,就表示取核的中心点为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。

参数5:用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT,我们一般不用管它。

显示结果
在这里插入图片描述
blur()函数中的参数3,若核越大,则处理后的图像越模糊。上一节讲的盒式滤波(方框滤波),若将boxFilter()函数中的参数6,设为true,则表现的就是均值滤波,即归一化后的方框滤波。

3、高斯滤波

高斯滤波(高斯平滑)是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波是最有用的滤波器 (尽管不是最快的)。高斯平滑滤波器对于抑制服从正态分布的噪声非常有效。

什么是高斯滤波?

首先,它引入了数学中的高斯函数(正态分布函数)(PS:对于平面图像来说,往往用到的是二维函数)。

在这里插入图片描述

高斯滤波的思路就是:对高斯函数进行离散化,以离散点上的高斯函数值为权值,对我们采集到的灰度矩阵的每个像素点做一定范围邻域内的加权平均,即可有效消除高斯噪声。

离散的高斯卷积核H:(2k+1)×(2k+1)维,其元素计算方法为:

在这里插入图片描述

其中Sigma为方差,k确定核矩阵的维数。

通过上述公式,我们可以方便地求出高斯模板,从而进行高斯滤波处理。这里不得不提在图像处理中,高斯滤波一般有两种实现方式,一是用离散化窗口滑窗卷积,另一种通过傅里叶变换。最常见的就是第一种滑窗实现,只有当离散化的窗口非常大,用滑窗计算量非常大(即使用可分离滤波器的实现)的情况下,可能会考虑基于傅里叶变化的实现方法。

“离散化”:上面已经提到了离散的高斯卷积核,实际上就是将高斯函数进行离散化,方便程序计算高斯模板;

“窗口”:这个窗口比喻得很形象,实际上我的理解就是M*N维的高斯模板;

“滑窗”:有了这个高斯模板,接下来是结合我们待处理的灰度数据,处理一个接着一个的像素点。例如说,处理完(1,1)这个点之后,接下来要处理(1,2)这个数据点,那么模板相当于右移了一个像素点,那么我们可以把这个过程形象地看作是滑窗。在碰上待处理图像的边缘时,往往处理不了,此时要进行特殊处理,比如说在检测到边缘时,复制原来的灰度数据,即不处理;

“卷积”:在高数里有过这个概念,然而在这个地方,卷积远远没有书上的那么复杂,实际上就是待处理图像的各像素灰度数据与模板对应元素的数值的加权和的运算过程,就称之为卷积。

有了以上解释之后,我们可以把“离散化”和“窗口”看成是第一个步骤,可以称之为预处理,通过对高斯函数离散化得到的函数来编程得到你所需要的高斯模板,也就是窗口;把“滑窗”和“卷积”看作是第二个步骤,可以称之为处理过程,通过“滑窗”的方式来进行“卷积”过程。

实际上,在OpenCV中处理起来没这么复杂,因为已经将高斯滤波封装在GaussianBlur()函数中。

GaussianBlur()函数——高斯滤波

OpenCV将高斯滤波封装在GaussianBlur()函数中,作用是输入一副图像对其进行高斯滤波。下面来看下GaussianBlur()函数的定义:

void GaussianBlur(InputArray src,OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT);

参数说明:

参数1:输入要处理的图像。

参数2:得到处理后的输出图像,与输入图像有一样的尺寸和类型。

参数3:高斯内核的大小。一般用Size(w,h)来表示内核大小,其中w为像素宽度,h为像素高度,w与h可以不同,但必须是正数和奇数,或者为0.

参数4:表示高斯核函数在X方向的标准偏差。

参数5:表示高斯核函数在Y方向的标准偏差。

参数6:用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT,我们一般不用管它。

显示结果
在这里插入图片描述
4、中值滤波

中值滤波法是一种非线性平滑技术,将图像的每个像素用邻域 (以当前像素为中心的正方形区域)像素的中值代替 ,常用于消除图像中的椒盐噪声。

与低通滤波不同的是,中值滤波对脉冲噪声有良好的滤除作用,特别是在滤除噪声的同时,能够保护信号的边缘,使之不被模糊,但它会洗去均匀介质区域中的纹理。这些优良特性是线性滤波方法所不具有的。

中值滤波能减弱或消除傅里叶空间的高频分量,同时也影响低频分量。中值滤波去除噪声的效果依赖于两个要素:邻域的空间范围和中值计算中涉及的像素数。一般说来,小于滤波器面积一半的亮或暗的物体基本上会被滤除,而较大的物体几乎会原封不动地保存下来,因此中值滤波器的空间尺寸必须根据现有的问题来进行调整。

medianBlur()函数——中值滤波
OpenCV将均值滤波封装在medianBlur()函数中,作用是输入一副图像对其进行中值滤波。下面来看下medianBlur()函数的定义:

void medianBlur( InputArray src, OutputArray dst, int ksize );

参数说明:

参数1:输入要处理的图像。

参数2:得到处理后的输出图像,与输入图像有一样的尺寸和类型。

参数3:int类型的ksize,表示内核大小,必须设置为奇数。

显示结果
在这里插入图片描述可以发现,中值滤波可以很好保留物体的边缘信息。

5、双边滤波

双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部的特点。

双边滤波器的好处是可以做边缘保存,这个特点对于一些图像模糊来说很有用。一般过去用的维纳滤波或者高斯滤波去降噪,都会较明显地模糊边缘,对于高频细节的保护效果并不明显。一般的高斯模糊在进行采样时主要考虑了像素间的空间距离关系,但是却并没有考虑像素值之间的相似程度,因此这样我们得到的模糊结果通常是整张图片一团模糊。

双边滤波的改进就在于在采样时不仅考虑像素在空间距离上的关系,同时加入了像素间的相似程度考虑。双边滤波器比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波。对于脉冲噪声,双边滤波会把它当成边缘从而不能去除。

在双边滤波器中,输出像素的值依赖于邻域像素值的加权值组合,公式如下:

在这里插入图片描述

而加权系数w(i,j,k,l)取决于定义域核和值域核的乘积。

其中定义域核表示如下:

在这里插入图片描述

定义域滤波对应图示:

在这里插入图片描述

值域核表示为:

在这里插入图片描述

值域滤波:

在这里插入图片描述

两者相乘后,就会产生依赖于数据的双边滤波权重函数:

在这里插入图片描述

bilateralFilter()——双边滤波

OpenCV将双边滤波封装在bilateralFilter()函数中,作用是输入一副图像对其进行双边滤波。下面来看下bilateralFilter()函数的定义:

void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );

参数说明:

参数1:输入要处理的图像,需要为8位或者浮点型单通道、三通道的图像。

参数2:得到处理后的输出图像,与输入图像有一样的尺寸和类型。

参数3:表示在过滤过程中每个像素邻域的直径。如果这个值我们设其为非正数,那么OpenCV会从第五个参数sigmaSpace来计算出它来。

参数4:表示颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。

参数5:double类型的sigmaSpace坐标空间中滤波器的sigma值,坐标空间的标注方差。它的数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。

参数6:用于推断图像外部像素的某种边界模式。注意它有默认值BORDER_DEFAULT,我们一般不用管它。

显示结果
在这里插入图片描述可以发现双边滤波对图像物体的边缘信息保留的很完整。

2019-12-13 10:10:58 qq_17518433 阅读数 58

几种视差图后处理方法,包括滤波去噪(中值滤波或双边滤波)、连通域检测和左右一致性检测。

1)滤波去噪

滤波去躁主要用于去除视差图中由于误匹配造成的孤立噪点,视差图后处理中常用的两种滤波方法有中值滤波和双边滤波。

中值滤波是一种典型的非线性滤波技术,其基本思想是用像素点邻域灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声、椒盐噪声的同时又能保留图像的边缘细节。如下图所示:

image.png

 

双边滤波是结合图像的空间邻近度和像素值相似度的一种折衷处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。双边滤波器顾名思义比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。如下图所示:

image.png

2)连通域检测

连通域检测主要用于去除视差图中由于误匹配造成的小团块。其算法大概流程如下:

0.首先设定speckleRange和speckleWindowSize,speckleWindowSize是指设置检测出的连通域中像素点个数,也就是连通域的大小。speckleRange是指设置判断两个点是否属于同一个连通域的阈值条件。

1.判断当前像素点四邻域的邻域点与当前像素点的差值diff,如果diff<speckleRange,则表示该邻域点与当前像素点是一个连通域,设置一个标记。然后再以该邻域点为中心判断其四邻域点,步骤同上。直至某一像素点四邻域的点均不满足条件,则停止。

2.步骤1完成后,判断被标记的像素点个数count,如果像素点个数count<=speckleWindowSize,则说明该连通域是一个小团块(blob),则将当前像素点值设置为newValue(表示错误的视差值,newValue一般设置为负数或者0值)。否则,表示该连通域是个大团块,不做处理。同时建立标记值与是否为小团块的关系表rtype[label],rtype[label]为0,表示label值对应的像素点属于小团块,为1则不属于小团块。

3.处理下一个像素点时,先判断其是否已经被标记:如果已经被标记,则根据关系表rtype[label]判断是否为小团块(blob),如果是,则直接将该像素值设置为newValue;如果不是,则不做处理。继续处理下一个像素。如果没有被标记,则按照步骤1处理。

4.所有像素点处理后,满足条件的区域会被设置为newValue值。

代码:

typedef cv::Point_<short> Point2s;
void myFilterSpeckles(cv::Mat &img, int newVal, int maxSpeckleSize, int maxDiff)
{
	int width = img.cols;
	int height = img.rows;
	int imgSize = width * height;
	int *pLabelBuf = (int*)malloc(sizeof(int)*imgSize);//标记值buffer
	Point2s *pPointBuf = (Point2s*)malloc(sizeof(short)*imgSize);//点坐标buffer
	uchar *pTypeBuf = (uchar*)malloc(sizeof(uchar)*imgSize);//blob判断标记buffer
	//初始化Labelbuffer
	int currentLabel = 0;
	memset(pLabelBuf, 0, sizeof(int)*imgSize);

	for (int i = 0; i < height; i++)
	{
		float *pData = img.ptr<float>(i);
		int *pLabel = pLabelBuf + width * i;
		for (int j = 0; j < width; j++)
		{
			if ((pData[j] - newVal) > 1e-1)
			{
				if (pLabel[j])
				{
					if (pTypeBuf[pLabel[j]])
					{
						pData[j] = newVal;
					}
				}
				else
				{
					Point2s *pWave = pPointBuf;
					Point2s curPoint(j, i);
					currentLabel++;
					int count = 0;
					pLabel[j] = currentLabel;
					while (pWave >= pPointBuf)
					{
						count++;
						float *pCurPos = &img.at<float>(curPoint.y, curPoint.x);
						float curValue = *pCurPos;
						int *pCurLabel = pLabelBuf + width * curPoint.y + curPoint.x;
						//bot
						if (curPoint.y < height - 1 && !pCurLabel[+width] && pCurPos[+width] != newVal && abs(curValue - pCurPos[+width]) <= maxDiff)
						{
							pCurLabel[+width] = currentLabel;
							*pWave++ = Point2s(curPoint.x, curPoint.y + 1);
						}
						//top
						if (curPoint.y > 0 && !pCurLabel[-width] && pCurPos[-width] != newVal && abs(curValue - pCurPos[-width]) <= maxDiff)
						{
							pCurLabel[-width] = currentLabel;
							*pWave++ = Point2s(curPoint.x, curPoint.y - 1);
						}
						//right
						if (curPoint.x < width - 1 && !pCurLabel[+1] && pCurPos[+1] != newVal && abs(curValue - pCurPos[+1]) <= maxDiff)
						{
							pCurLabel[+1] = currentLabel;
							*pWave++ = Point2s(curPoint.x + 1, curPoint.y);
						}
						//left
						if (curPoint.x > 0 && !pCurLabel[-1] && pCurPos[-1] != newVal && abs(curValue - pCurPos[-1]) <= maxDiff)
						{
							pCurLabel[-1] = currentLabel;
							*pWave++ = Point2s(curPoint.x - 1, curPoint.y);
						}

						--pWave;
						curPoint = *pWave;
					}

					if (count <= maxSpeckleSize)
					{
						pTypeBuf[pLabel[j]] = 1;
						pData[j] = (float)newVal;
					}
					else
					{
						pTypeBuf[pLabel[j]] = 0;
					}
				}
			}
		}
	}

	free(pLabelBuf);
	free(pPointBuf);
	free(pTypeBuf);
}

3)左右一致性检测

左右一致性检测是用于遮挡检测的,具体做法:

根据左右两幅输入图像,分别得到左右两幅视差图。对于左图中的一个点p,求得的视差值是d1,那么p在右图里的对应点应该是(p-d1),(p-d1)的视差值记作d2。若|d1-d2|>threshold,p标记为遮挡点(occluded point)。

2019-10-26 17:34:40 wujuxKkoolerter 阅读数 147

梯形高通滤波

梯形高通滤波器(TLPF)的传递函数如下:

$$
H(u,v) = 1 - \begin{cases}
1 & D(u,v) \lt D_0 \\
\frac{D(u,v) - D_1}{D_0-D_1} & D_0 \lt D(u,v) \leq D_1 \\
0 &D(u,v) > D_1
\end{cases}

\tag{18-1}

$$

Python语言实现的代码如下:

def trapezoidal_low_pass_kernel(img,D0=5,D1=10):
    assert img.ndim == 2
    r,c = img.shape[1],img.shape[0]
    u = np.arange(r)
    v = np.arange(c)
    u, v = np.meshgrid(u, v)
    low_pass = np.sqrt( (u-r/2)**2 + (v-c/2)**2 )

    idx = low_pass < D0
    idx2 = (low_pass >= D0) & (low_pass <= D1)
    idx3 = low_pass > D1

    low_pass[idx] = 1
    low_pass[idx2] = (low_pass[idx2] - D1) / (D1 - D0)
    low_pass[idx3] = 0

    return low_pass

def trapezoidal_high_pass_filter(img,D0=5,D1=15):
    assert img.ndim == 2
    gray = np.float64(img)
    kernel = 1 - trapezoidal_low_pass_kernel(img,D0,D1)
    gray_fft = np.fft.fft2(gray)
    gray_fftshift = np.fft.fftshift(gray_fft)
    dst = np.zeros_like(gray_fftshift)
    dst_filtered = kernel * gray_fftshift
    dst_ifftshift = np.fft.ifftshift(dst_filtered)
    dst_ifft = np.fft.ifft2(dst_ifftshift)
    dst = np.abs(np.real(dst_ifft))
    dst = np.clip(dst,0,255)
    return np.uint8(dst)

程序运行结果:

在这里插入图片描述

没有更多推荐了,返回首页