How to connect the points from a contour of a binary image

Viewed 466

I have a segmentation result stored in a binary image, from which i want to extract the contours. To do so, I compute the difference between the mask and the eroded mask. Hence, I am able to extract the pixels that are on the boundaries of my segmentation result. Here is a code snippet:

import numpy as np
from skimage.morphology import binary_erosion
from matplotlib import pyplot as plt

# mask is a 2D boolean np.array containing the segmentation result
contour_raw=np.logical_xor(mask,binary_erosion(mask)) 
contour_y,contour_x=np.where(contour_raw)

fig=plt.figure()
plt.imshow(mask)
plt.plot(contour_x,contour_y,'.r')

I end up with a collection of dots on the contours of the mask:

enter image description here

The troubles starts when I want to connect the dots. Doing a naive plot of the contours results of course in a disappointing results, because contour_x and contour_y are not sorted as I would like:

plt.plot(contour_x,contour_y,'--r')

And here is the result, with a focus on an arbitrary part of the figure to highlight the connection between the dots:

enter image description here

How is it possible to sort the contours coordinates contour_x and contour_y so that they are correctly ordered when I connect the dot? Furthermore, if my mask contains several independent connected component, I would like to obtain as many contours as there are connected components.

Thanks for your help!

Best,

1 Answers

I think combining a clustering and convex hull works in your case. For this example, I am generating three synthetic segments using make_blobs function and demonstrating each with a color:

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import DBSCAN
from scipy.spatial import ConvexHull, convex_hull_plot_2d

X, y = make_blobs(n_samples=1000, centers=3, n_features=2, random_state=0, cluster_std=0.3)
plt.scatter(X[:,0], X[:,1], c=y)

Synthetic segments

Then, since segments are distributed in a two dimensional map, we can run density based clustering method to cluster them, and then by finding a convex hull around each cluster, we can find points surrounding those clusters coming with order:


# Fitting Clustering
c_alg = DBSCAN()
c_alg.fit(X)
labels = c_alg.labels_

for i in range(0, max(labels)+1):
    ind = np.where(labels == i)

    segment = X[ind, :][0]
    hull = ConvexHull(segment)

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

Convex hull

However in your case Concave Hull should work not Convex Hull. There is a package alphashape in python that claimed to find Concave hulls in two-dimensional maps. More information here. The tricky part is to find the best alpha, but in this example, we can fit concave hulls using:

import alphashape
from descartes import PolygonPatch

fig, ax = plt.subplots()
for i in range(0, max(labels)+1):
  ind = np.where(labels == i)
  points = X[ind, :][0,:,:]

  alpha_shape = alphashape.alphashape(points,5.0)
  ax.scatter(*zip(*points))
  ax.add_patch(PolygonPatch(alpha_shape, alpha=0.5))

plt.show()

Concave Hull

Related