简体   繁体   English

使用 Python OpenCV 库单击鼠标在图像上绘制线条

[英]Drawing a line on an image using mouse clicks with Python OpenCV library

I am trying to draw a line on an image using mouse operations.我正在尝试使用鼠标操作在图像上画一条线。 I am using OpenCV library.我正在使用 OpenCV 库。 My code我的代码

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)

When I run the code and try to draw a line by clicking the left mouse button, drag mouse to a second point and release the left mouse button, I see my print statements, case1, case2, case3 being printed in terminal.当我运行代码并尝试通过单击鼠标左键来绘制一条线时,将鼠标拖动到第二个点并释放鼠标左键,我看到我的打印语句 case1、case2、case3 正在终端中打印。 But the line is not coming up.但是这条线没有出现。 I am not sure where am I going wrong.我不确定我哪里出错了。

To draw lines on an image using mouse clicks, we must capture the event actions of a mouse click then record the starting and ending coordinates.要使用鼠标单击在图像上绘制线条,我们必须捕获鼠标单击的事件动作,然后记录开始和结束坐标。 OpenCV allows us to do this by processing mouse click events. OpenCV 允许我们通过处理鼠标点击事件来做到这一点。 Anytime a mouse click event is triggered, OpenCV will relay the information to our extract_coordinates callback function by attaching it to the cv2.setMouseCallback handler.每当触发鼠标单击事件时,OpenCV 都会通过将信息附加到cv2.setMouseCallback处理程序,将信息传递给我们的extract_coordinates回调函数。 In order to detect the event, OpenCV requires various arguments:为了检测事件,OpenCV 需要各种参数:

  • event : Event that took place (left/right pressed or released mouse click) event :发生的事件(左/右按下或释放鼠标单击)
  • x : The x-coordinate of event x : 事件的 x 坐标
  • y : The y-coordinate of event y : 事件的 y 坐标
  • flags : Relevant flags passed by OpenCV flags : OpenCV 传递的相关标志
  • Parameters : Extra parameters passed by OpenCV参数:OpenCV 传递的额外参数

A pressed left click ( cv2.EVENT_LBUTTONDOWN ) records the starting coordinates while a released left click ( cv2.EVENT_LBUTTONUP ) records ending coordinates.按下左键 ( cv2.EVENT_LBUTTONDOWN ) 记录起始坐标,而松开左键 ( cv2.EVENT_LBUTTONUP ) 记录结束坐标。 We then draw a line with cv2.line and print the coordinates to the console.然后我们用cv2.line画一条线并将坐标打印到控制台。 A right click ( cv2.EVENT_RBUTTONDOWN ) will reset the image.右键单击( cv2.EVENT_RBUTTONDOWN )将重置图像。 Here's a simple widget to draw lines on an image:这是一个在图像上绘制线条的简单小部件:

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)

There are several problems with your code.您的代码有几个问题。

1) img1 = fFrame.copy() instantiates img1 and then you draw on it, and as a local variable you never use it again, causing you to lose what you drew. 1) img1 = fFrame.copy()实例化img1然后你在它上面画图,作为一个局部变量你再也不会使用它,导致你失去你画的东西。 Instead, draw on the actual frame as below.相反,在实际框架上绘制如下。

if (event == cv2.EVENT_MOUSEMOVE and drag and not(select_flag)):
   print('case 2')
   point2 = [x,y]
   drawMyLine(fFrame)

2) After drawing the current line, you should update the beginning of your next line (next point1 ) to be the end of the current line (current point2 ). 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) This is optional, you can directly show the current frame, instead of img2 . 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) This is also optional, but in order to correctly draw the last line at the end of the click, you should call the draw function for the last time in that case. 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

Overall, the rest of the code is the same, and the updated mouse handler is below.总的来说,其余的代码都是一样的,更新的鼠标处理程序如下。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM