chase
chase

Reputation: 3782

houghcircles - finding parameters

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.

My hope is to split up different ranges for minimum and maximum radii to search within, then to use the found circles across each section to what parameters I should use for the final houghcircles transform. (If anyone has a better approach to this I would love to hear it.)

However I ran into this problem:

It doesn't appear that the minimum and maximum radii parameters, or the Canny and Hough space thresholds are being respected.


For example, we may take this image:

circles
(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.

cicrlces

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

Answers (2)

Abhishek Ravi
Abhishek Ravi

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

Brian Burns
Brian Burns

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

Related Questions