Как обрабатывать изображения, которые не помещаются в оперативную память в Python
Что проверяют
Понимаете ли вы, что проблема не в Python, а в формате файла и способе доступа к пикселям. Интервьюер ждёт обработку по тайлам или полосам и знание инструментов, которые так умеют. Следом обычно спрашивают, как применить фильтр без швов на границах тайлов.
Как отвечать
Сначала уточните масштаб: гигапиксельный снимок со спутника или микроскопа не помещается в память целиком, а миллион обычных фото решается простым пакетным обходом.
Для одного огромного изображения:
- тайловые форматы: тайловый TIFF или BigTIFF хранит картинку блоками, и каждый блок читается отдельно.
tifffileотдаёт такой файл как массив Zarr черезimread(path, aszarr=True), для геоданных уrasterioесть чтение окномsrc.read(window=Window(...)); - pyvips: обёртка над libvips, считает изображение по требованию полосами и держит в памяти немного строк.
Image.new_from_file(path, access="sequential")включает потоковое чтение, аdzsaveрежет результат в пирамиду тайлов; - Dask и Zarr: изображение как массив чанков, операции идут по кускам, а
map_overlapдобавляет перекрытие для фильтров с ядром; numpy.memmap: для несжатых сырых данных, операционная система подгружает только нужные страницы;- пирамиды: смотрите и грубо анализируйте уменьшенный уровень, а в полное разрешение спускайтесь только в интересных областях.
Сжатые JPEG и PNG произвольного доступа по сути не дают, их декодируют последовательно. Огромный кадр в таком формате лучше один раз перегнать в тайловый TIFF или Zarr.
Где спотыкаются
Считают, что Image.open() и crop() в Pillow спасают. Открытие ленивое, но первая операция с пикселями вызывает load(), и в память декодируется весь кадр. Вдобавок у Pillow есть защита от «бомб распаковки» Image.MAX_IMAGE_PIXELS, и её отключают, не понимая последствий.
Режут на тайлы без перекрытия, а потом применяют размытие или свёртку. На стыках появляются швы, нужен запас на радиус ядра.
Предлагают cv2.VideoCapture или временные файлы как «потоковую обработку». Первое читает видео, а не одно изображение, второе без тайлового формата ничего не экономит.