Reputation: 3782
Is there a manner in which to make circle detection parameter-less? - And why do the parameters in cv2.HoughCircles()
not get affected sometimes after changing them? I have a for loop to alter parameters but it will not affect the outcome all of the time.
It seems that Hough Circles requires a lot of parameter optimization by the user, which is an awful problem if the user is wanting to use the system in a very generalized manner. Therefore, I am attempting to create an algorithm to find the best parameters for opencv's houghcirlces function automatically. The houghcirlces function at the moment takes in a maximum and minimum radius for circles that it will find in an image with some thresholds for how good of a match the circles are that are found.
However I ran into this problem:
For example, we may take this image:
(source: stanford.edu)
and run the following code I have on it:
import numpy as np
import cv2
file_path = '1.png'
img = cv2.imread(file_path)
gray = cv2.imread(file_path, cv2.IMREAD_GRAYSCALE)
# Begin using the largest dimesion of the image as the largest possible radius
largest_dimension = np.max([gray.shape[0], gray.shape[1]])
for i in range(1,100):
# For the first iteration we use the largest possible radius
if i == 1:
maxRadius = largest_dimension
# THe next iterations we use what the minimum radius was last iteration
else:
maxRadius = minRadius
# Reduce the size by 2 everytime
minRadius = maxRadius/2
dp = 1 # Inverse ratio of thresholded image resolution ?? Not sure what to do with this
minDist = minRadius # Not likely to be much closer than the minimum radius...?
param1 = 200 # Canny edge threshold - image OTSU threshold dependence ??
param2 = 100 # Hough space threshold - radius dependance? np.pi*maxRadius**2 ??
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius)
# Display some inforation about the results
if circles is not None:
img_copy = img.copy()
radii = np.array([c[2] for c in circles[0]])
num = len(circles[0])
avg = np.mean(radii)
print str(num) + ' found: avg radius: ' + str(avg)
if any(radii < minRadius) or any(radii > maxRadius):
print 'The minimum and maximum radii given are not being respected'
for c in circles[0]:
cv2.circle(img_copy, (c[0],c[1]), c[2], (255,0,255),2)
cv2.namedWindow('', cv2.WINDOW_NORMAL)
cv2.imshow('',img_copy)
cv2.waitKey(0)
We will get the output shown below and that radii are not respected by the function everytime. Also, if we change param1 and param2 (Canny edge detection and Hough space thresholds) from 3 to 6000 almost nothing changes.
Clearly the image shown below has detected far more circles than any person typically would, and it only gets worse.
I may mention that the images I would like to use this script on in the future will appear as something such as this:
Upvotes: 2
Views: 3608
Reputation: 137
To more accurately detect circles and get rid of noise, I would actually perform a canny edge detector on the grayscale image before sending it to the HoughCircles() method. By doing this, you get a lot more precision with threshold of the edge detection since you have full control of both parameters rather than just one.
Canny(src_gray, src_gray, 300, 500, 3 );
HoughCircles( src_gray, circles, CV_HOUGH_GRADIENT, 1, image.rows/2, 30, 30, 40, 1000 );
Play around with the parameters for canny() method, specifically the 300 and 500 and find a sweet spot for your use case. Hope this is helpful! Good luck
Upvotes: 0
Reputation: 22060
I had this same problem with the parameters behaving oddly - you have
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, dp, minDist, param1, param2, minRadius, maxRadius)
but the function signature is actually
>>> import cv2
>>> print cv2.HoughCircles.__doc__
HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles
note the circles
in the parameter list -
I had copied some code from somewhere which explicitly named the remaining parameters, like
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,param1=50,param2=30,minRadius=0,maxRadius=0)
and at some point I removed the names. Mistake!
Upvotes: 0