仅沿一个轴平滑二维阵列

Smoothing a 2D array along only one axis

我想知道是否有人可以帮助我将 the smoothing example in the SciPy cookbook 扩展到二维问题。

这个脚本非常适合平滑 1D 函数,它们还提供了在两个轴上进行 2D 平滑的代码(即模糊图像)。

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

因此,我想知道如何在二维中做到这一点?我想我需要制作一个权重仅沿一个方向变化的 2D 内核,但我不确定该怎么做,也不知道要使用哪个卷积函数(numpy.convolvescipy.signal.convolvescipy.ndimage.filters.convolve1d等)

简介

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

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

import numpy as np

kern = np.ones((11, 1))  # This will smooth along columns

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

kern /= kern.sum()

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

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)

这应该给你这样的东西,

更好的内核

上面我使用了 'boxcar' 内核(常量值),许多人认为它有些粗糙。人们通常更喜欢使用更锐利或更平滑的过滤器(例如食谱中的 'hanning' 或 'gaussian')。

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()

这些不同的windows看起来像这样,

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

请注意,'Gauss7' 内核与 boxcar 几乎相同,因此它在输出中产生非常相似的结果。另一方面,hanning window 更精细,因此它会产生更清晰的数据过滤器(环上的涂抹更少)。

也许最简单的选择是使用 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)

您也可以像这样使用非一维版本的过滤器: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)

这是各种输出的样子:

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()