2

In my image I have 6 segmented objects. My aim is to measure width of each object. However, in some segmented masks, objects touch each other. I am struggling to find a way to separate them. My program works correctly, if there are no merging regions.

Original image: https://i.imgur.com/osQZztn.jpeg Corresponding mask: https://i.stack.imgur.com/i5Jpr.jpg

Code:

import numpy as np
import cv2


#===================================================================================================================
def mask_preprocessing(mask):
    gray = cv2.imread(mask)                                                   #read mask

    #---mask preprocessing stage
    ret,thresh = cv2.threshold(gray,150,255,0)                                #apply threshhold to remove any noise
    kernel_1 = np.ones((5,5), np.uint8)                                       #dilation kernel
    kernel_2 = np.ones((4,4), np.uint8)                                       #erosion kernel
    dilation = cv2.dilate(thresh,kernel_1, iterations=1)                      #apply dialation
    erosion = cv2.erode(dilation, kernel_2, iterations=1)                     #apply erosion
    preprocessed = cv2.cvtColor(erosion, cv2.COLOR_BGR2GRAY)
    #closing = cv2.morphologyEx(dilation, cv2.MORPH_GRADIENT, kernel_1)   
 
    return preprocessed



def overlap_split(preprocessed):

    return 



def find_contours(preprocessed, min_perimeter):
    contours, hierarchy = cv2.findContours(preprocessed,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)        #find contours
    contours_new = []                                                                               #new empty list of contours
    for cnts in contours:                                                                           #looping trough contours
        perimeter = cv2.arcLength(cnts,True)                                                        #arc length
        if perimeter > min_perimeter:                                                               #leave only significant contours
            contours_new.append(cnts)      
    print(len(contours_new)) 

    return contours_new



def measure_pixelwise(img, contours):
    for cnt in contours:
        #get rectangle
        rect = cv2.minAreaRect(cnt)
        (x,y),(w,h), angle = rect

        #display rect 
        box = cv2.boxPoints(rect)
        box = np.int0(box)

        mid_pnt_x = (int((box[0,0]+box[3,0])/2), int((box[0,1]+box[3,1])/2))
        mid_pnt_y = (int((box[1,0]+box[2,0])/2), int((box[1,1]+box[2,1])/2))

        cv2.polylines(img, [box], True, (0,0,255),2)
        cv2.putText(img, 'Width: {}'.format(round(h,1)), (int(x)-200,int(y)-50), cv2.FONT_HERSHEY_PLAIN, 5, (100, 200, 0), 2)
        cv2.arrowedLine(img, mid_pnt_x, mid_pnt_y, (0,0,255), 2, tipLength = 0.02)                    
        cv2.arrowedLine(img, mid_pnt_y, mid_pnt_x, (0,0,255), 2, tipLength = 0.02)

    return img



def conversion(org_width):

    return 
#===================================================================================================================



min_perimeter = 7000                                                           #min perimeter
img_num = 6
results_path = 'results/'
image_path = 'images/'
true_img = image_path+str(img_num)+'_image.bmp'                                #actual image
mask = image_path+str(img_num)+'_predicted_mask.bmp'                           #corresponding mask

image = cv2.imread(true_img)                                                   #read true image
preprocessed = mask_preprocessing(mask)                                        #mask preprocessing
contours = find_contours(preprocessed, min_perimeter)                          #contour extraction considering minimum contour length
img_final = measure_pixelwise(image, contours)                                 #measuring planks width pixelwise


#---save image
cv2.imwrite(results_path+str(img_num)+'_measured.bmp',img_final)

Result: https://i.imgur.com/qDMDBL8.jpeg

Above algorithm doesn't work with the following segmented mask: https://i.stack.imgur.com/V80Kl.jpg. Separation should be handled after maskpreprocessing() function.

Thank you for any advices!

  • 1
    The image does not look like it has touching parts. Try a different threshold and possibly more erosion. In fact, why are you even dilating (before eroding)? That will cause it to touch and then erosion will not be as effective. – fmw42 Mar 23 '22 at 22:09

0 Answers0