Use python opencv to generate irregular masks image without knowing the number of masks

Viewed 94

I have some images and the corresponding ROI positions, I want to use these data to generate a mask image, I have tried to generate some mask images, but it works fine when there is only one ROI, but when there are more than two ROIs causes mask to connect.

Is there any way to generate a Mask image without knowing how many ROIs there are?

code:

import numpy as np
import cv2
from skimage import morphology

def get_mask(imgshape, roi):
    mask = np.zeros(imgshape, dtype=np.int32)
    mask = cv2.fillConvexPoly(mask, roi, 255)
    mask = morphology.binary_closing(mask)
    return mask

mask_img = get_mask((200,200), roi_pos)

ROI = [[104,  94],[105,  94],[106,  93],[105,  92],[104,  91],
[103,  92],[103,  93],[ 95,  94],[ 96,  94],[ 97,  92],[ 97,  91],
[ 97,  91],[ 95,  91],[ 94,  91],[ 93,  93],[ 94,  94]]

Resluts: enter image description here

1 Answers

Since you have many points in a single array, you will have to cluster them. As mentioned by Rahul, K-means is well suited for this job.

One question remains, how do you know how many ROIs are present? In other words, how many clusters do you divide your points into?

I used the silhouette method detailed well in this post and is available in scikit-learn

Code:

import cv2
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

# array of points/coordinates
r = np.array(ROI)

# this range can be increases if many ROIs are present
range_n_clusters = [2, 3, 4, 5]
# list to store silhouette score for each cluster   
silhouette_avg = []
for num_clusters in range_n_clusters:
 kmeans = KMeans(n_clusters=num_clusters)
 kmeans.fit(r)
 cluster_labels = kmeans.labels_
 silhouette_avg.append(silhouette_score(r, cluster_labels))
 
plt.xlabel('Values of K') 
plt.ylabel('Silhouette score') 
plt.title('Silhouette analysis For Optimal k')
plt.plot(range_n_clusters,silhouette_avg,'bx-')
plt.show()

enter image description here

The cluster with the highest silhouette score must be chosen to give best clustering results. The optimal number of cluster based on the graph above is 2.

# K-Means model with 2 clusters
final_kmeans = KMeans(n_clusters = 2)
final_kmeans.fit(r)
final_kmeans.predict(r)

# points and labels to separate lists
r_list = r.tolist()
labels = final_kmeans.predict(r).tolist()
# number of unique clusters
num_clusters = np.unique(final_kmeans.predict(r)).tolist()

# sample mask for demonstration
mask = np.zeros((300, 250,1), dtype=np.uint8)

# select points by their cluster labels and draw them
for clus in num_clusters:
  points = []
  for i, j in zip(r_list, labels):
    if j == clus:
      points.append(i)
  mask = cv2.fillConvexPoly(mask, np.array(points), 255)

enter image description here

Hope this gives you an idea. You can further optimize it. Remember the maximum number of ROIs that can be possible for your data set. You can try other clustering algorithms and also look out for methods that can get you optimal number of clusters

Related