I am looking to extract the coordinates of a features perimeter. My intension is to use these coordinates to find the nearest edge-to-edge Euclidean distance for all features of interest from a .tif image. I am relatively new to scikit-image and am wondering if this can be done using options available from https://scikit-image.org/docs/dev/api/skimage.measure.html#skimage.measure.regionprops ?
I am able to extract the filled area binary boolean matrix from skimage.measure.regionprops.
[[False False True True True False False False False False]
[False False True True True True True True False False]
[False False True True True True True True False False]
[False False True True True True True True True False]
[False False False True True True True True True True]
[False True True True True True True True True True]
[False True True True True True True True True True]
[ True True True True True True True True True True]
[ True True True True True True True True True True]
[False True True True True True True True True True]
[False True True True True True True True True True]
[False True True True True True True True True False]
[False True True True True True True True False False]
[ True True True True True True True False False False]
[ True True True True True True False False False False]
[False False True True True False False False False False]]
These features are identified based on grayscale and morphological properties using a binary logistic regression classifier after some smoothing, dilation, and erosion techniques.
My attempt to get the perimeter coordinates:
for m in matrix:
y, x = m.shape
l = []
for i in np.arange(x):
r = np.argwhere(m[:, i][m[:, i] == 0]).ravel().reshape(-1, 1)
t = np.full(shape=len(r), fill_value=i, dtype=int).reshape(-1, 1)
if i==0 or i==x:
coords = np.hstack((r, t))
l.append(coords)
else:
if len(r) <= 1:
coords = np.hstack((r, t))
l.append(coords)
else:
r = r[[0, -1]] # Problem, may not capture all coordinates.
# if the feature has concave regions.
t = np.full(shape=len(r), fill_value=i, dtype=int).reshape(-1,1)
coords = np.hstack((r, t))
l.append(coords)
I think this works if there are no concave regions, unfortunately some of the features I am looking at definitely are crescent shaped. I suppose I could run the function second time across the other axis and identify the unique coordinates? I would imagine there is a better approach.
Also, eventually I need to map these coordinates back on to the original images coordinates. I figure I can use the bounding box corners to do that coordinate transfer. It be nice if I can get the coordinates ordered so I can plot them as a polygon around the feature, but this is not necessary to do the minimum edge-to-edge distance calculation.
Would this solution be something I can add as a udf to scikit-image.measure.regionsprops 'extra_properties' parameter?
With Bilal's response I was able to come up with a suitable solution.
perimeter = binary_image ^ binary_erosion(binary_image)
for i in [0, -1]:
vedges = np.argwhere(m[:, i] == True).ravel()
if len(vedges) == 0: continue
for x in vedges:
perimeter[x, i] = True
hedges = np.argwhere(m[i, :] == True).ravel()
if len(hedges) == 0: continue
for y in hedges:
perimeter[i, y] = True
coordinates = np.argwhere(perimeter == True)