'How to accurately segment the basic shaped elements in a hand drawn sketch?

I am trying to segment the basic shaped elements in a hand-drawn sketch using the cv2.findContours - external contours detection method. But the problem is the accuracy of some segmented elements are not 100% achieved. Inner contours are also considered as a separated element. As well, adjacent elements which are drawn in small-sized are also detected as one element. It would be really helpful if someone can suggest a solution in order to achieve the accuracy of the segmented elements?

Here is the sample sketch. hand drawn sketch

Here is the output. enter image description here

This image shows the result of the external contour detection. But it also has detected the inner contours and segmented them as separated elements.

Here is the code.

import cv2 as cv
import numpy as np
import os

#Read image
img = cv.imread('img/img.jpeg')
#cv.imshow('Img', img)

# resized function
def rescaleImg(img,scale_percent=60):
        height, width, channel = img.shape

        print('original height: ', height)
        print('original width:  ', width)
        print('original channel:', channel)
        if height > 200 or width > 500:
            width = int(img.shape[1] * scale_percent / 100)
            height = int(img.shape[0] * scale_percent / 100)
            dimension = (width, height)
            resized = cv.resize(img, dimension, interpolation=cv.INTER_AREA)
            return resized
        else:
            resized=img
            return resized

#resize image
resized = rescaleImg(img)
#cv.imshow('Rescaled', resized)

#convert to gray
gray= cv.cvtColor(resized, cv.COLOR_BGR2GRAY)
#cv.imshow('gray',gray)

#reduce noice by median blur
median_blur = cv.medianBlur(gray,5,5)
#cv.imshow('median blur',median_blur)

#edge cascade
canny= cv.Canny(gray,30,200)
cv.imshow('canny',canny)

#dialate image
dilated=cv.dilate(canny,(5,5),iterations=3)
cv.imshow('dilated',dilated)

eroded = cv.erode(dilated,(1,1),iterations=3)
#cv.imshow('eroded',eroded)

#convert into threshold
ret, thresh = cv.threshold(eroded,125,255,cv.THRESH_BINARY)
#cv.imshow("Thresh", thresh)

#contour detection
contours,hierarchy = cv.findContours(dilated,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
print('Numbers of contours found=' + str(len(contours)))
#print(contours)

#draw all contours
cont= cv.drawContours(resized, contours, -1, (0,255,0),3)
cv.imshow('External Contours', cont)
 
height, width, channels = resized.shape


#croping image
data=[]
idx =0
for index, cont in enumerate(contours):
    idx += 1
    (x, y, w, h) = cv.boundingRect(cont)
    #print( x, y, w, h)
    x = x - 2
    y = y - 2
    w = w + 4
    h = h + 4

    rect = cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
   
    crop_img = img[y:y + h, x:x + w]
    new = cv.imwrite('img/croped_img/'+ str(idx) + '.jpg', crop_img)
    
#cv.imshow('cropped',img)
cv.waitKey(0)
cv.destroyAllWindows()


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source