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!