p4rzival
p4rzival

Reputation: 3

Correct tuning of parameters for Hough circles transform

I'm trying to locate the circles in this image using the Hough transform, however I can't get good results, in fact they are quite bad, however I don't understand what's wrong, the image looks quite clean to me

here is the code:

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
morph = cv2.morphologyEx(drilling_gray_image, cv2.MORPH_CLOSE, kernel, iterations=2)

cv2_imshow(morph)
plt.figure(figsize=(20, 4))
plt.imshow(morph, cmap='gray', vmin=0, vmax=255)

_, bin_image = cv2.threshold(morph, 128, 255, cv2.THRESH_BINARY)
plt.figure(figsize=(20, 4))
plt.imshow(bin_image, cmap='gray', vmin=0, vmax=255)

rows = bin_image.shape[0]
circles = cv2.HoughCircles(bin_image, cv2.HOUGH_GRADIENT, minDist=10, dp=rows / 16, param1=100, param2=200, minRadius=0, maxRadius=0)
print(circles)

result = drilling_gray_image.copy()
if circles is not None:
  circles = np.uint16(np.around(circles))
  for i in circles[0, :]:
    center = (i[0], i[1])
    # circle center
    cv2.circle(result, center, 1, (0, 100, 100), 3)
    # circle outline
    radius = i[2]
    cv2.circle(result, center, radius, (255, 0, 255), 3)

plt.figure(figsize=(20, 4))
plt.imshow(result, cmap='gray', vmin=0, vmax=255)

here you can find the starting image: link

I try to follow this example that is similar to my case: stackoverflow

can anybody help me in detecting the circle in the image after the binarization?

Upvotes: 0

Views: 114

Answers (1)

Barış Aktaş
Barış Aktaş

Reputation: 426

i am not the expert on HoughCircle Algorithm but let me show you how i would do it:

  • First your image has circles with varying radius, so divide them into categories.
  • Calibrate the algorithm for each category with narrower limits and more precision. (which is also easier)

Also about the parameters of the HoughCircle Algorithm:

  • minDist : minimum distance between any to circle centers.
  • dp : just use recommended value 1.5 except for very smal circles.
  • param1 : high threshold for Canny Edge Detection, also low threshold is set to half of param1. Therefore first try canny on your image and find the best value for this.
  • param2 : i am not exactly sure about this one but smaller means more circles. In the documentation it is explained as it is the accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first.
  • minRadius : name is the explanation
  • maxRadius : name is the explanation

For tuning the HoughCircles transform, first give fixed values to minDist, minRadius and maxRadius according to your circle's radius. Choose the best canny high threshold value by applying cv2.Canny() and set it to param1 and use the recomended dp = 1.5. Finally, play with the last remaining variable which is param2.

Now, for your example i divided the circles into 3 categories according to their radius, 2 big ones on the left (green colored), 3 mid sized ones at the bottom (blue colored), and the remaining small ones (red colored). After running the algorithm for each category this is the final result:

enter image description here

As you see for the mid sized circles there is a false one inside a green circle. You can eliminate theese type false cirles with various methods for example after finding each circle draw them filled on the source image. I hope this is helpful for you.

This is the final code:

import cv2
import numpy

#Read the image and get blurred version
img = cv2.imread('image.png')
result = img.copy()
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
blur = cv2.medianBlur(gray,9)

#Run the hough algorithm three times 
small_circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, minDist=20, dp=1, param1=100, param2=30, minRadius=7, maxRadius=40)
big_circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, minDist=100, dp=1, param1=100, param2=20, minRadius=90, maxRadius=120)
mid_circles = cv2.HoughCircles(blur, cv2.HOUGH_GRADIENT, minDist=60, dp=1, param1=100, param2=12, minRadius=50, maxRadius=65)


#Draw detected small circles
if small_circles is not None:
    small_circles = numpy.uint16(numpy.around(small_circles))
    for i in small_circles[0, :]:
        center = (i[0], i[1])
        radius = i[2]
        cv2.circle(result, center, radius, (0, 0, 255), 3)


#Draw detected big circles
if big_circles is not None:
    big_circles = numpy.uint16(numpy.around(big_circles))
    for i in big_circles[0, :]:
        center = (i[0], i[1])
        radius = i[2]
        cv2.circle(result, center, radius, (0, 255, 0), 3)


#Draw detected mid circles
if mid_circles is not None:
    mid_circles = numpy.uint16(numpy.around(mid_circles))
    for i in mid_circles[0, :]:
        center = (i[0], i[1])
        radius = i[2]
        cv2.circle(result, center, radius, (255, 0, 0), 3)

#Show the result image
cv2.imshow('img',cv2.resize(result,(0,0),fx=0.5,fy=0.5))
cv2.waitKey()

Upvotes: 1

Related Questions