Как извлечь пиксель из PNG-файла с помощью C ++? - PullRequest
0 голосов
/ 17 октября 2011

Имеется ли библиотека изображений, которая позволяет пользователю извлекать пиксели из файла png, который был загружен на диск, не распаковывая его?

Итак, у меня есть 100k 8-битные изображения размером 512x512, где каждое из них составляет около 10kb в формате png. Это означает, что мне понадобится всего 1 ГБ ОЗУ для хранения всех изображений во время выполнения программы, которую я пишу.

Возможно ли эффективно извлечь пиксели из изображения, подобного этому? То есть Допустим, у меня есть массив images, где images[i] ссылается на изображение PNG, которое было загружено, но не распаковано в ОЗУ (это происходит при загрузке изображения PNG?)

Тогда в идеале я хотел бы написать что-то вроде

pixel = images[i].getPixel(x,y);

Кто-нибудь знает, возможно ли это? Какая библиотека? Где мои предположения ложны?

Ответы [ 4 ]

2 голосов
/ 17 октября 2011

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

Лучшая ставка, я думаю, и каноническая библиотека для чтения и записи PNG - libpng . Он обеспечивает отличный низкоуровневый доступ к данным изображения и метаданным и, вероятно, будет самым быстрым / наиболее эффективным вариантом. Это позволяет вам распаковывать данные построчно (и, возможно, порцию за порцию - я не помню), так что вы можете распаковать, пока не получите свой пиксель, затем сбросить распакованные данные и перейти к следующему изображению.

Недостатком является то, что он, вероятно, не так удобен для программистов, как некоторые другие варианты. Документация является исчерпывающей до такой степени, что является утомительной, IMO, но там могут быть более простые учебники. С другой стороны, вам, вероятно, понадобятся все детали в руководстве, чтобы выполнить минимальную декомпрессию, к которой вы стремитесь. Это также поможет объяснить формат файла PNG, чтобы вы могли лучше управлять данными вплоть до уровня чанка.

2 голосов
/ 17 октября 2011

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

Не можете ли вы просто (загрузить и) распаковать по требованию, а затем освободить память, как только она больше не нужна?

1 голос
/ 17 октября 2011

Я думаю, что лучшее, что вы можете сделать с этими требованиями, - это сжать все PNG в памяти (примерно 1 ГБ, как вы указали) и распаковывать только один раз, когда вы хотите получить из него пиксели. Размер буфера распакованного 8-битного изображения в градациях серого 512x512 составляет 256 КБ. Если изображения RGB, то размер составляет 768 КБ. Если у вас также есть альфа-канал, то размер будет 1 МБ.

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

Если вы хотите скрыть тот факт, что изображения сжимаются в памяти, вы можете поместить сжатые данные PNG в класс изображений. Метод getPixel(x, y) в этом классе вызовет распаковку, если изображение сжато. Члены класса в этом классе могут отслеживать, какое изображение было распаковано, и когда другое изображение необходимо распаковать, предыдущее может сбросить его распакованный буфер.

Единственная проблема, с которой вы можете столкнуться при таком решении, состоит в том, что система может thrash , если вы перебираете свои 100K-изображения, запрашивая только один пиксель, а затем переходите к следующему пикселю. Чтобы избежать этого, вам нужно будет получить всю необходимую информацию из одного изображения, а затем перейти к следующему изображению.

1 голос
/ 17 октября 2011

Во-первых, я не уверен, что понимаю ваше требование не распаковывать образ в ОЗУ ...

Хотя это может быть больше библиотеки, чем вы ищете, библиотека Cinder позволит вам легко загружать изображения и перебирать пиксели с помощью класса Surface.

Вот отличное руководство, как это сделать:

http://libcinder.org/docs/v0.8.3/guide___images.html

...