1

I have images with eight blue and eight red circles.
I want to find the center position ((x, y) in pixels) of each circle and I also want to know whether the circle is red or blue. The circles can have a slight variation in diameter.

This is what I'm trying to process
It feels like this would not be so hard to solve, but it's to hard for me ...

I tried using OpenCV and Template Matching by following a tutorial. It finds all the circles but I don't know how to pinpoint the center or pick the circle-color.
It also seems to draw a lot more than 1 rectangle per circle.

Circles identified using Template Matching

img_rgb = cv2.imread('images/img.png')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('red.png',0)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.66
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
    cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 1)

I also gave Hough Circles a try. But without any result at all. Maybe my circles are too small to be true circles, with the pixels showing.

Is Template Matching the right approach, even if I don't get it to work all the way, or can it be done more easily another way?

Any help would be much appreciated.
Thanks Martin

Ramesh-X
  • 4,853
  • 6
  • 46
  • 67
  • If the circles vary in size you may have problems with template matching in the future... if they are always the same size or almost the same size then it should match.... The center of the rectangle should be the center of the circle, you can also add all the colored values positions inside such rectangle and take the mean, this will give you the center. For the color, you can also do the same (mean of all the colors) or you can take the color from the centroid pixel and check to what color is closer (red or blue) – api55 Feb 21 '18 at 11:13
  • One more thing, if you have multiple ones, for each circle, it could be that it is like one pixel away and still get a good result, maybe a harder threshold will help, or try to take the best then fill this rectangle with 0 (bad value) and look again until the max is lower than your threshold (it will probably be slow though) – api55 Feb 21 '18 at 11:16
  • 1
    Possible duplicate of [Detect different color blob opencv](https://stackoverflow.com/questions/42924059/detect-different-color-blob-opencv) – Piglet Feb 21 '18 at 11:43
  • google "blob detection" or "connected component". sampling the colour is trivial once you have the centroids of those blobs. also have a look at https://docs.opencv.org/trunk/dd/d49/tutorial_py_contour_features.html – Piglet Feb 21 '18 at 11:47

1 Answers1

0

I solved it myself with using findContours.

image = cv2.imread('images/img.png')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (5, 5), 0)
thresh = cv2.threshold(blurred, 80, 255, cv2.THRESH_BINARY)[1]
cnts = cv2.findContours(thresh.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]

coordinates = []
for c in cnts:
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])
    #cv2.circle(image, (cX, cY), 1, (255, 255, 255), -1)
    coordinates.append([cX,cY])