detecting small circles using houghCircles (OpenCV)

10,039

Solution 1

It will take you a long time to solve this if you try to vary the parameters without understanding what they does.

This description is from here

minDist: Minimum distance between the center (x, y) coordinates of detected circles. If the minDist is too small, multiple circles in the same neighborhood as the original may be (falsely) detected. If the minDist is too large, then some circles may not be detected at all.

param1: Gradient value used to handle edge detection in the Yuen et al. method.

param2: Accumulator threshold value for the cv2.HOUGH_GRADIENT method. The smaller the threshold is, the more circles will be detected (including false circles). The larger the threshold is, the more circles will potentially be returned.

minRadius: Minimum size of the radius (in pixels).

maxRadius: Maximum size of the radius (in pixels).

You can clearly see that the circles in your image have fixed radius and have min distance separating them. If you set these two, you can improve your results. So its important to read the docs.

And about your problem, If you have specific necessity to use Houghcircles go ahead and fine tune it. Things you could do to improve are ,preprocess using gaussianblur, use adaptivethreshold instead of just threshold.

If there is no necessity to use Hough circles, I would suggest you to use contours instead. Because it is more robust and generalises well to different images. Here is the results I got using contours. The circles appear smaller because I have used erosion for 6 iterations and dilation only for 3 iterations.

finding circles using contours

Here is the code I used.

import numpy as np
import cv2

image_color= cv2.imread("Ye3gs.png")
image_ori = cv2.cvtColor(image_color,cv2.COLOR_BGR2GRAY)

lower_bound = np.array([0,0,10])
upper_bound = np.array([255,255,195])

image = image_color

mask = cv2.inRange(image_color, lower_bound, upper_bound)

# mask = cv2.adaptiveThreshold(image_ori,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
#             cv2.THRESH_BINARY_INV,33,2)

kernel = np.ones((3, 3), np.uint8)

#Use erosion and dilation combination to eliminate false positives. 
#In this case the text Q0X could be identified as circles but it is not.
mask = cv2.erode(mask, kernel, iterations=6)
mask = cv2.dilate(mask, kernel, iterations=3)

closing = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)

contours = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
        cv2.CHAIN_APPROX_SIMPLE)[0]
contours.sort(key=lambda x:cv2.boundingRect(x)[0])

array = []
ii = 1
print len(contours)
for c in contours:
    (x,y),r = cv2.minEnclosingCircle(c)
    center = (int(x),int(y))
    r = int(r)
    if r >= 6 and r<=10:
        cv2.circle(image,center,r,(0,255,0),2)
        array.append(center)

cv2.imshow("preprocessed", image_color)
cv2.waitKey(0)

Hope this helps :)

Solution 2

In OpenCV 3 the signature of findContours has changed. To get the contours returned you need to change this line:

contours = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]

to this

contours = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[1]
Share:
10,039
Lily Baker
Author by

Lily Baker

Updated on June 17, 2022

Comments

  • Lily Baker
    Lily Baker almost 2 years

    I'm trying to detect small circles in this cropped image using houghcircles(). I tried to change its parameters but it gets errors when i increase param2 above 50 and maxRadius also gets errors when its value is smaller than 100. Now it runs but with bad performance This is the original image: enter image description here

    And this is the result image: enter image description here

    And this is my code:

    from imutils.perspective import four_point_transform
    from imutils import contours
    import numpy as np
    import argparse
    import imutils
    import cv2
    
    im = cv2.imread('crop.png')
    imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
    ret,thresh = cv2.threshold(imgray, 200, 255,cv2.THRESH_BINARY)
    cimg = cv2.cvtColor(thresh,cv2.COLOR_GRAY2BGR)
    
    c = cv2.HoughCircles(thresh, cv2.HOUGH_GRADIENT, 0.5, 41, param1=70, 
    param2=30, minRadius=10,maxRadius=175)
    c = np.uint16(np.around(c))
    
    for i in c[0,:]:
        # draw the outer circle
        cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
        # draw the center of the circle
        cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
    
    cv2.namedWindow('img',cv2.WINDOW_NORMAL)
    cv2.resizeWindow('img', 800,800)
    cv2.imshow('img',cimg)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

    Please, how should i change the parameters?