user76284
user76284

Reputation: 1328

Circle detection with OpenCV

How can I improve the performance of the following circle-detection code

from matplotlib.pyplot import imshow, scatter, show
import cv2

image = cv2.imread('points.png', 0)
_, image = cv2.threshold(image, 254, 255, cv2.THRESH_BINARY)
image = cv2.Canny(image, 1, 1)
imshow(image, cmap='gray')

circles = cv2.HoughCircles(image, cv2.HOUGH_GRADIENT, 2, 32)
x = circles[0, :, 0]
y = circles[0, :, 1]

scatter(x, y)
show()

with the following source image:

enter image description here

I have tried adjusting the parameters of the HoughCircles function but they result in either too many false positives or too many false negatives. In particular, I am having trouble with spurious circles being detected in the gap between the two blobs:

enter image description here

Upvotes: 2

Views: 6132

Answers (2)

Graph4Me Consultant
Graph4Me Consultant

Reputation: 353

While it is possible to fine-tune Hough Circles for a given image, the optimal parameters from image to image may vary alot. Hence, it takes quite some effort to make the circle detection robust using Hough Circles, though its doable!

Instead I would suggest to use more modern approaches like:

Upvotes: 2

Michał Gacka
Michał Gacka

Reputation: 3071

@Carlos, I'm not really a big fan of Hough Circles in situations like the one you've described. To be honest, I find this algorithm very unintuitive. What I would recommend in your case is using findContour() function and then calculating mass centers. Thus said, I tuned the Hough's parameters a bit to get reasonable results. I also used a different method for preprocessing before Canny, since I don't see how that thresholding would work in any other case than that particular one.

Hough method: enter image description here

Finding mass centers: enter image description here

And the code:

from matplotlib.pyplot import imshow, scatter, show, savefig
import cv2

image = cv2.imread('circles.png', 0)
#_, image = cv2.threshold(image, 254, 255, cv2.THRESH_BINARY)
image = cv2.GaussianBlur(image.copy(), (27, 27), 0)
image = cv2.Canny(image, 0, 130)
cv2.imshow("canny", image)
cv2.waitKey(0)
imshow(image, cmap='gray')

circles = cv2.HoughCircles(image, cv2.HOUGH_GRADIENT, 22, minDist=1, maxRadius=50)
x = circles[0, :, 0]
y = circles[0, :, 1]

scatter(x, y)
show()
savefig('result1.png')
cv2.waitKey(0)

_, cnts, _ = cv2.findContours(image.copy(), cv2.RETR_EXTERNAL,
    cv2.CHAIN_APPROX_SIMPLE)

# loop over the contours
for c in cnts:
    # compute the center of the contour
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])

    #draw the contour and center of the shape on the image
    cv2.drawContours(image, [c], -1, (125, 125, 125), 2)
    cv2.circle(image, (cX, cY), 3, (255, 255, 255), -1)

cv2.imshow("Image", image)
cv2.imwrite("result2.png", image)
cv2.waitKey(0)

Both methods require some more fine tuning but I hope that gives you something more to work with.

Sources: this answer and pyimagesearch.

Upvotes: 8

Related Questions