首页 > 解决方案 > 地图地形分析:numpy.roll 函数的替代方案?

问题描述

我正在尝试分析StarCraft 2 bot API给出的地图地形。

此分析的初学者任务是为收割者寻找悬崖,这是 SC2 中可以上下悬崖的特殊单位。

为了解决这个问题,我分析了点本身不可路径(=悬崖)并且北部和南部两个点是可路径的点。在数组中,可路径点标记为 1,不可路径点为 0。

地形图以 2D numpy 数组的形式存在。以下是较大的 200x200 阵列的一小段摘录:

import numpy as np
example = np.array([[0, 0, 0, 0],
                   [0, 1, 1, 0],
                   [0, 0, 0, 0],
                   [0, 1, 1, 0],
                   [0, 0, 0, 0]])

在这里,点 [2, 1] 和 [2, 2] 将匹配点本身不可路径 (=0) 且它们上方和下方的点可路径 (=1) 的标准。

这可以通过以下代码实现:

above = np.roll(example, 1, axis=0) # Shift rows downwards
below = np.roll(example, -1, axis=0) # Shift rows upwards
result = np.zeros_like(example) # Create array with zeros
result[(example == 0) & (above == 1) & (below == 1)] = 1 # Set cells to 1 that match condition
print(repr(result))
#   array([[0, 0, 0, 0],
           [0, 0, 0, 0],
           [0, 1, 1, 0],
           [0, 0, 0, 0],
           [0, 0, 0, 0]])

现在我的问题是,是否可以用更少的代码来实现相同的目标?

np.roll 函数每次都会创建一个新的 np.array 对象,因此分析数百个附近的点可能会导致 100 行不必要的代码和高内存使用。

我试图找到类似的东西

result = np.zeros_like(example)
result[(example == 0) & (example[-1, 0] == 1) & (example[1, 0 == 1)] = 1
# or
result[(example == 0) & ((example[-1:2, 0].sum() == 2)] = 1

这里括号中的数字显示了与当前分析点的相对位置,但我不知道是否有办法让它与 numpy.

此外,在检查“上方”点时,第零行的结果也不清楚:它可以访问最后一行,导致错误或返回默认值(0 或 1)。

编辑: 我找到了这篇文章,它指向了可以在这里应用的scipy convolve2d函数,这可能是我正在寻找的:

import numpy as np
from scipy import signal
example = np.array([[0, 0, 0, 0],
                   [0, 1, 1, 0],
                   [0, 0, 0, 0],
                   [0, 1, 1, 0],
                   [0, 0, 0, 0]])
kernel = np.zeros((3, 3), dtype=int)
kernel[::2, 1] = 1
print(repr(kernel))
# array([[0, 1, 0],
#        [0, 0, 0],
#        [0, 1, 0]])
result2 = signal.convolve2d(example, kernel, mode="same")
print(repr(result2))
# array([[0, 1, 1, 0],
#        [0, 0, 0, 0],
#        [0, 2, 2, 0],
#        [0, 0, 0, 0],
#        [0, 1, 1, 0]])
result2[result2 < 2] = 0
result2[result2 == 2] = 1
print(repr(result2))
# array([[0, 0, 0, 0],
#        [0, 0, 0, 0],
#        [0, 1, 1, 0],
#        [0, 0, 0, 0],
#        [0, 0, 0, 0]])

Edit2: 另一种解决方案可能是scipy.ndimage.minimum_filter似乎工作类似:

import numpy as np
from scipy import ndimage
example = np.array([[0, 0, 0, 0],
                   [0, 1, 1, 0],
                   [0, 0, 0, 0],
                   [0, 1, 1, 0],
                   [0, 0, 0, 0]])
kernel = np.zeros((3, 3), dtype=int)
kernel[::2, 1] = 1
print(repr(kernel))
# array([[0, 1, 0],
#        [0, 0, 0],
#        [0, 1, 0]])
result3 = ndimage.minimum_filter(example, footprint=kernel_vertical, mode="constant")
print(repr(result3))
# array([[0, 0, 0, 0],
#        [0, 0, 0, 0],
#        [0, 1, 1, 0],
#        [0, 0, 0, 0],
#        [0, 0, 0, 0]])

标签: pythonnumpy

解决方案


推荐阅读