仅沿一个轴平滑二维阵列
Smoothing a 2D array along only one axis
我想知道是否有人可以帮助我将 the smoothing example in the SciPy cookbook 扩展到二维问题。
这个脚本非常适合平滑 1D 函数,它们还提供了在两个轴上进行 2D 平滑的代码(即模糊图像)。
但是,我想将此函数应用于二维数据集,但仅沿一个轴(x 方向)。我可以循环执行此操作,方法是检查 y 中的每个切片,应用一维卷积,然后重建数组。但这似乎是糟糕的编码技术。
因此,我想知道如何在二维中做到这一点?我想我需要制作一个权重仅沿一个方向变化的 2D 内核,但我不确定该怎么做,也不知道要使用哪个卷积函数(numpy.convolve
、scipy.signal.convolve
、scipy.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()
我想知道是否有人可以帮助我将 the smoothing example in the SciPy cookbook 扩展到二维问题。
这个脚本非常适合平滑 1D 函数,它们还提供了在两个轴上进行 2D 平滑的代码(即模糊图像)。
但是,我想将此函数应用于二维数据集,但仅沿一个轴(x 方向)。我可以循环执行此操作,方法是检查 y 中的每个切片,应用一维卷积,然后重建数组。但这似乎是糟糕的编码技术。
因此,我想知道如何在二维中做到这一点?我想我需要制作一个权重仅沿一个方向变化的 2D 内核,但我不确定该怎么做,也不知道要使用哪个卷积函数(numpy.convolve
、scipy.signal.convolve
、scipy.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()