Reputation: 5031
I need to draw a line in the image such that I click on pt1 and drag till pt2. So as a result a line will be displayed and I also get the coordinates of pt1 and pt2. I am currently using two separate mouse clicks to draw a line with the following code
import numpy as np
import cv2
def get_points(im):
# Set up data to send to mouse handler
data = {}
data['im'] = im.copy()
data['points'] = []
# Set the callback function for any mouse event
cv2.imshow("Image", im)
cv2.setMouseCallback("Image", mouse_handler, data)
cv2.waitKey(0)
# Convert array to np.array
points = np.vstack(data['points']).astype(float)
return points
def mouse_handler(event, x, y, flags, data):
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(data['im'], (x, y), 3, (0, 0, 255), 5, 16);
cv2.imshow("Image", data['im']);
if len(data['points']) < 2: # This can be changed for more or less points
data['points'].append([x, y])
# Running the code
img = cv2.imread('image.jpg', 0)
pts = get_points(img)
cv2.line(img, (pts[0][0], pts[0][1]), (pts[1][0], pts[1][1]), (0,0,0), 2)
cv2.imshow('Image', img)
cv2.waitKey(0)
It works but does not solve my problem. I want it to drag down from pt1 to pt2 and draw a line it self rather than I get the points using clicks and then draw the line. So for example, the below image on the left my current implementation but i want to do it as done in the right image
Thanks for your suggestion in advance.
Upvotes: 2
Views: 5422
Reputation: 458
Just use the other events as well.
Here is a quick dirty solution:
import numpy as np
import cv2
btn_down = False
def get_points(im):
# Set up data to send to mouse handler
data = {}
data['im'] = im.copy()
data['lines'] = []
# Set the callback function for any mouse event
cv2.imshow("Image", im)
cv2.setMouseCallback("Image", mouse_handler, data)
cv2.waitKey(0)
# Convert array to np.array in shape n,2,2
points = np.uint16(data['lines'])
return points, data['im']
def mouse_handler(event, x, y, flags, data):
global btn_down
if event == cv2.EVENT_LBUTTONUP and btn_down:
#if you release the button, finish the line
btn_down = False
data['lines'][0].append((x, y)) #append the seconf point
cv2.circle(data['im'], (x, y), 3, (0, 0, 255),5)
cv2.line(data['im'], data['lines'][0][0], data['lines'][0][1], (0,0,255), 2)
cv2.imshow("Image", data['im'])
elif event == cv2.EVENT_MOUSEMOVE and btn_down:
#thi is just for a ine visualization
image = data['im'].copy()
cv2.line(image, data['lines'][0][0], (x, y), (0,0,0), 1)
cv2.imshow("Image", image)
elif event == cv2.EVENT_LBUTTONDOWN and len(data['lines']) < 2:
btn_down = True
data['lines'].insert(0,[(x, y)]) #prepend the point
cv2.circle(data['im'], (x, y), 3, (0, 0, 255), 5, 16)
cv2.imshow("Image", data['im'])
# Running the code
img = cv2.imread('C://image.jpg', 1)
pts, final_image = get_points(img)
cv2.imshow('Image', final_image)
print pts
cv2.waitKey(0)
Let me know if thi is what you had in mind.
Upvotes: 4