Need to find the outer boundary size of droplets in python

Viewed 42

Droplet Images

i am trying to find the outer boundary size of all drops along length of tube using python.

I am struggling to distinguish between outer and inner boundary after canny edge detection.can anyone help me please.

The image preproccessing i have used is like:

# load the image, convert it to grayscale, and blur it slightly
gray = cv2.GaussianBlur(imc, (5, 5), 0)
# perform edge detection, then perform a dilation + erosion to
# close gaps in between object edges
dilate = cv2.dilate(gray, None, iterations=1)
#cv2.imshow('dilated',dilate)
erode = cv2.erode(dilate, None, iterations=1)
#cv2.imshow('eroded',erode)
edged = cv2.Canny(erode,230,230)
#cv2.imshow('%deroded' %count,edged)
###############################################EDGE DETECTION
# find contours in the edge map
cnts= cv2.findContours(edged.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
#plot all contours
#for k in cnts:
    #cv2.drawContours(edged, [k], -1, (255, 255, 255), 2)
    #cv2.imshow('%d allcontours' %count,edged)
# Sort the contours as per Area small to large
cnts=sorted(cnts,key=cv2.contourArea,reverse=True)
# sort the contours from left-to-right 
(cnts, _) = contours.sort_contours(cnts)
contour_list=[]

# loop over the contours individually and find proper contours
#**************************************************************************ContourSelection
for contour in cnts:
    
    approx=cv2.approxPolyDP(contour,0.01*cv2.arcLength(contour,False),True)
    area=cv2.contourArea(contour)
    #print('drop area:',area)
    #print('edges',len(approx))
    #print('arclen',cv2.arcLength(contour,False))
    #print('next-------')
 #change area parameter for detecting size of circle 
     #check if contour is near circle and 
     #if((len(approx)>5)&(area<600) & (area>2) and cv2.arcLength(contour,False)>50):mustard2.5
    if((len(approx)>5)&(area<600) & (area>2) and cv2.arcLength(contour,False)>29): #for open 
contours False must be there in arc length
        contour_list.append(contour)
        #print('selected drop area',area)
        #print('selected edges',len(approx))
        #print('selected contour',cv2.isContourConvex(contour))
        #print('contourlength',cv2.arcLength(contour,False))
        #print('next')
cnts=contour_list
    # sort contours again as per area
#cnts=sorted(cnts,key=cv2.contourArea,reverse=True)
    #substitute blank contour if no contour found in image

if len(cnts)==0:
   cnts.append(np.array([[[0,0]],[[0,0]],[[0,0]]])) 
  1. This code gives me inner edges easily but i want outer edges.

  2. You can see droplet boundary is sufficiently thick and varies from case to case.

  3. I have to process 4000 images in a sequence.please guide me.

  4. i am unable to distinguish between droplet boundary and tube boundary.

How to eliminate inner edges and filter outer edges only?

expected output image i want to improve

above one is near expected output.

1 Answers

enter image description here A thresholding step and refined threshold values for your canny will provide only the outer edges. I performed preliminary histogram analysis data exploration (see OpenCV's calcHist function for further details) to gauge these threshold values.

Once you perform a thresholding step you can use either the thresholded image or the canny result to find contours, as seen in the image above.

If you still find both inner and outer edges in the future, I'd suggest grouping contours by their bounding box center, then filtering out smaller contours that share a similar center with a bigger contour of mildly larger area.

# gray = cv2.GaussianBlur(im, (5, 5), 0)

dilate = cv2.dilate(gray, None, iterations=1)
erode  = cv2.erode(dilate, None, iterations=1)

_, thresh = cv2.threshold(erode, 108, 255, cv2.THRESH_BINARY)
edged    = cv2.Canny(thresh, 144, 250)

canny_cnts, _  = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
thresh_cnts, _ = cv2.findContours(255-thresh[:,:,0], cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

f, ax = plt.subplots(3,1,figsize=(20,7))

for a, i, t in zip(ax, [erode, thresh, edged], ['Eroded', 'Thresholded', 'Canny']):
    a.imshow(i, 'gray')
    a.axis('off')
    a.set_title(t)

for a, cnts in zip(ax[1:], [thresh_cnts, canny_cnts]):
    for cnt, col in zip([ c[:,0] for c in cnts ], colors):
        a.plot( cnt[:,0], cnt[:,1], color=col, lw=2)
Related