[英]Drawing a line on an image using mouse clicks with Python OpenCV library
我正在尝试使用鼠标操作在图像上画一条线。 我正在使用 OpenCV 库。 我的代码
import matplotlib.pyplot as plt
import cv2
src_window = 'CV2 Window'
SHOW_DEBUG_STEPS = True
drag = 0
select_flag = 0
x1 = 0
x2 = 0
y1 = 0
y2 = 0
point1 = [x1,y1]
point2 = [x2,y2]
SCALAR_YELLOW = (0.0,255.0,255.0)
cap = cv2.VideoCapture('example_01.mp4')
def closeAll():
cap.release()
cv2.destroyAllWindows()
def retn(ret):
if not ret:
print('Error reading the frame')
closeAll()
def frm(fFrame):
if fFrame is None:
print('Error reading the frame')
closeAll()
def drawMyLine(frame):
global point1
global point2
cv2.line(frame,(point1[0],point1[1]),(point2[0],point2[1]),SCALAR_YELLOW,2,8)
def myMouseHandler(event,x,y,flags,param):
global point1
global point2
global drag
global select_flag
global callback
if (event==cv2.EVENT_LBUTTONDOWN and not(drag) and not(select_flag)):
print('case 1')
point1=[x,y]
drag = 1
if (event == cv2.EVENT_MOUSEMOVE and drag and not(select_flag)):
print('case 2')
img1 = fFrame.copy()
point2 = [x,y]
drawMyLine(img1)
if (event == cv2.EVENT_LBUTTONUP and drag and not(select_flag)):
print('case 3')
img2 = fFrame.copy()
point2 = [x,y]
drag = 0
select_flag = 1
cv2.imshow(src_window,img2)
callback = 1
if not(cap.isOpened()):
print('Error reading the video')
ret,fFrame = cap.read()
retn(ret)
frm(fFrame)
fGray = cv2.cvtColor(fFrame,cv2.COLOR_BGR2GRAY)
cv2.imshow(src_window,fGray)
cv2.setMouseCallback(src_window,myMouseHandler)
cv2.waitKey(0)
当我运行代码并尝试通过单击鼠标左键来绘制一条线时,将鼠标拖动到第二个点并释放鼠标左键,我看到我的打印语句 case1、case2、case3 正在终端中打印。 但是这条线没有出现。 我不确定我哪里出错了。
要使用鼠标单击在图像上绘制线条,我们必须捕获鼠标单击的事件动作,然后记录开始和结束坐标。 OpenCV 允许我们通过处理鼠标点击事件来做到这一点。 每当触发鼠标单击事件时,OpenCV 都会通过将信息附加到cv2.setMouseCallback
处理程序,将信息传递给我们的extract_coordinates
回调函数。 为了检测事件,OpenCV 需要各种参数:
按下左键 ( cv2.EVENT_LBUTTONDOWN
) 记录起始坐标,而松开左键 ( cv2.EVENT_LBUTTONUP
) 记录结束坐标。 然后我们用cv2.line
画一条线并将坐标打印到控制台。 右键单击( cv2.EVENT_RBUTTONDOWN
)将重置图像。 这是一个在图像上绘制线条的简单小部件:
import cv2
class DrawLineWidget(object):
def __init__(self):
self.original_image = cv2.imread('1.jpg')
self.clone = self.original_image.copy()
cv2.namedWindow('image')
cv2.setMouseCallback('image', self.extract_coordinates)
# List to store start/end points
self.image_coordinates = []
def extract_coordinates(self, event, x, y, flags, parameters):
# Record starting (x,y) coordinates on left mouse button click
if event == cv2.EVENT_LBUTTONDOWN:
self.image_coordinates = [(x,y)]
# Record ending (x,y) coordintes on left mouse bottom release
elif event == cv2.EVENT_LBUTTONUP:
self.image_coordinates.append((x,y))
print('Starting: {}, Ending: {}'.format(self.image_coordinates[0], self.image_coordinates[1]))
# Draw line
cv2.line(self.clone, self.image_coordinates[0], self.image_coordinates[1], (36,255,12), 2)
cv2.imshow("image", self.clone)
# Clear drawing boxes on right mouse button click
elif event == cv2.EVENT_RBUTTONDOWN:
self.clone = self.original_image.copy()
def show_image(self):
return self.clone
if __name__ == '__main__':
draw_line_widget = DrawLineWidget()
while True:
cv2.imshow('image', draw_line_widget.show_image())
key = cv2.waitKey(1)
# Close program with keyboard 'q'
if key == ord('q'):
cv2.destroyAllWindows()
exit(1)
您的代码有几个问题。
1) img1 = fFrame.copy()
实例化img1
然后你在它上面画图,作为一个局部变量你再也不会使用它,导致你失去你画的东西。 相反,在实际框架上绘制如下。
if (event == cv2.EVENT_MOUSEMOVE and drag and not(select_flag)):
print('case 2')
point2 = [x,y]
drawMyLine(fFrame)
2) 绘制当前行后,您应该将下一行的开头 (next point1
) 更新为当前行的结尾 (current point2
)。
if (event == cv2.EVENT_MOUSEMOVE and drag and not(select_flag)):
print('case 2')
point2 = [x,y]
drawMyLine(fFrame)
point1 = [x,y] # <-- update for next draw
3)这是可选的,你可以直接显示当前帧,而不是img2
。
if (event == cv2.EVENT_LBUTTONUP and drag and not(select_flag)):
print('case 3')
point2 = [x,y]
drag = 0
select_flag = 1
cv2.imshow(src_window,fFrame)
callback = 1
4)这也是可选的,但是为了在点击结束时正确绘制最后一行,你应该在这种情况下最后一次调用draw函数。
if (event == cv2.EVENT_LBUTTONUP and drag and not(select_flag)):
print('case 3')
point2 = [x,y]
drawMyLine(fFrame) # <-- draw the last line
drag = 0
select_flag = 1
cv2.imshow(src_window,fFrame)
callback = 1
总的来说,其余的代码都是一样的,更新的鼠标处理程序如下。
def myMouseHandler(event,x,y,flags,param):
global drag
global select_flag
global callback
global point1
global point2
if (event==cv2.EVENT_LBUTTONDOWN and not(drag) and not(select_flag)):
print('case 1')
point1=[x,y]
drag = 1
if (event == cv2.EVENT_MOUSEMOVE and drag and not(select_flag)):
print('case 2')
point2 = [x,y]
drawMyLine(fFrame)
point1 = [x,y]
if (event == cv2.EVENT_LBUTTONUP and drag and not(select_flag)):
print('case 3')
point2 = [x,y]
drawMyLine(fFrame)
drag = 0
select_flag = 1
cv2.imshow(src_window,fFrame)
callback = 1
import cv2
import numpy as np
def click_event(event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img,(x,y),3,(255,0,0),-1)
points.append((x,y))
if len(points) >= 2:
cv2.line(img,points[-1],points[-2],(0,255,0),1)
cv2.imshow("image", img)
cv2.imshow("image",img)
points = []
cv2.setMouseCallback('image',click_event)
cv2.waitKey(0)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.