#c #png #extract #pixel
#c #png #извлечь #пиксель
Вопрос:
Доступна ли библиотека изображений, которая позволяет пользователю извлекать пиксели из файла png, загруженного на диск, без его распаковки?
Итак, у меня есть 100 тысяч 8-битных изображений размером 512×512, где каждое из них составляет около 10 КБ в формате png. Это означает, что мне понадобится всего 1 ГБ оперативной памяти для хранения всех изображений во время выполнения программы, которую я пишу.
Возможно ли эффективно извлекать пиксели из изображения, подобного этому? Т.е. допустим, у меня есть массив images
, в котором images[i]
есть ссылки на изображение png, которое было загружено, но не распаковано в ОЗУ (это то, что происходит при загрузке изображения png?)
Тогда в идеале я хотел бы написать что-то вроде
pixel = images[i].getPixel(x,y);
Кто-нибудь знает, возможно ли это? Какая библиотека? Где мои предположения неверны?
Комментарии:
1. » извлекать пиксели из файла png, который был загружен на диск, не распаковывая его » Как это может быть возможно?
2. Под распаковкой я подразумеваю создание массива из 512×512 байт. Я почти уверен, что из изображения можно извлечь значение одного пикселя без извлечения всего изображения, но, возможно, я ошибаюсь.
3. Я уверен, что вам не нужно распаковывать все это. PNG сжимаются с помощью zlib, поэтому в худшем случае вам потребуется распаковать предыдущие данные.
Ответ №1:
Я не думаю, что вы сможете получить пиксель, не распаковав хотя бы предыдущую часть изображения. Когда вы открываете файл, он просто указывает на сжатые данные на диске. Когда вы запустите его через библиотеку PNG, он будет распакован.
Я думаю, что ваш лучший выбор и каноническая библиотека для чтения и записи PNG-файлов — libpng. Он обеспечивает отличный низкоуровневый доступ к данным изображения и метаданным и, вероятно, будет самым быстрым / наиболее эффективным вариантом. Это позволяет вам распаковывать данные строка за строкой (и, возможно, фрагмент за фрагментом — я не помню), так что вы, вероятно, можете распаковывать, пока не получите свой пиксель, затем выбросьте распакованные данные и перейдите к следующему изображению.
Недостатком является то, что это, вероятно, не так удобно для программистов, как некоторые другие варианты. Документация исчерпывающая до такой степени, что она утомительна, IMO, но могут быть более простые учебные пособия. С другой стороны, вам, вероятно, понадобятся все подробности в руководстве, чтобы выполнить требуемую минимальную декомпрессию. Это также поможет объяснить формат файла PNG, чтобы вы могли лучше управлять данными вплоть до уровня фрагмента.
Комментарии:
1. Можно ли выбрать, какую строку распаковывать? Мне это показалось бы достаточно хорошим решением.
2. Я так не думаю. Я думаю, вам нужно будет вызвать
png_read_row()
некоторое количество строк.3. По крайней мере, я так думаю, что libpng построен. Если вы углубитесь в детали (возможно, изменив исходный код), вы, возможно, сможете прочитать заголовок, пропустить некоторое количество
IDAT
фрагментов и просто распаковать небольшую группу пикселей, но сейчас я просто размышляю.
Ответ №2:
Я не думаю, что то, что вы просите, практично. К счастью, в этом также нет необходимости, если вы не сохраняете все несжатые изображения в памяти одновременно.
Разве вы не можете просто (загрузить и) распаковать по требованию, а затем освободить память, как только в ней больше не будет необходимости?
Комментарии:
1. Я полностью согласен, что это непрактично. Это нетривиальная проблема, из-за которой я немного застрял. Проблема в том, что мне приходится загружать значения пикселей со всех изображений миллионы раз в цикле (это вычисление разделения энтропии для построения дерева), а время доступа к жесткому диску сделало бы загрузку с диска полностью невозможной.
2. @twerdster Я не понимаю — если эти PNG не генерируются каким-то образом динамически, вам придется загружать их с диска, так или иначе. Это просто вопрос времени.
Ответ №3:
Во-первых, я не уверен, что понимаю ваше требование не распаковывать изображение в ОЗУ…
Хотя это может быть больше библиотеки, чем вы ищете, библиотека Cinder позволит вам легко загружать изображения и перебирать пиксели с помощью класса Surface.
Вот отличный учебник о том, как это сделать:
Ответ №4:
Я думаю, что лучшее, что вы можете сделать с этими требованиями, — это сжать все PNG-файлы в памяти (около 1 ГБ, как вы указали) и распаковывать только по одному, когда вы хотите получить из него пиксели. Размер буфера распакованного 8-битного изображения в оттенках серого размером 512×512 составляет 256 КБ. Если изображения имеют формат RGB, то размер составляет 768 КБ. Если у вас также есть альфа-канал, тогда размер будет 1 МБ.
Здесь вы можете найти очень легкую и простую библиотеку, которая распаковывает PNG.
Если вы хотите скрыть тот факт, что изображения сжимаются в памяти, вы можете поместить сжатые данные PNG в класс image . getPixel(x, y)
Метод в этом классе запустит распаковку, если изображение будет сжато. Члены класса в этом классе могут отслеживать, какое изображение было распаковано, и когда необходимо распаковать другое изображение, предыдущее может удалить его распакованный буфер.
Единственная проблема, с которой вы можете столкнуться при подобном решении, заключается в том, что система может сбиться, если вы перебираете 100 тысяч изображений, запрашивая только один пиксель, а затем переходите к следующему пикселю. Чтобы избежать этого, вам нужно будет получить всю необходимую информацию из одного изображения, а затем перейти к следующему изображению.
Комментарии:
1. Итак, используя pngs, невозможно извлечь значение пикселя без предварительного извлечения всего изображения?
2. Изображение сжато, поэтому значения пикселей нелегко получить, поскольку они закодированы эффективным способом. Единственный способ получить значение отдельного пикселя — это распаковать. Вы можете обойтись без распаковки частей изображения (минимум, пока не доберетесь до своего пикселя), но для этого вам понадобится пользовательский декодер. Решение, которое я предложил, позволит вам делать то, что вы хотите, но вам придется распаковывать по одному изображению за раз.