Обработка изображений на Python: инструменты и методы

Раздел: Обработка изображений -> библиотеки изображений

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

Python предлагает несколько библиотек для обработки изображений. Наиболее распространена Pillow (форк PIL), но существуют и другие инструменты с разными возможностями. Ниже рассмотрены основные варианты с примерами кода и типичными проблемами.

Как выполнить базовые операции с изображениями в Python?

Библиотека Pillow (установка: pip install Pillow) позволяет открывать, изменять размеры, обрезать, поворачивать и фильтровать изображения. Пример открытия и сохранения в другом формате:

from PIL import Image
img = Image.open('photo.jpg')
img.save('photo.png')

Python image library (библиотека изображений python)

Изменение размера с сохранением пропорций:

img.thumbnail((400, 300))  # уменьшает до заданного прямоугольника
img.save('thumb.jpg')

Обрезка области:

box = (10, 10, 200, 200)  # left, upper, right, lower
cropped = img.crop(box)
cropped.save('crop.jpg')

Применение фильтра (размытие):

from PIL import ImageFilter
blurred = img.filter(ImageFilter.GaussianBlur(radius=5))
blurred.save('blur.jpg')
Типичные проблемы: при открытии повёрнутых JPEG-файлов камера записывает ориентацию в EXIF, но Pillow её не применяет автоматически. Используйте ImageOps.exif_transpose(). Ошибка OSError: cannot identify image file – повреждённый файл или неподдерживаемый формат.

Как применить продвинутую обработку с помощью OpenCV?

OpenCV (установка: pip install opencv-python) предназначен для компьютерного зрения. Он работает с numpy-массивами, что даёт гибкость. Пример чтения, конвертации в оттенки серого и бинаризации:

import cv2
img = cv2.imread('image.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
cv2.imwrite('binary.jpg', thresh)

Детектирование границ алгоритмом Canny:

edges = cv2.Canny(gray, 50, 150)
cv2.imwrite('edges.jpg', edges)
Возможные ошибки: OpenCV использует порядок каналов BGR, а не RGB. При отображении через matplotlib нужно преобразование: cv2.cvtColor(img, cv2.COLOR_BGR2RGB). Файл не найден, если путь содержит кириллицу – используйте cv2.imdecode(np.fromfile(path, np.uint8), cv2.IMREAD_COLOR).

Какие научные методы доступны в библиотеке scikit-image?

scikit-image (установка: pip install scikit-image) предоставляет алгоритмы сегментации, морфологии, восстановления. Пример сегментации водоразделом:

from skimage import io, color, filters, segmentation
image = io.imread('cells.tif')
gray = color.rgb2gray(image)
edges = filters.sobel(gray)
markers = filters.peak_local_max(edges)
segmented = segmentation.watershed(edges, markers)
io.imsave('segmented.png', segmented)
Примечание: scikit-image возвращает массивы numpy, что позволяет комбинировать с другими библиотеками. Ошибка ValueError при несовпадении типов данных – преобразуйте в float64 или uint8.

Как использовать ImageMagick через библиотеку Wand?

Wand (установка: pip install Wand) – обёртка для ImageMagick. Пример конвертации изображения в PDF:

from wand.image import Image
with Image(filename='photo.jpg') as img:
    img.format = 'pdf'
    img.save(filename='output.pdf')

Изменение размера с высоким качеством:

with Image(filename='input.jpg') as img:
    img.resize(800, 600, filter='lanczos')
    img.save(filename='resized.png')
Проблемы: на системе должен быть установлен ImageMagick. В Windows требуется указать путь к библиотекам. Ошибка MissingDelegateError – отсутствует поддержка формата.

Как обрабатывать изображения напрямую через numpy?

Изображение можно представить как трёхмерный массив numpy. Пример инвертирования цветов:

import numpy as np
from PIL import Image
img = Image.open('photo.jpg')
arr = np.array(img)
inv_arr = 255 - arr
inv_img = Image.fromarray(inv_arr)
inv_img.save('inverted.jpg')

Поэлементные операции (увеличение яркости):

bright = np.clip(arr * 1.3, 0, 255).astype(np.uint8)
Image.fromarray(bright).save('bright.jpg')
Ошибки: несоответствие типов данных – массив должен быть uint8 для сохранения. Изменение формы без учёта каналов приводит к искажению.

Расширенные примеры работы с изображениями

Чтение и изменение EXIF-данных в Pillow

Извлечение метаданных из JPEG и их модификация.

Пример
from PIL import Image
from PIL.ExifTags import TAGS

img = Image.open('image.jpg')
exif = img._getexif()
for tag_id, value in exif.items():
    tag_name = TAGS.get(tag_id, tag_id)
    print(f'{tag_name}: {value}')

# Изменение ориентации
exif_data = img.info.get('exif')
if exif_data:
    from PIL.ExifTags import Base
    # Устанавливаем ориентацию 1 (нормальная)
    exif_dict = {}
    for k, v in img._getexif().items():
        exif_dict[TAGS.get(k)] = v
    exif_dict['Orientation'] = 1
    # Сохраняем с новым exif (требуется конвертация)
    # Проще использовать ImageOps.exif_transpose()
Результат: вывод списка тегов, например 'DateTimeOriginal: 2023:01:15 12:30:00'. При изменении ориентации изображение автоматически поворачивается.

Создание анимированного GIF из последовательности кадров

Объединение нескольких изображений в GIF-анимацию.

Пример
from PIL import Image

frames = []
for i in range(10):
    img = Image.new('RGB', (200, 200), color=(i*25, 50, 100))
    frames.append(img)

frames[0].save('animation.gif',
               save_all=True,
               append_images=frames[1:],
               duration=100,
               loop=0)
Создан файл animation.gif с 10 кадрами, каждый длительностью 100 мс, бесконечный цикл.

Использование маски для вырезания объекта

Наложение маски (чёрно-белого изображения) для извлечения части изображения.

Пример
from PIL import Image

image = Image.open('portrait.jpg')
mask = Image.open('mask.png').convert('L')  # маска в оттенках серого
result = Image.composite(image, Image.new('RGB', image.size, (0,0,0)), mask)
result.save('cutout.jpg')
Объект на белом фоне заменяется прозрачным (или чёрным). Альфа-канал маски учитывается.

Чтение изображений большого размера без полной загрузки

Использование ImageFile.Parser для потоковой обработки.

Пример
from PIL import ImageFile

parser = ImageFile.Parser()
with open('large_image.tif', 'rb') as f:
    chunk = f.read(8192)
    while chunk:
        parser.feed(chunk)
        chunk = f.read(8192)
img = parser.close()
print(img.size)
Выводится размер изображения без загрузки всего файла в память (эффективно для TIFF с LZW сжатием).

Конвертация в оттенки серого с сохранением альфа-канала

Стандартные методы преобразования теряют альфа. Сохраняем прозрачность вручную.

Пример
from PIL import Image

img = Image.open('logo.png').convert('RGBA')
if img.mode == 'RGBA':
    r, g, b, a = img.split()
    gray = Image.merge('RGB', (r, g, b)).convert('L')
    gray_rgba = Image.merge('RGBA', (gray, gray, gray, a))
else:
    gray_rgba = img.convert('L')
gray_rgba.save('gray_logo.png')
Сохраняется прозрачность исходного PNG. В результирующем изображении цветные пиксели становятся серыми, альфа-канал неизменен.

библиотека изображений Python - comments

En
Python image library (python)