Найти в Дзене
IT Start | Python

Обрезка изображений на Python OpenCv

Оглавление

Введение

В ходе данной статьи напишем код для обрезки изображений на Python с использованием библиотеки OpenCv.

Работать программа будет следующим образом:

  1. Выделение области: Пользователь выделяет область изображения, которую хочет обрезать.
  2. Сохранение обрезанного изображения: После выделения определённой области можно нажать на клавишу «C», и будет сохранено обрезанное изображение.
  3. Выход из программы: Для выхода из программы можно будет нажать на клавишу «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

Работа кода:

-2

Заключение

В ходе статьи мы с Вами написали код программы «Обрезка изображений на Python OpenCv». Надеюсь Вам понравилась статья, желаю удачи и успехов! 🙂

Мой Telegram канал

Мой YouTube канал

Мой курс по Python (50 видоуроков + дополнительные уроки)

Курс по созданию телеграм-ботов на Python с фреймворком Aiogram

Курс по созданию GUI на Python