Введение
В ходе данной статьи напишем код для обрезки изображений на Python с использованием библиотеки OpenCv.
Работать программа будет следующим образом:
- Выделение области: Пользователь выделяет область изображения, которую хочет обрезать.
- Сохранение обрезанного изображения: После выделения определённой области можно нажать на клавишу «C», и будет сохранено обрезанное изображение.
- Выход из программы: Для выхода из программы можно будет нажать на клавишу «Esc».
Установка и импорт необходимых библиотек
Перед написанием кода необходимо установить библиотеку OpenCv, а также numpy для лучшей её работы. Сделать это можно через pip. Для этого нужно перейти в терминал/командную строку, прописать pip install opencv-python numpy, нажать Enter и ждать установки.
pip install opencv-python numpy
После инсталляции импортируем библиотеку OpenCv:
import cv2
Создание функции для обработки событий мыши
Создадим функцию deaw_rectangle(), которая будет обрабатывать нажатия, перемещения и отпускания мыши, определять выделенную область на изображении.
У функции будет присутствовать четыре параметра, а именно:
- event: Тип события (например, нажатие кнопки мыши).
- x — Координата X текущей позиции курсора.
- y — Координата Y текущей позиции курсора.
- flags — дополнительные флаги события, которые могут включать состояние кнопок мыши или клавиш-модификаторов (например, Ctrl, Shift).
- param — Кортеж с изображением и координатами (start_point, end_point, drawing_flag).
import cv2
def draw_rectangle(event, x, y, flags, param):
В аргумент param должен будет передаваться кортеж (img, temp_img, points), где:
- img — исходное изображение, с которым работает пользователь.
- temp_img — временная копия изображения, которая используется для динамического отображения изменений (например, рисования прямоугольника) без изменения оригинального изображения.
- points — список, который содержит информацию о состоянии рисования:start_point — начальная точка прямоугольника (координаты X и Y).
end_point — конечная точка прямоугольника (координаты X и Y).
drawing_flag — флаг, указывающий, находится ли пользователь в процессе рисования (True — идет рисование, False — нет).
Распакуем переданные данные в аргумент param:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
Далее добавим условие, что если было начато рисование, то будет сохраняться начальная точка и включаться флаг для рисования:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN: # Начало рисования
points[0] = (x, y) # Запоминаем начальную точку
points[2] = True # Включаем флаг рисования
Добавим elif для обновления прямоугольника при движении мыши:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN:
points[0] = (x, y)
points[2] = True
elif event == cv2.EVENT_MOUSEMOVE and points[2]: # Обновляем прямоугольник при движении мыши
points[1] = (x, y) # Обновляем конечную точку
temp_img_copy = temp_img.copy() # Работаем с временным изображением, чтобы не затронуть исходное
cv2.rectangle(temp_img_copy, start_point, (x, y), (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
В последнем elif после завершения рисования будет устанавливаться конечная точка, производиться остановка рисования и проверка, валиден ли прямоугольник:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN:
points[0] = (x, y)
points[2] = True
elif event == cv2.EVENT_MOUSEMOVE and points[2]:
points[1] = (x, y)
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, (x, y), (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
elif event == cv2.EVENT_LBUTTONUP: # Завершение рисования
points[1] = (x, y) # Устанавливаем конечную точку
points[2] = False # Останавливаем рисование
if start_point != end_point: # Проверка, что прямоугольник валидный
temp_img_copy = temp_img.copy() # Отображаем изображение без сохранения зелёных полос
cv2.rectangle(temp_img_copy, start_point, end_point, (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
else:
print("Невалидный прямоугольник. Попробуйте ещё раз.")
Загрузка изображения и подготовка к рисованию
После создания функции необходимо загрузить изображение, с которым пользователь будет работать. Используем функцию cv2.imread() для загрузки изображения с диска:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN:
points[0] = (x, y)
points[2] = True
elif event == cv2.EVENT_MOUSEMOVE and points[2]:
points[1] = (x, y)
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, (x, y), (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
elif event == cv2.EVENT_LBUTTONUP:
points[1] = (x, y)
points[2] = False
if start_point != end_point:
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, end_point, (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
else:
print("Невалидный прямоугольник. Попробуйте ещё раз.")
img = cv2.imread('image.jpg')
# Проверка на успешную загрузку изображения
if img is None:
print("Ошибка: не удалось загрузить изображение.")
exit(1)
Также создадим копию изображения для временного отображения при рисовании, чтобы не изменять оригинал:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN:
points[0] = (x, y)
points[2] = True
elif event == cv2.EVENT_MOUSEMOVE and points[2]:
points[1] = (x, y)
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, (x, y), (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
elif event == cv2.EVENT_LBUTTONUP:
points[1] = (x, y)
points[2] = False
if start_point != end_point:
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, end_point, (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
else:
print("Невалидный прямоугольник. Попробуйте ещё раз.")
img = cv2.imread('image.jpg')
if img is None:
print("Ошибка: не удалось загрузить изображение.")
exit(1)
# Создание копии изображения для временного отображения
temp_img = img.copy()
Инициализируем переменные для хранения начальной и конечной точек прямоугольника, а также флага, указывающего на то, идет ли процесс рисования:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN:
points[0] = (x, y)
points[2] = True
elif event == cv2.EVENT_MOUSEMOVE and points[2]:
points[1] = (x, y)
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, (x, y), (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
elif event == cv2.EVENT_LBUTTONUP:
points[1] = (x, y)
points[2] = False
if start_point != end_point:
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, end_point, (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
else:
print("Невалидный прямоугольник. Попробуйте ещё раз.")
img = cv2.imread('image.jpg')
if img is None:
print("Ошибка: не удалось загрузить изображение.")
exit(1)
temp_img = img.copy()
points = [(0, 0), (0, 0), False] # [start_point, end_point, drawing_flag]
Привязка функции к окну и обработка событий
Для того чтобы наша функция draw_rectangle() начала работать, нужно привязать её к окну с изображением. В OpenCV есть функция cv2.setMouseCallback() для обработки событий мыши в конкретном окне:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN:
points[0] = (x, y)
points[2] = True
elif event == cv2.EVENT_MOUSEMOVE and points[2]:
points[1] = (x, y)
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, (x, y), (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
elif event == cv2.EVENT_LBUTTONUP:
points[1] = (x, y)
points[2] = False
if start_point != end_point:
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, end_point, (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
else:
print("Невалидный прямоугольник. Попробуйте ещё раз.")
img = cv2.imread('image.jpg')
if img is None:
print("Ошибка: не удалось загрузить изображение.")
exit(1)
temp_img = img.copy()
points = [(0, 0), (0, 0), False]
# Отображение исходного изображения в окне
cv2.imshow('image', img)
# Назначение функции обратного вызова для обработки событий мыши
cv2.setMouseCallback('image', draw_rectangle, (img, temp_img, points))
Таким образом функция будет вызываться каждый раз, когда пользователь взаимодействует с изображением с помощью мыши.
Основной цикл программы
Для того чтобы программа продолжала работать и реагировала на действия пользователя, создаем основной цикл. В нем мы будем обрабатывать нажатия клавиш:
- Нажатие клавиши «C» — обрезка выделенной области изображения.
- Нажатие клавиши Esc — выход из программы.
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN:
points[0] = (x, y)
points[2] = True
elif event == cv2.EVENT_MOUSEMOVE and points[2]:
points[1] = (x, y)
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, (x, y), (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
elif event == cv2.EVENT_LBUTTONUP:
points[1] = (x, y)
points[2] = False
if start_point != end_point:
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, end_point, (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
else:
print("Невалидный прямоугольник. Попробуйте ещё раз.")
img = cv2.imread('image.jpg')
if img is None:
print("Ошибка: не удалось загрузить изображение.")
exit(1)
temp_img = img.copy()
points = [(0, 0), (0, 0), False]
cv2.imshow('image', img)
cv2.setMouseCallback('image', draw_rectangle, (img, temp_img, points))
# Основной цикл программы для обработки событий клавиатуры
while True:
key = cv2.waitKey(1) & 0xFF
# Обрезка изображения по нажатию клавиши 'c'
if key == ord('c'):
start_point, end_point, _ = points
if start_point < end_point:
# Обрезка без учёта зелёных полос (используем оригинальное изображение)
cropped_region = img[start_point[1]:end_point[1], start_point[0]:end_point[0]]
cv2.imshow('cropped', cropped_region)
cv2.imwrite('cropped_image.jpg', cropped_region)
else:
print("Невалидное выделение. Попробуйте снова.")
# Выход из программы по нажатию клавиши Esc
elif key == 27:
break
После цикла добавим закрытие всех окон:
import cv2
def draw_rectangle(event, x, y, flags, param):
img, temp_img, points = param
start_point, end_point, drawing_flag = points
if event == cv2.EVENT_LBUTTONDOWN:
points[0] = (x, y)
points[2] = True
elif event == cv2.EVENT_MOUSEMOVE and points[2]:
points[1] = (x, y)
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, (x, y), (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
elif event == cv2.EVENT_LBUTTONUP:
points[1] = (x, y)
points[2] = False
if start_point != end_point:
temp_img_copy = temp_img.copy()
cv2.rectangle(temp_img_copy, start_point, end_point, (0, 255, 0), 2)
cv2.imshow('image', temp_img_copy)
else:
print("Невалидный прямоугольник. Попробуйте ещё раз.")
img = cv2.imread('image.jpg')
if img is None:
print("Ошибка: не удалось загрузить изображение.")
exit(1)
temp_img = img.copy()
points = [(0, 0), (0, 0), False]
cv2.imshow('image', img)
cv2.setMouseCallback('image', draw_rectangle, (img, temp_img, points))
while True:
key = cv2.waitKey(1) & 0xFF
if key == ord('c'):
start_point, end_point, _ = points
if start_point < end_point:
cropped_region = img[start_point[1]:end_point[1], start_point[0]:end_point[0]]
cv2.imshow('cropped', cropped_region)
cv2.imwrite('cropped_image.jpg', cropped_region)
else:
print("Невалидное выделение. Попробуйте снова.")
elif key == 27:
break
cv2.destroyAllWindows()
Обрезка изображений на Python OpenCv
Работа кода:
Заключение
В ходе статьи мы с Вами написали код программы «Обрезка изображений на Python OpenCv». Надеюсь Вам понравилась статья, желаю удачи и успехов! 🙂
Мой Telegram канал
Мой YouTube канал
Мой курс по Python (50 видоуроков + дополнительные уроки)
Курс по созданию телеграм-ботов на Python с фреймворком Aiogram