Пост

Обработка событий и примитивное приложение для рисования

OpenCV предоставляет мощные средства для обработки событий мыши и клавиатуры, что позволяет создавать интерактивные приложения. В этом разделе рассматривается создание простого приложения для рисования с использованием обработки событий мыши и изучение доступных событий в OpenCV.

Обработка событий и примитивное приложение для рисования

Введение

OpenCV предоставляет мощные средства для обработки событий мыши и клавиатуры, что позволяет создавать интерактивные приложения. В этом разделе рассматривается создание простого приложения для рисования с использованием обработки событий мыши и изучение доступных событий в OpenCV.

Получение списка событий OpenCV

Для просмотра всех доступных событий в OpenCV можно использовать следующий код:

1
2
3
4
5
6
7
8
import cv2

# Получение списка всех событий содержащих 'EVENT'
events = [i for i in dir(cv2) if 'EVENT' in i]

# Вывод отсортированного списка событий
for event in sorted(events):
    print(event)

Результат выполнения покажет все доступные события:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
EVENT_FLAG_ALTKEY
EVENT_FLAG_CTRLKEY
EVENT_FLAG_LBUTTON
EVENT_FLAG_MBUTTON
EVENT_FLAG_RBUTTON
EVENT_FLAG_SHIFTKEY
EVENT_LBUTTONDBLCLK
EVENT_LBUTTONDOWN
EVENT_LBUTTONUP
EVENT_MBUTTONDBLCLK
EVENT_MBUTTONDOWN
EVENT_MBUTTONUP
EVENT_MOUSEHWHEEL
EVENT_MOUSEMOVE
EVENT_MOUSEWHEEL
EVENT_RBUTTONDBLCLK
EVENT_RBUTTONDOWN
EVENT_RBUTTONUP

Создание примитивного приложения для рисования

Полный код приложения для рисования с обработкой различных событий мыши:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import cv2
import numpy as np

# Создание черного фона и именованного окна
windowName = 'Drawing'
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow(windowName)

def draw_circle(event, x, y, flags, param):
    """
    Функция обработки событий мыши
    Рисует круги разных цветов и размеров в зависимости от события
    """
    if event == cv2.EVENT_LBUTTONDBLCLK:
        # Двойной клик левой кнопкой - зеленый круг
        cv2.circle(img, (x, y), 40, (0, 255, 0), -1)
        print(f"Двойной клик левой кнопкой в ({x}, {y})")
        
    elif event == cv2.EVENT_MBUTTONDOWN:
        # Клик средней кнопкой - красный круг
        cv2.circle(img, (x, y), 20, (0, 0, 255), -1)
        print(f"Клик средней кнопкой в ({x}, {y})")
        
    elif event == cv2.EVENT_LBUTTONDOWN:
        # Клик левой кнопкой - синий круг
        cv2.circle(img, (x, y), 30, (255, 0, 0), -1)
        print(f"Клик левой кнопкой в ({x}, {y})")
        
    elif event == cv2.EVENT_RBUTTONDOWN:
        # Клик правой кнопкой - желтый круг
        cv2.circle(img, (x, y), 25, (0, 255, 255), -1)
        print(f"Клик правой кнопкой в ({x}, {y})")

# Привязка функции обработки событий к окну
cv2.setMouseCallback(windowName, draw_circle)

# Основной цикл приложения
while True:
    cv2.imshow(windowName, img)
    
    # Выход при нажатии Esc (код 27)
    if cv2.waitKey(20) == 27:
        break

cv2.destroyAllWindows()

Примитивное приложение для рисования

Расширенное приложение для рисования с дополнительными функциями

Усовершенствованная версия с возможностью выбора цвета и очистки холста:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import cv2
import numpy as np

# Глобальные переменные
drawing = False
ix, iy = -1, -1
current_color = (255, 255, 255)  # Белый по умолчанию
brush_size = 5

def advanced_draw(event, x, y, flags, param):
    global ix, iy, drawing, current_color, brush_size
    
    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        ix, iy = x, y
        # Рисование точки при клике
        cv2.circle(img, (x, y), brush_size, current_color, -1)
        
    elif event == cv2.EVENT_MOUSEMOVE:
        if drawing:
            # Рисование линии при движении с зажатой кнопкой
            cv2.line(img, (ix, iy), (x, y), current_color, brush_size)
            ix, iy = x, y
            
    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        cv2.line(img, (ix, iy), (x, y), current_color, brush_size)
        
    elif event == cv2.EVENT_MOUSEWHEEL:
        # Изменение размера кисти колесом мыши
        if flags > 0:
            brush_size = min(brush_size + 1, 20)  # Увеличение
        else:
            brush_size = max(brush_size - 1, 1)   # Уменьшение
        print(f"Размер кисти: {brush_size}")

