|
import numpy as np |
|
import cv2 |
|
|
|
from scipy.cluster.hierarchy import linkage, fcluster |
|
from scipy.spatial import distance as ssd |
|
|
|
# Read input image and convert to grayscale |
|
img = cv2.imread('shapes.jpg') |
|
print("Image shape: " + str(img.shape)) |
|
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
|
|
|
|
|
# Apply adaptive threshold |
|
cv2.imwrite('gray.png',imgray) |
|
thresh = cv2.adaptiveThreshold(imgray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,11,2) |
|
cv2.imwrite('edge.png',thresh) |
|
|
|
|
|
# Find all contours of binary image |
|
_, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
|
|
# Number of contours |
|
num_contours=len(contours) |
|
print("Total number of contours: " + str(num_contours)) |
|
|
|
# Fill up all the shapes |
|
filled=cv2.fillPoly(thresh, pts=contours, color=(255,255,255)) |
|
|
|
# Remove noise by morphological opening |
|
kernel = np.ones((4,1),np.uint8) |
|
filled=cv2.morphologyEx(filled, cv2.MORPH_OPEN, kernel) |
|
|
|
# Crop and save proper contours separately [filter by area] |
|
contour_crop=[] |
|
colour_crop=[] |
|
num_contours=0 |
|
min_area=50 |
|
for cnt in contours: |
|
if(cv2.contourArea(cnt)>min_area): |
|
x,y,w,h = cv2.boundingRect(cnt) |
|
contour_crop.append(filled[y:y+h, x:x+w]) |
|
colour_crop.append(img[y:y+h, x:x+w]) |
|
cv2.imwrite("contour_binary"+str(num_contours)+".png",filled[y:y+h, x:x+w]) |
|
num_contours=num_contours+1 |
|
|
|
# Number of proper contours |
|
print("Number of proper contours: " + str(num_contours)) |
|
|
|
# Initialize similarity matrix |
|
sim_mat=np.zeros((num_contours, num_contours)) |
|
|
|
# Configure cluster settings |
|
cluster=np.zeros(num_contours, dtype=int) |
|
num_classes=4 |
|
colours=[(255,0,0),(0,255,0),(0,0,255),(0,0,0),(255,255,0), (0,255,255),(255,0,255),(128,128,128),(165,42,42)] |
|
|
|
|
|
# Compute similarity matrix [Uses Hu-Moments] |
|
print("Similarity Matrix - Hu Moements") |
|
for i in range(0,num_contours): |
|
for j in range(0, num_contours): |
|
im1=np.array(contour_crop[i]) |
|
im2=np.array(contour_crop[j]) |
|
sim_mat[i][j]=cv2.matchShapes(im1,im2,cv2.CONTOURS_MATCH_I2,0) |
|
print(str(round(sim_mat[i][j],4))+",",end =" ") |
|
print("\n") |
|
|
|
|
|
''' |
|
Cluster the contours using similarity matrix and max cluster no. |
|
Returns cluster vector [Range: 0 - (num_classes-1)] |
|
|
|
''' |
|
Zd = linkage(ssd.squareform(sim_mat), method="complete") |
|
cluster = fcluster(Zd, num_classes, criterion='maxclust') - 1 |
|
print("Cluster:-\n" + str(cluster)) |
|
|
|
|
|
# Draw contour clusters |
|
c=0 |
|
for cnt in contours: |
|
if(cv2.contourArea(cnt)>min_area): |
|
x,y,w,h = cv2.boundingRect(cnt) |
|
cv2.imwrite("contour_coloured"+str(c)+".png",img[y:y+h, x:x+w]) |
|
cv2.rectangle(img,(x,y),(x+w,y+h),colours[cluster[c]],2) |
|
c=c+1 |
|
|
|
# Show output in window |
|
cv2.imshow("Bounding Boxes", img) |
|
cv2.waitKey(0) |
|
cv2.destroyAllWindows() |