2

I am trying to obtain an ndarray of points along the boundary of a shape denoted by 1's in the array. I tried using scipy.spatial.ConvexHull but the boundary created by the convex hull did not account for the hole in the middle of the shape (I need a boundary around the hole too). This is the kind of boundary I am trying to create from the array. How can I account for the hole in the shape?

enter image description here

The colored in area is the area that the boundary points should be calculated from. enter image description here

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')
4
  • The image is not clear to me, for example, why is (3, 2) part of the frontier but (1, 3) is not? Commented Apr 15, 2019 at 21:03
  • @vlizana updated the image to show image I am trying to make a boundary from Commented Apr 15, 2019 at 21:12
  • 2
    thanks, but I still can't tell if you're going for a v4 or v8 frontier. For example in the picture you just uploaded, using a v8 neighborhood every point (1) would be part of the frontier, where as in the v4 kind there are a few who are interior points. Commented Apr 15, 2019 at 21:17
  • In the picture I drew out a v4 frontier. I presume the method would be the same for v4 as it is for v8 too Commented Apr 15, 2019 at 21:55

1 Answer 1

1

This is a bit hacky, but if you convolve the zeros with the right kernel (v4 or v8) you get the outer part plus the frontier, so if you do an and kind of operation with the inner part you get only the frontier. Here's an example:

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.