# Создание окна и изображения
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow('Advanced Drawing')
cv2.setMouseCallback('Advanced Drawing', advanced_draw)

print("Управление:")
print("1-7 - выбор цвета")
print("c - очистка холста")
print("s - сохранение рисунка")
print("Esc - выход")

while True:
    # Отображение информации о текущих настройках
    display_img = img.copy()
    info_text = f"Цвет: {current_color} Кисть: {brush_size}"
    cv2.putText(display_img, info_text, (10, 30), 
                cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 1)
    
    cv2.imshow('Advanced Drawing', display_img)
    
    key = cv2.waitKey(1) & 0xFF
    
    if key == 27:  # Esc
        break
    elif key == ord('c'):  # Очистка
        img = np.zeros((512, 512, 3), np.uint8)
    elif key == ord('s'):  # Сохранение
        cv2.imwrite('my_drawing.png', img)
        print("Рисунок сохранен как 'my_drawing.png'")
    elif key in [ord(str(i)) for i in range(1, 8)]:  # Выбор цвета
        colors = {
            ord('1'): (255, 255, 255),  # Белый
            ord('2'): (255, 0, 0),      # Синий
            ord('3'): (0, 255, 0),      # Зеленый
            ord('4'): (0, 0, 255),      # Красный
            ord('5'): (0, 255, 255),    # Желтый
            ord('6'): (255, 0, 255),    # Пурпурный
            ord('7'): (255, 255, 0)     # Голубой
        }
        current_color = colors[key]
        print(f"Выбран цвет: {current_color}")

cv2.destroyAllWindows()

Обработка комбинаций клавиш и модификаторов

Пример обработки сложных событий с модификаторами:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import cv2
import numpy as np

def complex_events(event, x, y, flags, param):
    """
    Демонстрация обработки сложных событий с модификаторами
    """
    if event == cv2.EVENT_LBUTTONDOWN:
        if flags & cv2.EVENT_FLAG_CTRLKEY:
            # Ctrl + левая кнопка - прямоугольник
            cv2.rectangle(img, (x-20, y-20), (x+20, y+20), (0, 255, 255), 2)
            print("Нарисован прямоугольник (Ctrl+ЛКМ)")
        elif flags & cv2.EVENT_FLAG_SHIFTKEY:
            # Shift + левая кнопка - треугольник
            pts = np.array([[x, y-25], [x-25, y+25], [x+25, y+25]], np.int32)
            cv2.polylines(img, [pts], True, (255, 0, 255), 2)
            print("Нарисован треугольник (Shift+ЛКМ)")
        else:
            # Просто левая кнопка - круг
            cv2.circle(img, (x, y), 25, (255, 255, 0), -1)
            print("Нарисован круг (ЛКМ)")
    
    elif event == cv2.EVENT_RBUTTONDOWN:
        # Правая кнопка - информация о позиции
        print(f"Позиция: ({x}, {y}), Цвет пикселя: {img[y, x]}")

# Инициализация
img = np.zeros((400, 600, 3), np.uint8)
cv2.namedWindow('Complex Events')
cv2.setMouseCallback('Complex Events', complex_events)

print("Инструкция:")
print("ЛКМ - круг")
print("Ctrl+ЛКМ - прямоугольник")
print("Shift+ЛКМ - треугольник")
print("ПКМ - информация о пикселе")
print("Esc - выход")

while True:
    cv2.imshow('Complex Events', img)
    if cv2.waitKey(20) == 27:
        break

cv2.destroyAllWindows()

Типичные проблемы и решения

Проблема: События мыши не обрабатываются Решение: Убедитесь, что окно активно и имеет фокус. Проверьте правильность привязки callback функции

Проблема: Рисование происходит с задержкой Решение: Уменьшите время ожидания в cv2.waitKey() (например, 1-20 мс)

Проблема: Не работают модификаторы (Ctrl, Shift) Решение: Используйте правильные флаги: cv2.EVENT_FLAG_CTRLKEY, cv2.EVENT_FLAG_SHIFTKEY

Проблема: Приложение потребляет много ресурсов Решение: Добавьте небольшую задержку в цикл и обновляйте изображение только при изменениях

Освоение обработки событий в OpenCV открывает возможности для создания интерактивных приложений компьютерного зрения. Понимание различных типов событий мыши и их комбинаций с модификаторами клавиш позволяет разрабатывать удобные интерфейсы для взаимодействия с пользователем. Эти навыки особенно полезны при создании инструментов для аннотации изображений и интерактивной настройки параметров алгоритмов.

Авторский пост защищен лицензией CC BY 4.0 .

© evdokimoff. Некоторые права защищены.

Использует тему Chirpy для Jekyll