How to find the centre of these sometimes-overlapping circles

Viewed 2247

As part of a project I'm working on, I need to find the centre-point of some "blobs" in an image using OpenCV with Python. I'm having a bit of trouble with it, and would truly appreciate any help or insight :)

My current method is to: get the contours of the images, overlay ellipses on those, use the blob detector to find the centre of each of these. This works fairly well, but occasionally I have extraneous blobs that I need to ignore, and sometimes the blobs are touching each-other.

Here's an example of when it goes well: Good source image: Good source image After extracting contours: After extracting contours With the blobs detected: With the blobs detected

And when it goes poorly (you can see that it's incorrectly overlayed an ellipse over three blobs, and detected one that I don't want): Bad source image: Bad source image After extracting contours: After extracting contours With the blobs detected: With the blobs detected

This is the code I currently use. I'm unsure of any other option.

def process_and_detect(img_path):
    img = cv2.imread(path)
    imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    ret, thresh = cv2.threshold(imgray, 50, 150, 0)
    im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    drawn_img = np.zeros(img.shape, np.uint8)
    min_area = 50
    min_ellipses = []
    for cnt in contours:
        if cv2.contourArea(cnt) >= min_area:
            ellipse = cv2.fitEllipse(cnt)
            cv2.ellipse(drawn_img,ellipse,(0,255,0),-1)
    plot_img(drawn_img, size=12)

    # Change thresholds
    params = cv2.SimpleBlobDetector_Params()
    params.filterByColor = True
    params.blobColor = 255
    params.filterByCircularity = True
    params.minCircularity = 0.75
    params.filterByArea = True
    params.minArea = 150
    # Set up the detector
    detector = cv2.SimpleBlobDetector_create(params)

    # Detect blobs.
    keypoints = detector.detect(drawn_img)
    for k in keypoints:
        x = round(k.pt[0])
        y = round(k.pt[1])
        line_length = 20
        cv2.line(img, (x-line_length, y), (x+line_length, y), (255, 0, 0), 2)
        cv2.line(img, (x, y-line_length), (x, y+line_length), (255, 0, 0), 2)
    plot_img(img, size=12)

Thank you so much for reading this far, I sincerely hope someone can help me out, or point me in the right direction. Thanks!

2 Answers
Related