First of all I'm a beginner in programming so please be indulgent.
I'm trying to detect an unique circle in a picture with HoughCircles from opencv.
detected_circles = cv2.HoughCircles(bw_contoured_img8,
cv2.HOUGH_GRADIENT, 1, 20, param1 = 255,
param2 = 30, minRadius = 25, maxRadius = 80)
By taking the hyperparameters up there, the circle is being pretty well detected. The problem is that this handmade tuning was pretty hazardous and poorly reproducible. Moreover, it was necessary to see the result each time and adapt in consequence.
The wider goal is to do that on multiple very similar pictures, but with few differences like maybe little translations/rotations, and the pre-processed picture is changing a little bit from one picture to another. So I wanted to find a way to "automatize" this hyperparameter research.
I found this post with this answer that seemed to perfectly match my expectations. But for some reason, the following code gave me a way too big circle, worse than the manually tuned one.
# load the image, clone it for output, and then convert it to grayscale
image = bw_contoured_img8
orig_image = np.copy(image)
output = image.copy()
circles = None
min_circle_size = 30
maximum_circle_size = 70 # Maximum possible circle size we're willing to find in pixels
guess_dp = 1.0
number_of_circles_expected = 1 # We expect to find just one circle
breakout = False
# Hand tuning
max_guess_accumulator_array_threshold = 100 # Minimum of 1, no maximum, the quantity of votes needed to qualify for a circle to be found
circleLog = []
guess_accumulator_array_threshold = max_guess_accumulator_array_threshold
while guess_accumulator_array_threshold > 1 and breakout == False:
# Start out with smallest resolution possible, to find the most precise circle, then creep bigger if none found
guess_dp = 1.0
# print("ressetting guess_dp:" + str(guess_dp))
while guess_dp < 9 and breakout == False:
guess_radius = maximum_circle_size
# print("setting guess_radius: " + str(guess_radius))
# print(circles is None)
while True:
# print("guessing radius: " + str(guess_radius) +
# " and dp: " + str(guess_dp) + " vote threshold: " +
# str(guess_accumulator_array_threshold))
circles = cv2.HoughCircles(orig_image,
cv2.HOUGH_GRADIENT,
dp=guess_dp, # Resolution of accumulator array
minDist=10, # Number of pixels center of circles should be from each other
param1=255,
param2=guess_accumulator_array_threshold,
minRadius=(guess_radius-3), #HoughCircles will look for circles at minimum this size
maxRadius=(guess_radius+3) #HoughCircles will look for circles at maximum this size
)
if circles is not None:
if len(circles[0]) == number_of_circles_expected:
# print("len of circles: " + str(len(circles)))
circleLog.append(copy.copy(circles))
# print("k1")
break
circles = None
guess_radius -= 5
if guess_radius < min_circle_size:
break;
guess_dp += 1.5
guess_accumulator_array_threshold -= 2
# Return the circleLog with the highest accumulator threshold
# Ensure at least some circles were found
for cir in circleLog:
# Convert the (x, y) coordinates and radius of the circles to integers
output = np.copy(orig_image)
if (len(cir) > 1):
print("FAIL before")
exit()
# print(cir[0, :])
cir = np.round(cir[0, :]).astype("int")
# loop over the (x, y) coordinates and radius of the circles
if (len(cir) > 1):
print("FAIL after")
exit()
for (x, y, r) in cir:
# Draw the circle in the output image, then draw a rectangle corresponding to the center of the circle
output = cv2.circle(output, (x, y), r, (255, 255, 255), 2)
output = cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (255, 255, 255), -1)
# Show the output image
plt.imshow(output)
PS. I'm not using cv2.imshow because it makes my Kernel crash (don't really know why but plt.imshow is making the job).