Добавление к файлу изображения - PullRequest
5 голосов
/ 06 декабря 2010

Я написал программу, которая делает «фотографию» и для каждого пикселя выбирает вставку изображения из ряда других фотографий.Выбранное изображение - это фотография, средний цвет которой наиболее близок к исходному пикселю фотографии.

Я сделал это, сначала усреднив значения rgb для каждого пикселя в «стоковом» изображении, а затем преобразовав его вCIE LAB, чтобы я мог рассчитать, насколько он «близок» к рассматриваемому пикселю с точки зрения восприятия человеком цвета.

Затем я скомпилировал изображение, в котором каждый пиксель исходного изображения «фото» имеетбыло заменено «ближайшим» изображением.

Работает хорошо, эффект хороший, однако размер стандартного изображения 300 на 300 пикселей и даже с флагами виртуальной машины «-Xms2048m -Xmx2048m», которыеда, я знаю, что это насмешка, на 555px на 540px изображение я могу заменить только стоковые изображения, уменьшенные до 50 px, прежде чем я получу ошибку нехватки памяти.

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

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

Любая помощь в этом последнем вопросе будет принята с благодарностью.

Спасибо,

Алекс

Ответы [ 3 ]

3 голосов
/ 06 декабря 2010

Я предлагаю изучить API Java Advanced Imaging (JAI).Возможно, вы сейчас используете BufferedImage, который хранит все в памяти: исходные изображения, а также выходные изображения.Это называется обработкой в ​​«немедленном режиме».Когда вы вызываете метод для изменения размера изображения, это происходит немедленно.В результате вы по-прежнему сохраняете изображения в памяти.

С JAI вы можете воспользоваться двумя преимуществами.

  1. Обработка в отложенном режиме.
  2. Вычисление плитки.

Отложенный режим означает, что выходные изображения не вычисляются правильно, когда вы вызываете методы для изображений.Вместо этого, вызов для изменения размера изображения создает небольшой объект «оператор», который может выполнить изменение размера позже.Это позволяет вам создавать цепочки, деревья или конвейеры операций.Таким образом, ваша работа будет создавать дерево операций, таких как «обрезать, изменять размер, составлять» для каждого изображения.Приятной особенностью является то, что операции являются просто объектами команд, поэтому вы не расходуете всю память, пока вы создаете свои команды.

Этот API основан на извлечении.Он откладывает вычисления до тех пор, пока какое-либо выходное действие не вытянет пикселей из операторов.Это быстро помогает сэкономить время и память, избегая ненужных операций с пикселями.

Например, предположим, что вам нужно выходное изображение с разрешением 2048 x 2048 пикселей, масштабированное по сравнению с кадрированием 512x512 из исходного изображения с разрешением 1600x512 пикселей.Очевидно, что не имеет смысла увеличивать все исходное изображение 1600x512, просто отбрасывая 2/3 пикселей.Вместо этого у оператора масштабирования будет «область интереса» (ROI), основанная на его выходных измерениях.Оператор масштабирования проецирует область интереса на исходное изображение и вычисляет только эти пиксели.

Команды в конечном итоге должны быть оценены.Это происходит в нескольких ситуациях, в основном связанных с выводом конечного изображения.Таким образом, запрос BufferedImage для отображения вывода на экране заставит все команды выполнить оценку.Аналогично, запись выходного изображения на диск приведет к принудительной оценке.

В некоторых случаях вы можете сохранить второе преимущество JAI - рендеринг на основе плиток.Принимая во внимание, что BufferedImage выполняет всю свою работу сразу, по всем пикселям, рендеринг тайлов одновременно работает только с прямоугольными участками изображения.

Используя предыдущий пример, выходное изображение 2048x2048 будет разбито на тайлы.Предположим, что это 256x256, тогда все изображение разбивается на 64 фрагмента.Объекты оператора JAI знают, как работать с плиткой на плитке.Таким образом, масштабирование 512x512 фрагментов исходного изображения действительно происходит 64 раза для исходных пикселей 64x64 за раз.

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

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


Несколько замечаний и предостережений:

  1. Вы можете победить рендеринг на основе плиток, даже не осознавая этого.Везде, где у вас есть BufferedImage в рабочем потоке, он не может выступать в качестве источника плитки или приемника.
  2. Если вы выполняете рендеринг на диск с помощью операторов ввода-вывода JAI или JAI Image для JPEG, то вы находитесь вхорошая фигура.Если вы попытаетесь использовать встроенные в JDK классы изображений, вам понадобится вся память.(По сути, избегайте смешивания двух типов манипуляций с изображениями. Непосредственный режим и отложенный режим плохо сочетаются.)
  3. Все интересные вещи с областями интереса, плитками и отложенным режимом прозрачны для программы.Вы просто делаете вызов API в классе JAI.Вы имеете дело с оборудованием только в том случае, если вам нужен больший контроль над такими вещами, как размеры листов, кэширование и параллелизм.
2 голосов
/ 06 декабря 2010

Вот предложение, которое может быть полезно;

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

0,0,image123.jpg
0,1,image542.jpg
.....

После того, как это задание выполнено (и это звучит так, как будто вы хорошо справились), тогда вы можете иметь отдельную программу для обработки компиляции.

Эту компиляцию можно выполнить, добавив изображение, но вы, вероятно, не хотите возиться с форматами файлов самостоятельно. Лучше позволить вашей среде программирования сделать это с помощью какого-либо объекта Java Image. Самое большое, которое вы можете поместить в память по пикселям, будет 2 ГБ, что приведет к максимальной (2 × 10 ^ 9) максимальной ширине и ширине. Из этого числа и деления на количество изображений, которые у вас есть по высоте и ширине, вы получите общее количество пикселей на разрешенный подизображение и сможете раскрасить их в соответствующие места.

0 голосов
/ 06 декабря 2010

Каждый раз, когда вы 'добавляете', возможно, вы неявно создаете новый объект с еще одним пикселем для замены старого (то есть, параллельно с классической проблемой многократного добавления строки вместо использования StringBuilder)?

Если вы разместите часть своего кода, которая выполняет хранение и добавление, кто-то, вероятно, поможет вам найти эффективный способ его перекодирования.

...