How to separate two touching blobs?

115 Views Asked by At

I have written the following code in order to detect the blobs based on their HSV values, everything works fine, except that when the two blobs intersect(touch) the are detected as one instead of two. I have read here that this can be solved, by using 4-neighborhood and morphological filtering operations, while I have not succeeded in implementing that in my code, I have tried erode operation, but that did not help because I had to combine it with dilate, and they are opposite operations no result was achieved, If I keep only erode all the blobs will be removed and the result will be a black image

This is the input image: enter image description here

The ones on the left are combined as one blob, and I want to separate them, so that I have 7 blobs instead of 6.

import cv2
import numpy as np

img = cv2.imread('./lemon.png')

hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

fruit_mask = cv2.inRange(hsv_img, *hsv_bounds[plant_name])
fruit_mask = cv2.cvtColor(fruit_mask, cv2.COLOR_GRAY2BGR)
result = cv2.bitwise_and(img, fruit_mask)

counter = {}
counter['lemon'] = 0

image_gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
image_gray = cv2.GaussianBlur(image_gray, (5, 5), 0)

image_edged = cv2.Canny(image_gray, 50, 100)
# kernel = np.ones((4, 4), np.uint8)

image_edged = cv2.dilate(image_edged, None, iterations=1)
# kernel = np.ones((4, 4), np.uint8)

image_edged = cv2.erode(image_edged, None, iterations=1)


cnts = cv2.findContours(
    image_edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cnts = cnts[0]

for c in cnts:

    if cv2.contourArea(c) < 200:
        continue

    hull = cv2.convexHull(c)
    img_mask = cv2.drawContours(result, [hull], 0, (0, 0, 255), 1)

    counter['lemon'] += 1

    print(counter)
    cv2.imwrite('./blob_testing/detected_55.png', img_mask)

Update: Thanks to the comments, I understood my mistake, and I have added the erode to the drawn contours (not the canny edges), and that fixed the problem, and the result look like that:

enter image description here

I still need to draw the red contours around the blobs so that I can count them

1

There are 1 best solutions below

0
fana On

Why don't do your process on binary mask image?

Perhaps fruit_mask = cv2.inRange(hsv_img, *hsv_bounds[plant_name]) is the mask. If so, apply morophology(dilate, erode) to this mask to remove noise and separate blobs. Then, findContours on the moropholygy result.

If the result is good(of course you can filter them further (e.g. based on area, shape, etc).), you can count contours, or draw contours on your input image if needed.