Получение границы формы массива numpy с отверстием

#python #numpy #scipy-spatial

#python #numpy #scipy-пространственный

Вопрос:

Я пытаюсь получить ndarray точек вдоль границы фигуры, обозначенной 1 в массиве. Я пытался использовать scipy.spatial.ConvexHull , но граница, созданная выпуклой оболочкой, не учитывала отверстие в середине формы (мне тоже нужна граница вокруг отверстия). Это та граница, которую я пытаюсь создать из массива. Как я могу учесть отверстие в форме?

введите описание изображения здесь

Область, выделенная цветом, — это область, из которой должны быть вычислены граничные точки. введите описание изображения здесь

 import numpy as np
from skimage.measure import label, regionprops
import matplotlib.pyplot as plt
from scipy.spatial import Voronoi, voronoi_plot_2d, ConvexHull


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

coords = []
for x in range(arr.shape[0]):
    for y in range(arr.shape[1]):
        if arr[x][y] > 0:
            tile = [x,y]
            coords.append(tile)
            # print("tile", tile)
coords = np.array(coords)
# print(coords)

hull = ConvexHull(coords)
plt.plot(coords[:,0], coords[:,1], 'o')
for simplex in hull.simplices:
    plt.plot(coords[simplex, 0], coords[simplex, 1], 'k-')

plt.plot(coords[hull.vertices,0], coords[hull.vertices,1], 'r--', lw=2)
plt.plot(coords[hull.vertices[0],0], coords[hull.vertices[0],1], 'ro')
  

Комментарии:

1. Например, мне непонятно, почему изображение является (3, 2) частью границы, но не (1, 3) является?

2. @vlizana обновил изображение, чтобы показать изображение, из которого я пытаюсь сделать границу

3. спасибо, но я все еще не могу сказать, собираетесь ли вы перейти на v4 или v8 frontier. Например, на картинке, которую вы только что загрузили, при использовании окрестности v8 каждая точка (1) будет частью границы, где, как и в виде v4, есть несколько внутренних точек.

4. На картинке я нарисовал границу v4. Я предполагаю, что метод будет таким же для v4, как и для v8

Ответ №1:

Это немного банально, но если вы свернете нули с помощью правильного ядра (v4 или v8), вы получите внешнюю часть плюс границу, поэтому, если вы выполните and какую-либо операцию с внутренней частью, вы получите только границу. Вот пример:

 import numpy as np
from scipy.signal import convolve2d

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

# v4 example, 
kernel = np.array([
    [0,1,0],
    [1,0,1],
    [0,1,0],
])

# you have to zero pad first in order to get the edges
padded = np.pad(arr, ((1, 1), (1, 1)), 'constant', constant_values=0)

# the `astype(bool)` is for normalization
# the `and` operation in this case is the elementwise product
frontier = convolve2d(1-padded, kernel, mode='valid').astype(bool) * arr