Delimit the position of cv2.houghCircles

Viewed 1064

Is there an option to delimit the x, y coordinates where I want to find a circle with the function cv2.HoughCircles?

I want to find circles where I click; with cv2.setMouseCallback I save the mouse position, but I don't know what I have to pass to cv2.HoughCircles.

cv2.HoughCircles returns an array with [Xposition, Yposition, radius].

I think maybe I can work with the first and second parameter, but I don't how to access them, because when I write print(circles[0]) the three values appear.

When I write print(x), the error message "local variable 'x' referenced before assignment" is returned.

Any ideas?

Thank you!

3 Answers

Do you want to get circles with center given by cv2.setMouseCallback(approach 2) or you want circle near cv2.setMouseCallback this region(approach 1).

  1. Crop the image before passing to houghCircles function crop_img = img[y-h:y+h, x-w:x+w] where x and y are the values returned by cv2.setMouseCallback. You can vary (h,w) depending upon how much area you want to use for finding circles

  2. After running cv2.houghCircles for whole image, you get an array with [Xposition, Yposition, radius].

    for( size_t i = 0; i < circles.size(); i++ ){
     Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
     int radius = cvRound(circles[i][2]);
    }
    

circles[i][0] and circles[i][1] gives x and y coordinate of center of circle. You can now use cv2.setMouseCallback to filter out wanted circles.

It is not possible to provide coordinates as an input to cv2.HoughCircles to find circles centred around that location. What you can do instead is process the returned array and extract the circles that contain the coordinates.

As you have seen, the result from circles[0] gives all three parameters of x-coordinate, y-coordinate and radius. To extract individual parameters you just need to specify which:

circles[0][0] will return the x-coordinate;
circles[0][1] will return the y-coordinate; and
circles[0][2] will return the radius.

You can store all of them in Python in one line with:

x, y, r = circles[0]

which is effectively the same as writing

x = circles[0][0]
y = circles[0][1]
r = circles[0][2]

Then with the x and y coordinates from cv2.HoughCircles and from the mouse click, you can check which circles match the wanted result.

You can do this using the general centre-radius equation for a circle

(x – h)^2 + (y – k)^2 = r^2

where the centre is at the point (h, k).

Thus if (x – h)^2 + (y – k)^2 - r^2 > 0 then the point is outside the circle, and if (x – h)^2 + (y – k)^2 - r^2 < 0 then the point is inside the circle (and if (x – h)^2 + (y – k)^2 - r^2 = 0 then the point is on the circle).

The documentation of HoughCircles says:

circles Output vector of found circles. Each vector is encoded as 3 or 4 element floating-point vector (x,y,radius) or (x,y,radius,votes)

This means that it is a vector of circles. So to print all the x,y,radius of each circle you can do:

for circle in circles:
  print ("(x,y) = (",circle[0],",",circle[1], ") and radius =", circle[2] )

or:

print ("(x,y) = (",circle[0][0],",",circle[0][1], ") and radius =", circle[0][2] )

to print the first circle.

Also, for the mouse position it is possible to pass a subimage like:

# the position of the click as (x,y) 
mousePosition = (10,15)
# the size of the image you want to look when you click (width, height)
swz = (20,20)

#calculate the box top corner  so that is no less than 0 and the right bottom side less than image size

imgSize = img.shape
tl = (max(0, mousePosition[0] - (swz [0] / 2)), max(0, mousePosition[1] - (swz [1] / 2)))
tl = (min(tl[0], imgSize[1] - (swz [0] / 2)), min(tl[1], imgSize[0] - (swz [1] / 2)))
tl = (int(tl[0]), int(tl[1]))

circles =   cv.HoughCircles(img[tl[1]:swz[1]+tl[1], tl[0]:swz[0]+tl[0]], cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0   )

Then to draw them:

# make sure it found anything and make them int
circles = None if circles is None else np.uint16(np.around(circles))
cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR)
for i in circles[0,:]:
    # draw the outer circle
    cv.circle(cimg,(i[0]+tl[0],i[1]+tl[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv.circle(cimg,(i[0]+tl[0],i[1]+tl[1]),2,(0,0,255),3)

An example of this will be with :

mousePosition = (100,170)
swz = (100,100)

and the OpenCVlogo as image and I get this search region:

enter image description here

and this result:

enter image description here

Related