5

I would like to determine the center positions of the tips of the syringes in this (video still) image. The tips are nominally round and of known size and quantity.

I am currently putting red ink on the tips to make them easier to detect. It would be nice to not to have to do this but I think without it, detection would be very difficult. Anyone like a challenge?

I started off trying SimpleBlobDetector as it has some nice filtering. One thing I couldn't figure out was how to get SimpleBlobDetector to detect the hollow circles (rings)?

I then tried canny + hough but the circle detection was too unstable, the positions jumped around.

I am currently using findContours + minEnclosingCircle which works OK but still quite unstable. The mask looks like this. The result. You can see the accuracy is not great:

Gif

I briefly looked at RANSAC but I couldn't find a Python example that would detect multiple circles plus the edge detection is tricky.

My current code:

# https://stackoverflow.com/questions/32522989/opencv-better-detection-of-red-color
frame_inv = ~frame0
# Convert BGR to HSV
hsv = cv2.cvtColor(frame_inv, cv2.COLOR_BGR2HSV)
blur = cv2.GaussianBlur(hsv, (5, 5), 0)
# define range of color in HSV
lower_red = np.array([90 - 10, 70, 50])
upper_red = np.array([90 + 10, 255, 255])
# Threshold the HSV image to get only red colors
mask = cv2.inRange(hsv, lower_red, upper_red)
# cv2.imshow('Mask', mask)
kernel = np.ones((5, 5), np.uint8)
dilate = cv2.dilate(mask, kernel)
# cv2.imshow('Dilate', dilate)
contours = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0]

tipXY = []
for c in contours:
    area = cv2.contourArea(c)
    if area > 200:
        (x, y), r = cv2.minEnclosingCircle(c)
        center = (int(x), int(y))
        r = int(r)
        shift = 2
        factor = 2 ** shift
        cv2.circle(frame0, (int(round((x) * factor)), int(round((y) * factor))),
                       int(round(10 * factor)), (0, 255, 0), 2, shift=shift)
        tipXY.append(center)

Any suggestions to improve the position detection accuracy/stability?

Anthony
  • 657
  • 2
  • 10
  • 21
  • 1
    [Hough circles](https://docs.opencv.org/4.x/da/d53/tutorial_py_houghcircles.html) are pretty good. With the current lighting setup you have, it might be difficult to find those tips without marking them red. If you can somehow get more contrast from the unmarked tips, maybe you can do some edge enhancement/detection techniques. – bfris Jun 14 '22 at 17:17
  • 1
    My understanding is, if you are not certain your image contains circles, hough circles is great. But, if you know there are circles other methods are perhaps easier to tune. Certainly I found hough to be very sensitive to the parameters. – Anthony Jun 15 '22 at 06:28

1 Answers1

1

Here is a better way to segment red color using the second image as input.

Idea:

Since the red color is prominent, I tried converting to other known color spaces (LAB and YCrCb) and viewed their individual channels. The Cr from YCrCb expressed the red color more prominently. According to this link, Cr channel represents the difference between red and luminance, enabling the color to stand out.

Code:

img = cv2.imread('stacked_rings.jpg')

ycc = cv2.cvtColor(img, cv2.COLOR_BGR2YCrCb)
cr_channel = ycc[:,:,1]

enter image description here

Though the hollow rings can be seen, the pixel intensity range is limited to the range [109 - 194]. Let's stretch the range:

dst = cv2.normalize(cr_channel, dst=None, alpha=0, beta=255,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

enter image description here

The circles a more prominent. Hope this pre-processing step helps you.

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
  • This is very useful, thanks. Incidentally, what colour makes the most sense for segmenting an image? I used red because that is the ink pad I had. – Anthony Jun 15 '22 at 18:06
  • @Anthony Dominant colors like red, green blue and yellow can be segmented quite easily depending on the color space. In [this answer](https://stackoverflow.com/questions/47483951/how-to-define-a-threshold-value-to-detect-only-green-colour-objects-in-an-image/72264323#72264323) I have shown how to segment green color from the 'A' channel of LAB color space. Red color can be segmented by analyzing the 'A' channel. Similarly, blue and yellow can be segmented using the 'B' channel as they sit on either ends of 'B' axis. – Jeru Luke Jun 15 '22 at 18:16
  • I have been playing around with this with mixed results. Can you suggest what my next step should be to find the centre of each ring? – Anthony Jun 27 '22 at 16:22
  • @Anthony You would have to binarize the image at an appropriate threshold such that the circles appear in white, while everything else is in black. Next find contours on this binary image and find the centroid for each contour. – Jeru Luke Jun 27 '22 at 19:16
  • Ah yes, makes sense. I will spend some time looking at thresholds. Thanks – Anthony Jun 27 '22 at 19:27