Lily Baker
Lily Baker

Reputation: 75

detecting small circles using houghCircles (OpenCV)

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?

Upvotes: 2

Views: 13141

Answers (2)

Darren Gallagher
Darren Gallagher

Reputation: 101

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]

Upvotes: 3

harshkn
harshkn

Reputation: 771

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 :)

Upvotes: 10

Related Questions