Расстояние до границы, представленной 2D / 3D NumPy Массивами - PullRequest
0 голосов
/ 29 апреля 2020

У меня есть большие 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

enter image description here

Ответы [ 2 ]

1 голос
/ 29 апреля 2020

Определенно работа для поиска ближайшего соседа:

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 соседей и возвращает вам как евклидово distance, так и index результата в оригинальном дереве. Действительно полезный инструмент. См. График ниже:

First nearest neighbour

Также результат для вторых ближайших соседей, передайте от 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])

second nearest neighbour

1 голос
/ 29 апреля 2020

Вы можете найти местоположения всех 1 с, получить евклидовы расстояния до заданного местоположения и вернуть наименьшее, используя 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)
...