Search code examples
pythonnumpyopencvimage-segmentationscikit-image

Pixel coordinates of the circle extracted (using scikit image) shifts from the actual position of the circle drawn over an image(using openCV)


I am using openCV to draw a circle over an image(with the mouse) and then I use the radius and center of the circle to segment a portion of the image using the random_walker() method in skimage. I have an issue with the coordinates of the pixels extracted using the mouse click. Whenever a circle is drawn over the image with the mouse, the pixel coordinates of the circle shifts a little from the actual position of the circle drawn. Please see the images: Images

As you can see, first image is the circle drawn with the mouse and the second image is the pixel coordinates of the circle the random walker extracts(used to segment the vertebrae). Since the coordinates of the circle shifts, the part of the image segmented becomes wrong. This is my code:

import math
import matplotlib.pyplot as plt
import numpy as np
from skimage import io
from skimage.color import rgb2gray
from skimage import data
import skimage.segmentation as seg
import skimage.draw as draw
import cv2

#To store center and cicumference points
circle_center = (0,0)
circumference = (0,0)

def image_show(image, nrows=1, ncols=1, cmap='gray'):
    fig, ax = plt.subplots(nrows=nrows, ncols=ncols, figsize=(8,8))
    ax.imshow(image, cmap='gray')
    ax.axis('off')
    return fig, ax

def circle_points(resolution, center, radius):
    
        #Generate points which define a circle on an image.Centre refers to the centre of the circle
        radians = np.linspace(0, 2*np.pi, resolution)
        c = center[1] + radius*np.cos(radians)#polar co-ordinates
        r = center[0] + radius*np.sin(radians)
        
        return np.array([c,r]).T

def drawCircle(event, x, y, flags, params):
    #referencing global variables
    global circle_center, circumference
    #action to be taken when left mouse button is pressed
    if(event ==  cv2.EVENT_LBUTTONDOWN):
        circle_center = (x,y)
        
        #draw the center
        cv2.circle(imageClone, circle_center, 2, (0, 0, 255), 1, cv2.LINE_AA)

    #action to be taken when left mouse button is released
    elif event == cv2.EVENT_LBUTTONUP:
        circumference = (x,y)

        #calculate radius of the circle
        radius1 = math.sqrt(math.pow(circle_center[0] - circumference[0], 2)+ math.pow(circle_center[1] - circumference[1], 2))
        print(radius1)
        #draw the circle
        cv2.circle(imageClone, circle_center, int(radius1), (0, 0, 255), 1, cv2.LINE_AA)
        cv2.imshow("image", imageClone)

        points = circle_points(200, [y,x], radius1)[:-1]
        image_labels = np.zeros((image_gray.shape), dtype=np.uint8)
        indices = draw.circle_perimeter(y,x,5)

        image_labels[indices] = 1
        image_labels[points[:,1].astype(np.int), points[:,0].astype(np.int)] = 2
        image_show(image_labels)

        image_segmented = seg.random_walker(image_gray, image_labels, beta = 3500)
        
        #Check our results
        fig, ax = image_show(image)
        ax.imshow(image_segmented == 1, alpha=0.3)
        plt.show()

image = cv2.imread('image.png')
image_gray = rgb2gray(image)

#Create a clone of input image to work on
imageClone = image_gray.copy()

#displaying the image 
cv2.imshow('image', image)

#setup callback for mouse event
cv2.setMouseCallback("image", drawCircle)

while True:
    cv2.imshow('image', imageClone)
    #wait for a widow to be closed
    k = cv2.waitKey(100)
    if k == 27:
        print('ESC')
        cv2.destroyAllWindows()
        break        
    if cv2.getWindowProperty('image',cv2.WND_PROP_VISIBLE) < 1:        
        break 

#close all the opened windows
cv2.destroyAllWindows()

Can someone tell me a proper solution to solve this?


Solution

  • It's subtle! You're drawing the second circle centered on mouse release (indices = draw.circle_perimeter(y,x,5), but the first circle on mouse down.