Как я могу записать в файл png / tiff патч за патчем?

Я хочу создать файл изображения в формате png или tiff из очень большого набора данных h5py, который нельзя загрузить в память сразу. Итак, мне было интересно, есть ли в python способ записи в файл png или tiff в патчах? (Я могу загрузить набор данных h5py фрагментами в numpy.ndarray). Я пробовал использовать библиотеку подушек и делал PIL.Image.paste, задавая координаты коробки, но для больших изображений она выходит из памяти.

В принципе, мне интересно, есть ли способ сделать что-то вроде:

for y in range(0, height, patch_size):
    for x in range(0, width, patch_size):
        y2 = min(y + patch_size, height)
        x2 = min(x + patch_size, width)
        # image_arr is an h5py dataset that cannot be loaded completely
        # in memory, so load it in slices
        image_file.write(image_arr[y:y2, x:x2], box=(y, x, y2, x2))

Я ищу способ сделать это без загрузки всего изображения в память. Я пробовал библиотеку подушек, но она загружает / сохраняет все данные в памяти.

Обновлено: этот вопрос не о h5py, а скорее о том, насколько чрезвычайно большие изображения (которые не могут быть загружены в память) мы можем записать в файл патчами - аналогично тому, как большие текстовые файлы могут быть созданы путем записи в него построчно.

tifffile.memmap дает вам массив numpy с отображением памяти, хранящийся в файле TIFF. Но без сжатия или плитки.
cgohlke 17.06.2018 01:46

Не могли бы вы создать кучу отдельных относительно небольших изображений в формате png / tiff и впоследствии объединить их все в одно большое?

martineau 17.06.2018 02:13

Голосование закрыто. Возможный дубликат Читает ли h5py весь файл в память?

Colonder 17.06.2018 02:14

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

assassin 17.06.2018 14:39

@martineau - их объединение потребует загрузки их данных в память. Здесь все данные не могут быть загружены в память, поэтому записываются небольшими фрагментами.

assassin 17.06.2018 14:40

assassin: Вы объединяете размер набора данных h5py и размер изображения (изображений). Тот факт, что один из них очень большой, не означает, что изображение, созданное из него, будет таким же большим.

martineau 17.06.2018 15:36

@martineau - Для этого вопроса предположим, что массив изображений не может быть загружен в память в несжатом виде? Цель этого вопроса - найти в python хороший способ записи больших изображений в мозаичном формате (или патч за патчем).

assassin 20.06.2018 18:54

убийца: Что хорошего в изображении, которое слишком велико, чтобы уместиться в памяти? Тем не менее, я сомневаюсь, что вы сможете добиться этого, пытаясь собрать кучу изображений вместе в любом из этих двух сжатых форматов. Если бы вместо этого, если бы он был несжатым (или ограничивался строчно-ориентированным сжатием, например RLE), можно было бы минимизировать использование памяти при их объединении, открыв только число, необходимое в любой момент времени, которое содержало строки тех же строк финальное изображение. Это позволило бы соединить линии окончательного изображения, не считывая их все сразу в память.

martineau 21.06.2018 00:42

Я также не вижу смысла в том, чтобы одно изображение было слишком большим, чтобы поместиться в памяти. Как вы это сделаете? Для таких вещей, как карты, на которых вы концептуально должны были бы иметь одно большое изображение, на практике они разбиваются на плитки и обслуживаются по запросу. Если ваш вопрос не относится к HDF5, то это похоже на дубликат этого: stackoverflow.com/questions/31806526/…

Jeff Ellen 24.06.2018 13:19

Насколько я понимаю, TIFF, тем не менее, не поддерживает изображения размером более 4 ГБ. Вы можете записать патчи в несколько файлов TIFF и сложить их вместе в 3D-файл TIFF. Стандарт tiff определяет определение «полосок», которые можно независимо сжимать. Я не знаю библиотеки для их написания. Насколько велики изображения, которые вы хотите написать?

Dschoni 25.06.2018 18:07

Пожалуйста, обновите вопрос, указав свои требования относительно сжатия или плиток. Как уже упоминалось, tifffile.memmap можно использовать для произвольной записи в несжатые файлы BigTIFF с чередованием.

cgohlke 26.06.2018 23:58
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
11
11
935
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Краткий ответ на вопрос «есть ли в Python способ записи в файл png или tiff патчами?». Что ж, да - в Python все возможно, если учесть достаточно времени и навыков, чтобы это реализовать. С другой стороны, НЕТ, готового решения для этого нет - потому что это не кажется очень полезным.

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

Если вы В самом деле хотите продолжить, вот информация, которая вам нужна: Файл PNG состоит из нескольких фрагментов метаданных и серии фрагментов данных изображения. Последние не зависят друг от друга, и поэтому вы можете создать большое изображение из нескольких меньших изображений (каждое из которых содержит целое количество строк, минимум одну строку), просто объединив их блоки данных изображения (IDAT) вместе и добавив необходимые фрагменты метаданных (вы можете выбрать их из первого небольшого изображения, за исключением фрагмента IHDR - он должен быть сконструирован таким образом, чтобы он содержал окончательный размер изображения).

Итак, вот как я бы это сделал, если бы мне пришлось (ПРИМЕЧАНИЕ, вам понадобится некоторое понимание типа Python bytes и методов преобразования байтовых последовательностей в типы данных Python и из них, чтобы осуществить это):

  • найдите, сколько строк я могу уместить в памяти, и сделайте это высотой моего «маленького фрагмента изображения». Ширина - это ширина всего окончательного изображения. назовем их width и small_height

  • просмотреть мой гигантский набор данных в h5py по одному фрагменту (width * small_height), преобразовать его в PNG и сохранить на диск во временном файле или, если ваша библиотека преобразования изображений это позволяет, - непосредственно в строку bytes в памяти. Затем обработайте байтовые данные следующим образом и удалите их в конце:

    - на первой итерации: просматривайте данные PNG по одной записи за раз (см. спецификацию PNG: http://www.libpng.org/pub/png/spec/1.2/png-1.2-pdg.html, это в форме значения тега длины и очень легко написать код, который эффективно перемещается по записи файла за записью) , сохраните ВСЕ записи в мой целевой файл, Кроме: измените IHDR, чтобы получить окончательный размер изображения, и пропустите запись IEND.

    - на всех последующих итерациях: просканируйте данные PNG и выберите только записи IDAT, запишите их в выходной файл.

  • добавить запись IEND в целевой файл.

Все готово - теперь у вас должен быть действительный огромный PNG. Хотя мне интересно, кто или что мог это прочитать.

Ответ принят как подходящий

Попробуйте tifffile.memmap:

from tifffile import memmap

image_file = memmap('temp.tif', shape=(height, width), dtype=image_arr.dtype,
                    bigtiff=True)

for y in range(0, height, patch_size):
    for x in range(0, width, patch_size):
        y2 = min(y + patch_size, height)
        x2 = min(x + patch_size, width)
        image_file[y:y2, x:x2] = image_arr[y:y2, x:x2]

image_file.flush()

Это создает несжатый файл BigTIFF с одной полосой. Плитки с отображением в память еще не реализованы. Не уверен, сколько библиотек могут обрабатывать такие файлы, но вы всегда можете напрямую читать из полосы, используя метаданные в тегах TIFF.

@gohlke bigtiff = True, похоже, не работает в последней версии.

Philippe Remy 17.09.2020 12:35

Другие вопросы по теме