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