detecting small circles using houghCircles (OpenCV)
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.
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]
Lily Baker
Updated on June 17, 2022Comments
-
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:
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?