簡體   English   中英

使用 Python OpenCV 庫單擊鼠標在圖像上繪制線條

[英]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 需要各種參數:

  • event :發生的事件(左/右按下或釋放鼠標單擊)
  • x : 事件的 x 坐標
  • y : 事件的 y 坐標
  • flags : OpenCV 傳遞的相關標志
  • 參數: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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM