Рисование линии на изображении с помощью щелчков мыши с помощью библиотеки Python OpenCV - PullRequest
1 голос
/ 08 марта 2020

Я пытаюсь нарисовать линию на изображении, используя операции мыши. Я использую библиотеку 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 печатается в терминале. Но линия не подходит. Я не уверен, где я иду не так. Может ли кто-нибудь помочь мне с этим.

Ответы [ 2 ]

0 голосов
/ 10 марта 2020

Чтобы нарисовать линии на изображении с помощью щелчков мыши, мы должны зафиксировать действия события щелчка мышью, а затем записать начальную и конечную координаты. OpenCV позволяет нам делать это, обрабатывая события щелчка мышью. Каждый раз, когда срабатывает событие щелчка мыши, OpenCV передает информацию нашей функции обратного вызова extract_coordinates, присоединяя ее к обработчику cv2.setMouseCallback. Чтобы обнаружить событие, OpenCV требует различных аргументов:

  • событие : событие, которое произошло (нажатие левой / правой кнопки мыши или отпускание мыши)
  • x : X-координата события
  • y : Y-координата события
  • flags : Соответствующие флаги пройдены по OpenCV
  • Параметры : дополнительные параметры, передаваемые OpenCV

Нажатие левой кнопки мыши (cv2.EVENT_LBUTTONDOWN) записывает начальные координаты, а нажатие левой кнопки (cv2.EVENT_LBUTTONUP) записывает конечные координаты. Затем мы рисуем линию с cv2.line и выводим координаты на консоль. Щелчок правой кнопкой мыши (cv2.EVENT_RBUTTONDOWN) сбросит изображение. Вот простой виджет для рисования линий на изображении:

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)
0 голосов
/ 09 марта 2020

Есть несколько проблем с вашим кодом.

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), чтобы оно стало концом текущей строки (текущий 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) Это также необязательно, но для того, чтобы правильно нарисовать последнюю строку в конце клика, вам следует вызвать функцию рисования в последний раз в этом случае.

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
...