Слияние больших изображений на диске - PullRequest
0 голосов
/ 11 мая 2018

Основная проблема:

У меня есть шаг карты, на котором я рендерил большое количество секторов изображения параллельно:

1 2
3 4

worker a -> 1
worker b -> 2
...

merge 1,2,3,4 to make final image

Если он может поместиться в памяти

С изображениями, которые являются относительно небольшими и могут помещаться в ОЗУ, можно просто использовать функциональность PIL:

def merge_images(image_files, x, y):
    images = map(Image.open, image_files)
    width, height = images[0].size    
    new_im = Image.new('RGB', (width * x, height * y))
    for n, im in enumerate(images):
        new_im.paste(im, ((n%x) * width, (n//y) * height))
    return new_im

К сожалению, у меня будет много, много больших секторов . Я хочу, наконец, объединить изображения в одно изображение размером примерно 40 000 x 60 000 пикселей, которое, по моим оценкам, составляет около 20 ГБ. (А может даже больше)

Итак, очевидно, мы не можем подойти к этой проблеме в оперативной памяти. Я знаю, что есть альтернативы, такие как memmap, использование массивов и запись в слайсы, которые я попробую. Однако Я ищу нестандартные решения .

Кто-нибудь знает какие-нибудь более простые альтернативы? Несмотря на то, что все подходы, которые я до сих пор пробовал, на python, он не обязательно должен быть на python .

Ответы [ 2 ]

0 голосов
/ 13 мая 2018

pyvips может делать то, что вы хотите, очень быстро и эффективно.Например:

import sys
import pyvips

images = [pyvips.Image.new_from_file(filename, access="sequential")
          for filename in sys.argv[2:]]
final = pyvips.Image.arrayjoin(images, across=10)
final.write_to_file(sys.argv[1])

Опция access="sequential" сообщает Pyvips, что вы хотите передать изображение.Он будет загружать только пиксели по требованию, поскольку генерирует выходные данные, так что вы можете объединять огромные изображения, используя только немного памяти.Оператор arrayjoin объединяет массив изображений в мозаичную сетку across.У него довольно много вариантов компоновки: вы можете указать границы, перекрытия, фон, поведение при центрировании и т. Д.

Я могу запустить его так:

$ for i in {1..100}; do cp ~/pics/k2.jpg $i.jpg; done
$ time ../arrayjoin.py x.tif *.jpg 

real    0m2.498s
user    0m3.579s
sys 0m1.054s
$ vipsheader x.tif
x.tif: 14500x20480 uchar, 3 bands, srgb, tiffload

Таким образом, он присоединился к 100 JPGизображений для создания мозаики размером 14 000 x 20 000 пикселей за 2,5 с на этом ноутбуке, а для просмотра top потребовалось около 300 МБ памяти.Я использовал его, чтобы объединить более 30000 изображений в один файл, и это будет выше.Я сделал изображения размером более 300 000 на 300 000 пикселей.

Пивиповский эквивалент PIL paste равен insert.Вы также можете использовать это, хотя это не будет работать так хорошо для очень большого количества изображений.

Также имеется интерфейс командной строки, поэтому вы можете просто ввести:

vips arrayjoin "${echo *.jpg}" x.tif --across 10

, чтобы объединить большой набор изображений JPG.

0 голосов
/ 13 мая 2018

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

LibTIFF - это канонический способ чтения и записи файлов TIFF. Он имеет простой способ создания нового файла TIFF и добавления плиток по одному за раз. Таким образом, ваша программа может создать файл TIFF, получить один сектор, записать его в виде (одного или нескольких) листов в файл TIFF, получить следующий сектор и т. Д. Вам придется выбрать размер плитки, чтобы равномерно разделить один сектор.

Существует привязка Python к LibTIFF, которая называется PyLibTIFF . Это должно позволить вам следовать приведенной выше модели из Python. В этом же репозитории имеется чистый модуль Python для чтения и записи файлов TIFF, я не знаю, способен ли он записывать файлы TIFF в тайлы или он позволяет записывать их порциями. Существует много других модулей Python для чтения и записи файлов TIFF, но большинство из них записывают одну матрицу в виде файла TIFF, а не позволяют записывать файл по одной плитке за раз.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...