Search code examples
pythongraphicscomputer-visiondrawing

How to draw a circle on image given float (subpixel) coordinates of it center


I want to visualize results of keypoint tracking algorithm in python. I have a sequence of (Image, Keypoint) pairs (video basically). Tracking algorithm is strong enough to give me subpixel accuracy. But i have no idea, how to visualize it properly.

I tried to round my coordinates and draw a circle by cv2.circle(image, (int(round(x)), int(round(y)))), but it leads to visual jittering of my keypoints due to small image resolution.

I checked OpenCV, Pillow, skimage, Pygame (pygame.draw.circle). All of them cannot properly draw circle with float coordinates.


Solution

  • DIPlib has the function DrawBandlimitedBall(), which draws a disk or a circle with smooth transitions and with floating-point origin coordinates (disclosure: I'm one of the authors). You might need to draw the circle in an empty image, then blend it in to get the effect you are looking for. Code would look something like this:

    import diplib as dip
    
    img = dip.ImageRead('/Users/cris/dip/images/flamingo.tif')
    p = [366.4, 219.1]
    
    # Create an empty image and draw a circle in it
    circle = dip.Image(img.Sizes(), 1, 'SFLOAT')
    circle.Fill(0)
    dip.DrawBandlimitedBall(circle, diameter=22.3, origin=p, value=1, mode='empty')
    circle /= dip.Maximum(circle)
    
    # Blend: img * (1-circle) + circle * color
    img *= 1 - circle
    img += circle * dip.Create0D([0,255,0]) # we make the circle green here
    
    img.Show()
    dip.ImageWrite(img, 'so.jpg')
    

    flamingo image with a green circle added

    (Note that the circle actually looks better without the JPEG compression artifacts.)

    You could draw the circle directly in the image, but this function adds the circle values to the image, it doesn't attempt to blend, and so you'd get a much worse look for this particular application.