Java - Как написать очень большое (20 000 x 20 000 пикселей или больше) изображение tif

Я работаю с очень большими изображениями tif, которые я составляю в одно большое изображение. У меня есть библиотека, созданная моим коллегой, которая генерирует пирамиду изображений и предоставляет очень удобный инструмент для визуализации пирамиды изображений. Этот визуализатор отлично подходит для получения пикового изображения на большом изображении и визуального определения точек интереса, но клиенты больше заинтересованы в анализе изображений на этих больших изображениях.

Таким образом, необходимо экспортировать очень большое изображение в один файл. Я считаю, что это проблематично, учитывая, что эти образы могут иметь размер от 800 МБ до нескольких ГБ. И сама задача загрузки этого единственного изображения в память является сложной задачей, особенно когда выполняется анализ изображения.

Мне было интересно, можно ли в java написать это большое изображение в формате tiff в виде блока или строки за строкой. В настоящее время моему приложению не хватает памяти на небольших (8 ГБ ОЗУ) машинах.

Текущий метод составления этих изображений:

  1. Сохраните значения пикселей в BufferedImage с помощью WritableRaster

    short[][]pixels = ...
    BufferedImage image = new BufferedImage(width, height, type);
    WritableRaster = image.getRaster();
    for (int row = 0; row < height; row++)
    {
        for (int col = 0; col < width; col++)
        {
           raster.setSample(col, row, 0, pixel[row][col]);
        }
    }   
    
  2. А затем записать буферизованное изображение на диск. В этой части я использую ImageJ для записи изображения в формате tif. Если есть лучшие способы поддержки 16-битных изображений tif в оттенках серого, я буду рад взглянуть

    // BufferedImage image; from above
    ...
    ImagePlus img = new ImagePlus();
    img.setImage(image);
    FileSaver fs = new FileSaver(img);
    fs.saveAsTiff(file.getAbsolutePath());  
    

Проблема с этим методом заключается в том, что он занимает слишком много памяти для машины с 8 ГБ ОЗУ.

В идеале я хотел бы иметь только один short[][]pixels. Это в основном потому, что мне нужно вычислить среднюю функцию смешивания, поэтому там будет некоторый объем памяти. Также в будущем я добавлю линейный бленд. short[][]pixels должен занимать только ~765 МБ ОЗУ для данных размером 20k x 20k пикселей, что, как мне кажется, в настоящее время неизбежно, поэтому для больших изображений, например, 100k x 100k пикселей, я надеюсь, что биологи не захотят экспортировать это изображение как это займет 18 ГБ ОЗУ.

Позже я изменю код для поддержки экспорта очень больших изображений, таких как 100k x 100k. На данный момент я согласен с тем, что для хранения начальных значений пикселей используется один фрагмент памяти.

Итак, каков хороший метод записи частей изображения tif на диск, чтобы я мог поддерживать запись основных изображений, таких как изображения 100k x 100k.

Я видел это сообщение: Напишите мозаичный вывод TIFF, используя ImageIO на Java

Но это просто обсуждает спецификацию TIFF 6.0. Но я посмотрю на ImageOutputStreams. Однако Тиф — зверь, поэтому я мог бы просто стиснуть зубы и призвать биологов экспортировать только интересующие области.

EDIT: найдено жизнеспособное решение:

ПИСАТЕЛЬ: https://github.com/openmicrooscopy/bioformats/blob/v4.4.8/components/scifio/src/loci/formats/out/TiffWriter.java

и

ЧИТАТЕЛЬ: https://github.com/openmicrooscopy/bioformats/blob/v4.4.8/components/scifio/src/loci/formats/in/TiffReader.java

Основная страница группы: https://github.com/openmicrooscopy/bioformats


person Jameshobbs    schedule 24.09.2013    source источник
comment
Можете ли вы работать с изображением по частям, скажем, квадратами по 10 000 пикселей, а затем объединить их все вместе?   -  person ug_    schedule 24.09.2013
comment
У меня нет проблем с работой с квадратами 10k px, проблема в том, как записать их в файл tif.   -  person Jameshobbs    schedule 24.09.2013
comment
Возможно, вам следует разделить проблему. 1. Напишите большой необработанный файл данных изображения. 2. Прочтите это и сохраните в формате tiff. Как только это сработает, вы можете попробовать сделать это за 1 проход.   -  person hyde    schedule 24.09.2013
comment
Еще одно предложение: используйте файлы с отображением памяти Java7 и 64-битной JVM и избавьте себя от головной боли.   -  person hyde    schedule 24.09.2013
comment
Вам нужна полная картина для вашего смешивающего фильтра? Или только часть?   -  person Ortwin Angermeier    schedule 24.09.2013
comment
Опять же, основная проблема здесь заключается в том, как написать tif по частям.   -  person Jameshobbs    schedule 24.09.2013
comment
@user2747970 согласно википедии, tiff состоит из фрагментов или полос, поэтому должно быть возможно ломать вещи.   -  person Ortwin Angermeier    schedule 24.09.2013
comment
@ user2747970 И я имел в виду, преобразовать эту проблему в запись необработанного (отображенного в память) файла по частям, что тривиально. Затем решите проблему чтения необработанных данных и последовательной записи tiff, что также должно быть тривиальным.   -  person hyde    schedule 24.09.2013
comment
@ortang В этом случае фильтру смешивания не требуется все изображение (решение этой проблемы должно быть тривиальным). Основная проблема, с которой я сталкиваюсь, связана с форматом файла tif и записью частичных изображений в большое изображение tif. Смешивание требуется, потому что я имею дело со сшиванием перекрывающихся изображений, и шаг композиции может включать 8 или более изображений для данного пикселя, поэтому каждый пиксель из каждого изображения смешивается для этого данного пикселя. В настоящее время я использую среднюю смесь. У меня также есть наложение, но оно имеет тенденцию иметь шум из-за разницы в яркости между изображениями.   -  person Jameshobbs    schedule 24.09.2013


