user5705019
user5705019

Reputation: 37

Detecting Overlapping Circles in OpenCV

I'm using the OpenCV library for Python to detect the circles in an image. As a test case, I'm using the following image:

bottom of can:

enter image description here

I've written the following code, which should display the image before detection, then display the image with the detected circles added:

import cv2
import numpy as np

image = cv2.imread('can.png')
image_rgb = image.copy()
image_copy = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
grayscaled_image = cv2.cvtColor(image_copy, cv2.COLOR_GRAY2BGR)

cv2.imshow("confirm", grayscaled_image)
cv2.waitKey(0)

cv2.destroyAllWindows()


circles = cv2.HoughCircles(image_copy, cv2.HOUGH_GRADIENT, 1.3, 20, param1=60, param2=33, minRadius=10,maxRadius=28)


if circles is not None:
    print("FOUND CIRCLES")
    circles = np.round(circles[0, :]).astype("int")
    print(circles)
    for (x, y, r) in circles:
        cv2.circle(image, (x, y), r, (255, 0, 0), 4)
        cv2.rectangle(image, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)
    cv2.imshow("Test", image + image_rgb)
    cv2.waitKey(0)

cv2.destroyAllWindows()

I get this:resultant image

enter image description here

I feel that my problem lies in the usage of the HoughCircles() function. It's usage is:

cv2.HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]])

where minDist is a value greater than 0 that requires detected circles to be a certain distance from one another. With this requirement, it would be impossible for me to properly detect all of the circles on the bottom of the can, as the center of each circle is in the same place. Would contours be a solution? How can I convert contours to circles so that I may use the coordinates of their center points? What should I do to best detect the circle objects for each ring in the bottom of the can?

Upvotes: 3

Views: 2366

Answers (1)

Akhilesh Sreedharan
Akhilesh Sreedharan

Reputation: 25

Not all but a majority of the circles can be detected by adaptive thresholding the image, finding the contours and then fitting a minimum enclosing circle for contours having area greater than a threshold

import cv2
import numpy as np

block_size,constant_c ,min_cnt_area = 9,1,400
img = cv2.imread('viMmP.png')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
thresh = cv2.adaptiveThreshold(img_gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,block_size,constant_c)
thresh_copy = thresh.copy()
contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
    if cv2.contourArea(cnt)>min_cnt_area:
        (x,y),radius = cv2.minEnclosingCircle(cnt)
        center = (int(x),int(y))
        radius = int(radius)
        cv2.circle(img,center,radius,(255,0,0),1)
cv2.imshow("Thresholded Image",thresh_copy)
cv2.imshow("Image with circles",img)
cv2.waitKey(0)

Now this script yields the result:

enter image description here

enter image description here

But there are certain trade-offs like, if the block_size and constant_c are changed to 11 and 2 respectively then the script yields:

enter image description here

enter image description here

You should try applying erosion with a kernel of proper shape to separate the overlapping circles in the thresholded image

You may look at the following links to understand more about adaptive thresholding and contours:

Threshlding examples: http://docs.opencv.org/3.1.0/d7/d4d/tutorial_py_thresholding.html

Thresholding reference: http://docs.opencv.org/2.4/modules/imgproc/doc/miscellaneous_transformations.html

Contour Examples: http://docs.opencv.org/3.1.0/dd/d49/tutorial_py_contour_features.html

Upvotes: 1

Related Questions