仅沿一个轴平滑二维数组

Ian*_*rts 4 python numpy convolution scipy smoothing

我想知道是否有人可以帮助我将SciPy 食谱中的平滑示例扩展到 2D 问题。

该脚本非常适用于平滑一维函数,并且它们还提供了在两个轴上进行二维平滑的代码(即模糊图像)。

但是,我想将此函数应用于 2D 数据集,但仅沿一个轴(x 方向)。我可以循环执行此操作,方法是检查 y 中的每个切片,应用一维卷积,然后重建数组。但这似乎是糟糕的编码技术。

因此,我想知道如何在 2D 中做到这一点?我想我需要做一个2D内核与重量仅沿一个方向变化,但我不知道如何做到这一点,或卷积功能的使用(numpy.convolvescipy.signal.convolvescipy.ndimage.filters.convolve1d等)

far*_*rth 5

介绍

看起来您应该能够ny=1执行 2D 图像的 1D 卷积,但这表明食谱函数实际上使用的是长度2 * n + 1内核。这让我认为您可以使用ny=0,但这会0/0在内核的定义中创建一个。所以,那里也没有运气。:( 基于此,我认为食谱不适合您的目的,因此我提供了另一种方法来执行您的要求。

要仅沿 1 维通过卷积对 2D 数组进行平滑处理,您需要做的就是制作一个沿其中一个维度的形状为 1 的 2D 数组(内核),

import numpy as np

kern = np.ones((11, 1))  # This will smooth along columns
Run Code Online (Sandbox Code Playgroud)

并将其归一化,使其总和为 1,

kern /= kern.sum()
Run Code Online (Sandbox Code Playgroud)

然后将它与你的信号进行卷积,

import scipy.signal as signal

X, Y = np.mgrid[-70:70, -70:70]
Z = np.cos((X**2+Y**2)/200.) + np.random.normal(size=X.shape)

Z_smooth = signal.convolve(Z, kern)
Run Code Online (Sandbox Code Playgroud)

这应该给你这样的东西, 棚车窗口。

更好的内核

上面我使用了“boxcar”内核(常量值),很多人认为它有些粗糙。人们通常更喜欢使用更锐利或更平滑的过滤器(例如“汉宁”或“高斯”,如食谱中所述)。

kern_hanning = signal.hanning(11)[:, None]
kern_hanning /= kern_hanning.sum()
kern_gauss7 = signal.gaussian(11, 7)[:, None]
kern_gauss7 /= kern_gauss7.sum()
kern_gauss3 = signal.gaussian(11, 3)[:, None]
kern_gauss3 /= kern_gauss3.sum()
Run Code Online (Sandbox Code Playgroud)

这些不同的窗户看起来像这样,

内核

应用这些过滤器后,你会得到类似的东西,

汉宁内核。 Gauss3内核 Gauss7内核

请注意,'Gauss7' 内核与 boxcar 几乎相同,因此它在输出中产生非常相似的结果。另一方面,汉宁窗口要精细得多,因此它可以对数据产生更清晰的过滤器(环上的拖尾现象要少得多)。


ali*_*i_m 5

也许最简单的选择是使用以下中的一维滤波器之一scipy.ndimage.filters

from scipy import ndimage
from scipy.misc import lena

img = lena()

# a uniform (boxcar) filter with a width of 50
boxcar = ndimage.uniform_filter1d(img, 50, 1)

# a Gaussian filter with a standard deviation of 10
gauss = ndimage.gaussian_filter1d(img, 10, 1)
Run Code Online (Sandbox Code Playgroud)

您还可以使用过滤器的非一维版本,如下所示:(ndimage.gaussian_filter(img, (0, 10))即将您不想平滑的轴的过滤器宽度设置为 0)。

要平滑任意内核,您可以使用scipy.ndimage.convolve1d

import numpy as np

kern = np.hanning(50)   # a Hanning window with width 50
kern /= kern.sum()      # normalize the kernel weights to sum to 1

hanning = ndimage.convolve1d(img, kern, 1)
Run Code Online (Sandbox Code Playgroud)

以下是各种输出的样子:

from matplotlib import pyplot as plt

fig, ax = plt.subplots(2, 2, figsize=(8, 8))
ax[0, 0].imshow(img)
ax[0, 0].set_title('Original')
ax[0, 1].imshow(boxcar)
ax[0, 1].set_title('Boxcar filter (width = 50)')
ax[1, 0].imshow(gauss)
ax[1, 0].set_title(r'Gaussian filter ($\sigma$ = 10)')
ax[1, 1].imshow(hanning)
ax[1, 1].set_title(r'Hanning window (width = 50)')

for aa in ax.flat:
    aa.set_axis_off()

fig.tight_layout()
plt.show()
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述