Ответы (4)


В рамках проекта SCIFIO мы обобщаем структуру ввода-вывода изображений Bio-Formats для создания научных изображений в вообще, помимо микроскопии и наук о жизни. API SCIFIO сейчас находится в стадии бета-тестирования, и включает TIFF, который, конечно, может read и написать в плитках. Всегда приветствуются отзывы об API и ошибках в списке рассылки SCIFIO!

person ctrueden    schedule 26.09.2013
comment
С тех пор прошло довольно много времени, но я решил взглянуть на проект SCIFIO. У меня проблемы с выяснением, с чего именно начать писать TIFF с нуля. Я вижу scifio.initializeWriter, но для этого требуется объект MetaData, и неясно, как создать экземпляр этого объекта метаданных. Есть ли дополнительные руководства по использованию этого? - person Jameshobbs; 23.03.2020
comment
@Jameshobbs Не могли бы вы опубликовать свой вопрос на forum.image.sc? Это канал, который проект SCIFIO использует для поддержки в наши дни. Если вы упомянете ctrueden, я постараюсь ответить своевременно... спасибо! - person ctrueden; 26.03.2020

Хорошо, я нашел хорошее решение для этого на Java.

Спасибо @bdares за указание на BigTiff.

Но в комплекте с FIJI есть группа биоформатов, которая внедрила scifio.

Они предоставляют ряд поддерживаемых программ чтения/записи, одна из которых является TiffReader/Writer.

https://github.com/openmicrooscopy/bioformats/blob/v4.4.8/components/scifio/src/loci/formats/in/TiffReader.java

и

https://github.com/openmicrooscopy/bioformats/blob/v4.4.8/components/scifio/src/loci/formats/out/TiffWriter.java

Я отредактировал исходное сообщение. Спасибо всем за комментарии, это помогло мне посмотреть в правильном направлении.

person Jameshobbs    schedule 24.09.2013

Вопреки вашему комментарию, на самом деле не так уж сложно реализовать свой собственный писатель TIFF.

Спецификацию можно загрузить здесь. В частности, страницы 13-14 — это (почти) все, что вам нужно, чтобы понять, что такое TIFF и как его писать.

Учтите, что согласно спецификации 6.0 (действующей на сентябрь 2013 г.) максимальный размер образа составляет 4 ГБ. Я бы посоветовал обратиться к BigTiff. Различия в спецификациях указаны по второй ссылке.

person Community    schedule 24.09.2013
comment
Это действительно очень интересно. Я не знал, что размер заголовка ограничен 32-битными (4 ГБ). Похоже, мне придется переключиться с записи ImageJ на использование писателя Фиджи (или просто использовать libtiff). - person Jameshobbs; 24.09.2013

У вас есть двойной массив коротких. Вместо того, чтобы хранить это в памяти, вам нужно хранить это на диске и манипулировать им на диске. BufferedImage не поможет. Вам нужна библиотека (или написать библиотеку), которая позволяет манипулировать изображением на диске без необходимости полной загрузки изображения в память.

Вы не хотите получать доступ к каждому значению по отдельности. Вместо этого вы захотите сделать что-то вроде этого:

  1. прочитать блок (возможно, 4k, 8k или 40k, что имеет смысл).
  2. обработать весь блок.
  3. записать блок на диск.
  4. перейти к шагу 1, пока не закончите.
person DwB    schedule 24.09.2013
comment
Основная проблема здесь заключается в том, как писать поблочно для изображения tif. Я уже подумываю написать свой собственный модуль записи tif, но tif — не самый простой из протоколов, для которого нужно создавать модуль записи. - person Jameshobbs; 24.09.2013
comment
попробуйте создать изображение в более простом формате, чем использовать инструмент преобразования, чтобы сделать его tiff. - person DwB; 24.09.2013