I want to detect circles in image as below:

So, I tried with cv2.findContours and cv2.Houghcirclesin python, but there were some problems.
Both methods were applied after image processing (Canny, threshold, etc.)
First, if I use cv2.findCountours, it cannot detect outer circles since they were overlapped and detect as a single contour.
Here's my python code.
contours, hier = cv2.findContours(input, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
c= (random.randint(0,255),random.randint(0,255),random.randint(0,255))
if area>10000 and area<100000: # Filtering the target size
(x, y), radius = cv2.minEnclosingCircle(contour)
center= (int(x), int(y))
radius= int(radius)
cv2.circle(color, center, radius, c,5)

Second, if I use cv2.Houghcircles (Split the radius range to detect concentric circles), the results were better, but still the results were poor.
for maxR in range(100,200,10): # minimum 100 to maximum 200 by step 10
circles = cv2.HoughCircles(input, cv2.HOUGH_GRADIENT, 1, 100, param1=100,param2=22,minRadius=minR,maxRadius=maxR)
minR+=10
# Check to see if there is any detection
if circles is not None:
# If there are some detections, convert radius and x,y(center) coordinates to integer
circles = np.round(circles[0, :]).astype("int")
for (x, y, r) in circles:
c= (random.randint(0,255),random.randint(0,255),random.randint(0,255))
cv2.circle(view, (x, y), r, c, 3) # draw circumference
cv2.rectangle(view, (x - 2, y - 2), (x + 2, y + 2), c, 5) # draw center

Is there any better methods to detect concentric circles in image and measure center coordinates and radius of them?
I compared the encloed area and minimum enclosing circle area. And I got circular contours.
contours, hier = cv2.findContours(aaa, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
for contour in contours:
c= (random.randint(0,255),random.randint(0,255),random.randint(0,255))
area = cv2.contourArea(contour)
(cx, cy), radius = cv2.minEnclosingCircle(contour)
err=abs((area-np.pi*radius*radius)/(np.pi*radius*radius))
if err< 0.1:
cv2.drawContours(aaa, [contour], -1, (255,255,255) , thickness=cv2.FILLED)
cv2.drawContours(color, [contour], -1, c , 5)
Then, I filled the area with white color.

Now, the problem is very simple. All I need to do is separate the overlapping circles into their own circles. (I can find many references)
Thanks you all!



I haven't done much analysis or testing, but thought the following approach might produce some reasonable results.
make a grid of "seed" points that covers the entire image - I am thinking the gridlines should be just less than the radius of the smallest circle you hope to find so that we guarantee a seed point in each circle
iterate over the grid points and for each one, flood-fill with red starting from that location
remove everything that is not red in the image and then check the area and circularity of the red area and add to a list if sufficiently circular and suitably sized.
You would get things like this depending whether each seed point is within a cell or the background:
I guess you would have to experiment with the flood-filling parameters, and the circularity measure (available from
findContours()) and also filter the list of results because you would likely detect some circles twice. You would also need to avoid flood-filling starting on the darker cell-boundaries, so maybe you'd want to reduce to 3 colours first so you only get the light white background and the darker grey cell boundaries and the darkest grey boundaries.