How to detect optical circles(hollow as well as filled)? Is there any approach which can solve segementation issue in generalize way?
I was not able to detect optical circle when I apply the following approach:
import numpy as np
import cv2
image= cv2.imread("cropped.jpg")
lower_bound = np.array([0,0,0])
upper_bound = np.array([255,255,195])
blur_factor = (3,3)
image= cv2.blur(image, blur_factor)
mask = cv2.inRange(image, lower_bound, upper_bound)
kernel = np.ones((3,3),np.uint8)
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
for c in contours:
(x,y),r = cv2.minEnclosingCircle(c)
center = (int(x),int(y))
r = int(r)
if r >= 12 and r<=15:
cv2.circle(image,center,r,(0,255,0),2)
array.append(center)
for i in array:
text_color = (0, 0, 255)
cv2.putText(image, str(ii), i, cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 2)
ii = ii + 1
cv2.imshow("masked",mask)
cv2.imshow("circled",image)
cv2.waitKey(0)
Your question is not entirely clear, but I'm gonna go ahead and suppose you wanna detect black circles on these images.
I'm not gonna delve into smoothing parameters, I don't think that's the issue here (not very blurry image, and easy to segment). Your code is fine for detecting components enclosed in a circle with a certain radius. You're getting a bunch of false positives because an object enclosed in a circle is not necessarily a circle.
Consider the two following pink objects : with your code, both of them are detected with an enclosing circle (in white) with the same radius
Since here we are lucky to try to detect full circle, an easily recognizable object, I would suggest to check for each circle you detect if the object inside it occupies a big part of this circle or not. This will enable to eliminate false positives such as the pink line in example above.
So with minimum tweaking of your code, I would suggest something like
import numpy as np
import cv2
image= cv2.imread(your_image)
lower_bound = np.array([0,0,0])
upper_bound = np.array([255,255,195])
blur_factor = (3,3)
image= cv2.blur(image, blur_factor)
mask = cv2.inRange(image, lower_bound, upper_bound)
maskg=np.copy(mask)
kernel = np.ones((3,3),np.uint8)
closing = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
contours = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
contours=contours[1]
array = []
ii = 1
for c in contours:
#for mask creation
imgg=np.zeros(image.shape[0:2])
(x,y),r = cv2.minEnclosingCircle(c)
center = (int(x),int(y))
r = int(r)
if r >= 12 and r<=18:
#potential interesting circle. Let's check if it's a full circle. Create a mask with only your full circle
cv2.circle(imgg,center,r,255,-1)
#mask your thresholded image by this mask
masked=cv2.bitwise_and(maskg.astype(np.uint8),maskg.astype(np.uint8),mask=imgg.astype(np.uint8))
#and count how much white pixels are in this mask (divided by the mask's area)
circle_fullness=np.sum(masked)/(np.pi*r**2*255)
#if more than X% of the area is indeed an object, than you've got yourself a full circle
if circle_fullness>=0.8:
#and then do you consider it as positive
array.append(center)
cv2.circle(image, center, r, (0, 255, 0), 2)
for i in array:
text_color = (0, 0, 255)
cv2.putText(image, str(ii), i, cv2.FONT_HERSHEY_SIMPLEX, 0.5, text_color, 2)
ii = ii + 1
cv2.imshow("masked",mask)
cv2.imshow("circled",image)
cv2.waitKey(0)
Result [deleted on demand]