平滑的离散二维数组

3

我需要将一个包含离散步长高程的2D numpy数组进行平滑处理。这里我在位置 (0, 0) 的值为z-value = 1(高程),但它可以是0到1之间的任何值。我的数组看起来像这样:

['1.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']

我尝试使用scipy应用余弦核函数,然后使用convolve2d。像这样:

import numpy as np
from scipy import signal

peak_array = np.array([
   [ 1.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.],
   [ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.]])

def elevation_grid():
    """Creates a smooth elevation-grid, from an array of peaks."""
    def gkern():
        """Returns a 2D Triangle kernel array."""
        # Decay is a cosine.
        # It is centered, so multiply by two, and add one
        # This way, we cover the entire grid, and assert
        # equal smoothing (due to an odd width)
        gkern1d_c = signal.cosine(peak_array.shape[0]*2 + 1)
        gkern1d_r = signal.cosine(peak_array.shape[1]*2 + 1)

        gkern2d = np.outer(gkern1d_c, gkern1d_r)
        return gkern2d

    kernel = gkern()
    grad = signal.convolve2d(peak_array, kernel, mode='same')

    # Normalize the grid
    grad -= np.amin(grad)
    grad /= np.amax(grad)

    return grad

def print_readable(array):
    """Prints the map to a human-readable format."""
    for row in range(0, array.shape[0]):
        # Round to two decimals
        r = ["%.2f" % array[col][row] for col in range(0, array.shape[1])]
        print(r)

smooth_array = elevation_grid()

print_readable(smooth_array)

这将导致数组看起来像这样:
['1.00', '0.99', '0.95', '0.90', '0.82', '0.72', '0.60', '0.47', '0.33', '0.18']
['0.99', '0.98', '0.94', '0.89', '0.81', '0.71', '0.60', '0.47', '0.33', '0.18']
['0.95', '0.94', '0.91', '0.85', '0.78', '0.68', '0.57', '0.45', '0.32', '0.17']
['0.90', '0.89', '0.85', '0.80', '0.73', '0.64', '0.54', '0.42', '0.29', '0.16']
['0.82', '0.81', '0.78', '0.73', '0.67', '0.59', '0.49', '0.38', '0.27', '0.14']
['0.72', '0.71', '0.68', '0.64', '0.59', '0.51', '0.43', '0.33', '0.23', '0.12']
['0.60', '0.60', '0.57', '0.54', '0.49', '0.43', '0.36', '0.28', '0.19', '0.09']
['0.47', '0.47', '0.45', '0.42', '0.38', '0.33', '0.28', '0.21', '0.14', '0.06']
['0.33', '0.33', '0.32', '0.29', '0.27', '0.23', '0.19', '0.14', '0.09', '0.03']
['0.18', '0.18', '0.17', '0.16', '0.14', '0.12', '0.09', '0.06', '0.03', '0.00']

预期结果是这样的。然而,如果我在每个角落放置峰值:
['1.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '1.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00']
['1.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '0.00', '1.00']

它们在中间相加,导致中心有一个更大的峰值,我希望在中间得到最低的值...

['0.00', '0.17', '0.30', '0.39', '0.44', '0.44', '0.39', '0.30', '0.17', '0.00']
['0.17', '0.36', '0.51', '0.61', '0.66', '0.66', '0.61', '0.51', '0.36', '0.17']
['0.30', '0.51', '0.67', '0.77', '0.83', '0.83', '0.77', '0.67', '0.51', '0.30']
['0.39', '0.61', '0.77', '0.89', '0.94', '0.94', '0.89', '0.77', '0.61', '0.39']
['0.44', '0.66', '0.83', '0.94', '1.00', '1.00', '0.94', '0.83', '0.66', '0.44']
['0.44', '0.66', '0.83', '0.94', '1.00', '1.00', '0.94', '0.83', '0.66', '0.44']
['0.39', '0.61', '0.77', '0.89', '0.94', '0.94', '0.89', '0.77', '0.61', '0.39']
['0.30', '0.51', '0.67', '0.77', '0.83', '0.83', '0.77', '0.67', '0.51', '0.30']
['0.17', '0.36', '0.51', '0.61', '0.66', '0.66', '0.61', '0.51', '0.36', '0.17']
['0.00', '0.17', '0.30', '0.39', '0.44', '0.44', '0.39', '0.30', '0.17', '0.00']

如何平滑我的峰值? 需要效率高,因为我有很大的数组(最多达到1000x1000)。


这是一个浮点数数组。我在打印函数中将它们转换为字符串,以便更易读。但所有的逻辑都是基于浮点数完成的。 - Rasmus
你的代码无法运行,因为有一堆未定义的变量:kern_widthkern_heightpeak_array... - Nils Werner
我的代码运行了,我没有包含整个文件。它们已经被定义了。peak_array是包含峰值的数组。 - Rasmus
4
请提供一个示例代码,能够适用于所有人而不仅仅是你自己,并提供能够复现你所看到的行为的确切参数。 - Nils Werner
你不能只使用一个更窄的内核吗? - Paul Panzer
显示剩余4条评论
1个回答

1
因此,如果k是您的内核,*是卷积,v1,..v4是像您发布的第一个输入矩阵一样的输入矩阵,您可以对它们求和并获得另一个矩阵w。

w = v1 + v2 + v3 + v4

您正在应用线性操作——卷积。

output = k * w = k * (v1+v2+v3+v4) = k * v1 + k2 * v2 ...

如果您注意到,在角落处输入四个1(Inp2)基本上与仅有一个1的初始矩阵的四个总和(Inp1)相同。
您可以通过简单地旋转Inp1 90度并求和(在numpy中进行转置和fliprl)来构建Inp2。因此,您只需旋转第一次计算的结果并将其相加即可找到正确的最终结果。
非常不可能,由于Inp1的四个旋转版本之和与应用于Inp2的卷积不同。
如果是这种情况,可能是一个数值问题(如果你使用这些数字,就不应该出现这种情况)。仔细检查一下你如何使用最大值和最小值对数据进行重新缩放。你正在除以最大值,所以确保它是非负的,而且比一个eps更大。

嗯,我明白了。我想要能够在任何地方放置峰值,而不仅仅是在角落处。我考虑使用插值来解决这个问题,而不是卷积。 - Rasmus
无论您将它们放在何处,都可以应用相同的原则,因为卷积是平移不变的。 - 00__00__00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接