Найти в Дзене
ФЭД

Как автоматически обрезать большие белые поля на скане фото с помощью Python

Бывает так, что у вас есть папка со сканированными фотографиями, которые имеют большие белые поля во весь лист А4 (кто-то при сканировании не совсем удачно выставил настройки). Чтобы не обрезать каждое фото отдельно вручную, хорошо бы применить код на питоне для автоматической обрезки лишних белых полей. Не всегда это корректно срабатывает, это зависит от качества скана, но в общем и целом может значительно облегчить вам редактирование старых фотографий, когда пакет файлов обрежется автоматически. Ссылка на код на Гитхабе (можно взять): <https://gist.github.com/ElenaInDespair/58bc2385445f38ec69244b089eb9ba39> Краткое описание кода (с сокращениями, код не копируем, тут нет отступов): import cv2 import os import glob extensions = ('*.jpg', '*.jpeg', '*.png', '*.bmp', '*.tiff') image_files = [] for ext in extensions: image_files.extend(glob.glob(os.path.join(folder_path, ext))) for image_path in image_files: print(f'Processing: {image_path}') # загрузка изображений image = cv2.imread(im
Это я на Азовском море (у кого еще была фотка с обезьяной?)
Это я на Азовском море (у кого еще была фотка с обезьяной?)

Бывает так, что у вас есть папка со сканированными фотографиями, которые имеют большие белые поля во весь лист А4 (кто-то при сканировании не совсем удачно выставил настройки). Чтобы не обрезать каждое фото отдельно вручную, хорошо бы применить код на питоне для автоматической обрезки лишних белых полей. Не всегда это корректно срабатывает, это зависит от качества скана, но в общем и целом может значительно облегчить вам редактирование старых фотографий, когда пакет файлов обрежется автоматически.

Ссылка на код на Гитхабе (можно взять):

<https://gist.github.com/ElenaInDespair/58bc2385445f38ec69244b089eb9ba39>

Краткое описание кода (с сокращениями, код не копируем, тут нет отступов):

import cv2

import os

import glob

  • импортируем библиотеки ---> OpenCV: для обработки изображений; os: предоставляет функции для манипулирования путями к файлам. glob: находит все пути, соответствующие указанному шаблону (подстановочные знаки).

extensions = ('*.jpg', '*.jpeg', '*.png', '*.bmp', '*.tiff')

  • Список типов файлов изображений, которые будет обрабатывать скрипт.
  • Подстановочный знак * позволяет сопоставлять любые имена файлов, заканчивающиеся на эти расширения.

image_files = []

for ext in extensions:

image_files.extend(glob.glob(os.path.join(folder_path, ext)))

  • этот цикл выполняет поиск в папке файлов, соответствующих каждому шаблону.
  • функция glob.glob() возвращает список имен файлов, соответствующих шаблону.
  • os.path.join() создает правильные пути к файлам в разных ОС.
  • все совпадающие имена файлов собираются в image_files.

for image_path in image_files:

print(f'Processing: {image_path}')

# загрузка изображений

image = cv2.imread(image_path)

if image is None:

print(f'Failed to load {image_path}')

continue

  • выполняется цикл по каждому файлу изображения.
  • функция cv2.imread() загружает изображение в память.
  • если изображение не может быть загружено (повреждено, имеет неправильный формат),оно пропускается и выводится сообщение.

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

  • Преобразуется цветное изображение в изображение в оттенках серого (одноканальное). Упрощает анализ яркости и определение границ.

_, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)

  • При установлении порогового значения изображение в оттенках серого преобразуется в двоичное изображение (черно-белое). Пиксели ярче 240 становятся равными 0 (черные), остальные - 255 (белые).

cv2.THRESHOLD_BINARY_INV инвертирует двоичное изображение.:

  • Светлые области (белые границы) становятся черными (0). Основное содержимое, обычно более темное, становится белым (255). Это помогает выделить белые границы.

contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

  • Находит контуры белых областей (которые после установления порогового значения становятся черными).
  • cv2.RETR_EXTERNAL: только внешние контуры, игнорируя вложенные.
  • cv2.CHAIN_APPROX_SIMPLE: сжимает горизонтальные, вертикальные и диагональные сегменты для экономии памяти.

if contours:

# находит самый большой контур

c = max(contours, key=cv2.contourArea)

x, y, w, h = cv2.boundingRect(c)

cropped_img = image[y:y+h, x:x+w]

  • Проверяет, были ли найдены какие-либо контуры. Предполагается, что самый большой контур соответствует основному содержимому изображения (а не границе).
  • cv2.boundingRect() находит наименьший прямоугольник, который охватывает контур (положение x, y и ширина, высота). Обрезает исходное изображение по этому прямоугольнику.

filename = os.path.basename(image_path)

name, ext = os.path.splitext(filename)

new_filename = f"{name}_cropped{ext}"

save_path = os.path.join(folder_path, new_filename)

cv2.imwrite(save_path, cropped_img)

print(f'Saved: {save_path}')

  • Извлекает имя файла и расширение.
  • Создает новое имя файла с добавлением "_cropped".
  • Сохраняет обрезанное изображение с помощью функции cv2.imwrite().
  • Печатает подтверждение.

else:

print(f'No contours found for {image_path}')

  • Если контуры не обнаружены, выводится сообщение об этом.

Попробуйте, возможно, вам будет полезно! Если у вас группа сканированных фото, где есть названия на русском, вам может пригодиться моя предыдущая статья, чтобы приготовить эти фото к обрезанию границ: