【问题标题】:Distance to boundary represented by 2D/3D NumPy Arrays由 2D/3D NumPy 数组表示的边界距离
【发布时间】:2020-04-29 17:12:34
【问题描述】:

我有大型 2D/3D NumPy 二进制值数组。 1 代表边界,0 代表区域。附带一个步长数组,表示每个维度的步长大小。

我正在寻找一个高效的程序,它可以找到(其中一个)与给定元素最近的边界元素。距离是欧式距离。

2D 示例:

import seaborn as sns
import numpy as np

step_size = np.array([5,5])  # size of step in each dimension
arr = np.array([[0,0,0,0,0,0,0,0,1,0],[1,0,0,0,0,0,0,1,0,0],[1,0,0,0,0,0,0,1,0,0],[0,1,0,0,0,0,1,0,0,0],[0,0,1,0,0,0,0,1,0,0],[0,0,1,1,1,1,1,0,0,0]])
sns.heatmap(arr, annot=True, cbar=False, linewidths=.3)

a = (0,2)  # a given element index
b = (1,0)  # nearest boundary element index, which is to be found by the program

a_coor = np.multiply(np.array(a), step_size)  # array([0,10])
b_coor = np.multiply(np.array(b), step_size)  # array([5,0])

distance = np.linalg.norm(a_coor-b_coor)  # 11.18

【问题讨论】:

标签: python arrays numpy matrix geometry


【解决方案1】:

绝对是最近邻搜索的工作:

import seaborn as sns
import numpy as np
from sklearn.neighbors import KDTree
from matplotlib import pyplot as plt

step_size = np.array([5,5])  # size of step in each dimension
arr = np.array([[0,0,0,0,0,0,0,0,1,0],[1,0,0,0,0,0,0,1,0,0],[1,0,0,0,0,0,0,1,0,0],[0,1,0,0,0,0,1,0,0,0],[0,0,1,0,0,0,0,1,0,0],[0,0,1,1,1,1,1,0,0,0]])
sns.heatmap(arr, annot=True, cbar=False, linewidths=.3)

# get boundary pts (+0.5 to center for plot)
boundary = np.column_stack(np.nonzero(arr)) + 0.5

# create tree
tree = KDTree(boundary)

# get zero points to test for
zeros = np.column_stack(np.nonzero(~arr)) + 0.5

# get nearest neighbour boundary point for each zero
distance, index = tree.query(zeros)

# plot the results
for i, pt in enumerate(zeros):
    plt.gca().plot([pt[1], boundary[index[i,0]][1]], [pt[0], boundary[index[i,0]][0]], 'r')

KDTree 可以轻松计算k 邻居,并返回原始树中结果的欧几里得distanceindex。一个非常有用的工具。见下图:

还有第二近邻的结果,将k=2 传递给query 并绘制:

# plot the results
colors = ['r', 'b']
for i, pt in enumerate(zeros):
    for k in range(index.shape[1]):
        plt.gca().plot([pt[1], boundary[index[i,k]][1]], [pt[0], boundary[index[i,k]][0]], colors[k])

【讨论】:

  • 谢谢!真是令人印象深刻。 step_size 怎么也包含在内?这里为简单起见,我将它们全部设置为 5,但它们不一定相等。
  • KDTree 只需要一个点数组,它们不必是整数,因此您可以将其包含在其中。或者,为了解决这里的问题,邻居之间的笛卡尔距离由delta = boundary[i] - boundary[index[i,0]] 给出,因此您可以轻松地在此处添加任何步长,甚至是不均匀的步长,例如。 d = delta * (6,4) 其中(6,4) 是您的步长。然后我会使用np.linalg.norm(d) 来获得你的欧几里得距离。我希望这会有所帮助!
  • 谢谢。还有我的另一个相关的question,现在我认为可以使用类似的方法来解决。至少对于它的 2D/3D 版本来说,还是可以的。
  • @Reveille 我刚刚看了你的链接问题,我认为最近邻搜索在这种情况下也能很好地工作。
【解决方案2】:

您可以找到所有1s 的位置,获取到给定位置的欧几里得距离,并在结果上使用argpartition 返回最小值:

def nearest_boundary(x, loc):
    ones = np.c_[np.where(arr == 1)]
    dist = ((ones - loc)**2).sum(1)
    return ones[dist.argpartition(0)[0]]

一些例子:

nearest_boundary(arr, (0,2))
# array([1, 0], dtype=int64)

nearest_boundary(arr, (2,4))
# array([3, 6], dtype=int64)

使用 3D 数组:

np.random.seed(2)
arr = np.random.choice([0,1], p=[0.8,0.2], size=(3,5,4))

array([[[0, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
        [1, 0, 1, 0]],

       [[0, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0],
        [0, 0, 0, 0]],

       [[1, 0, 1, 0],
        [0, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 1]]])

nearest_boundary(arr, (0,3,0))
# array([0, 4, 0], dtype=int64)

【讨论】:

  • 谢谢!我实际上正在考虑一种方法,该方法首先找到周围的边界,然后只计算那些边界。 (比如,如果地区是国家,它不会计算到世界上所有边界的距离)。但我会检查这对我的情况是否足够有效。
猜你喜欢
  • 2012-12-09
  • 2014-06-02
  • 1970-01-01
  • 2017-06-15
  • 1970-01-01
  • 2021-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多