2015-11-17 3 views
4

Я изо всех сил пытаюсь выполнить эквивалентный код с помощью PNGJ. Я не хочу использовать ImageIO.read и BufferedImage.getRGB. Вместо этого я хочу получить пиксели, используя PNGJ. Код ниже был моей версией ImageIO + BufferedImage.Чтение PNG пикселей с использованием PNGJ без BufferedImage

BufferedImage bi = ImageIO.read(imageFile); 
... 
int[] pixels = new int[arrSize]; 
bi.getRGB(0, 0, width, height, pixels, 0, width); 

Я хочу что-то вроде в PNGJ-х

lint = (ImageLineInt) reader.readRow(); 
scanLine = lint.getScanline(); 
... 
??? 

Вот мои тестовые детали изображения:
ImageInfo [смещ_по_столбцы = 1530, строки = 1980, глубина цвета = 8, каналы = 3, bitspPixel = 24 , bytesPixel = 3, bytesPerRow = 4590, samplesPerRow = 4590, samplesPerRowP = 4590, alpha = false, greyscale = false, indexed = false, packed = false]

+1

Если я понимаю ваши комментарии к ответу @ FiReTiTi, ваш вопрос не в том, как использовать PNGJ, но более «Как я могу получить доступ к пикселям быстрее»? Если это так, вы можете сделать несколько действий, чтобы сделать «ImageIO.read» быстрее. Самый большой выигрыш обычно достигается с помощью 'ImageIO.setUseCache (false)'. – haraldK

+0

Спасибо @haraldK Я пробовал код, который вы опубликовали, и вы правы, это быстрее. Около ~ 50 мс в виде разреза (по крайней мере, на моем тесте). Хотя PNGJ еще быстрее (~ 40 мс быстрее), чем ImageIO с setUseCache (false). Я преуспел в преобразовании ints, возвращаемых PNGJ. Я выложу это через некоторое время. –

ответ

0

Вы можете иметь пиксели, используя BufferedImage. получить RGB является одним из самых медленных способов доступа к значениям пикселей. Вы хотите получить доступ к DataBuffer.

BufferedImage bi = ImageIO.read(imageFile); 
byte[] pixels = ((DataBufferByte)bi.getRaster().getDataBuffer()).getData() ; 

Вы должны быть осторожны с кодировкой изображения (байт, интервал или короткий).

+0

Спасибо за ответ, но я не хочу читать файл и скрывать его до BufferedImage перед доступом к пикселям. Эта строка: BufferedImage bi = ImageIO.read (imageFile); занимает около 200 мс в моем тесте с изображением 1530x1980. С PNGJ я могу читать пиксели PNG, но тогда я не знаю, как пропустить эти массивы int, возвращаемые PNGJ. Моя цель - сопоставить его с возвратом BufferedImage.getRGB. Я реорганизую свой код, чтобы заменить BufferedImage.getRGB на PNGJ. –

+0

Я не использую PNGJ. Чтобы помочь вам в ваших тестах, вы можете использовать getRaster(). GetSample (x, y, c) вместо getRGB(). Мне было бы намного легче проверить значения и сравнить результат. Имейте в виду, что java не использует значения без знака. – FiReTiTi

+0

Кстати, на моем ноутбуке я читал 42 изображения RGB 1024x1024 в ~ 560 мс с помощью ImageIO, поэтому ~ 13.3 мс/изображение (SSD HDD). Возможно, у вас есть проблема в другом месте ... BufferedImage - всего лишь 1D-массив. – FiReTiTi

2

До сих пор вот что я нашел. https://code.google.com/p/pngj/wiki/FAQ

Как читать/записывать значения пикселей? Каждый вызов PREReader readRow() возвращает IImageLine, представляющий строку изображения PNG; конкретная реализация расширяема. Но по умолчанию включена реализация (PngReader или PngReaderInt) возвращает ImageLineInt. Этот класс обертывает масштабируемым (getScanline()), который является массивом int []. Каждый элемент этот массив соответствует образцу изображения; поэтому длина массива равна (по крайней мере ) столбцам x каналов.

Альтернативный формат ImageLineByte, который идентичен за исключением того, он хранит каждый образец в бай (преимущество: меньше использования памяти, оптимальная скорости для 8bits изображений; недостатки: теряет разрешение, если изображение 16 бит на канал , и более громоздко выполнять арифметику - байты в Java подписываются).

Компоновка значений выборок внутри строки развертки заключается в следующем:

Для истинных цветных изображений, RGB/RGBA образцы в RGB (А) Последовательность: RG BRGB ... (без альфа-канала) или RGBARGBA ... (с альфой); значения не масштабируются: они будут находиться в диапазоне 0-255, только если битдепт = 8 (0-65535, если бит-бит = 16, 0-15, если бит-бит = 4 и т. д.). Для индексированных изображений каждое значение образца соответствует индексу палитры I I .... Для полутоновых изображений G/GA это серое значение G G G ... (без альфа) или G A G A ... (с альфой).

Вот код, который я использовал, который может быть подан в BufferedImage (с прозрачностью.TRANSLUCENT) позже:

PngReader reader = new PngReader(inputPNGFile); 
arrSize = (int) reader.imgInfo.getTotalPixels(); 

width = reader.imgInfo.cols; 
height = reader.imgInfo.rows; 
channels = reader.imgInfo.channels;  

ImageLineInt lint; 
while (reader.hasMoreRows()) { 
    lint = (ImageLineInt) reader.readRow(); 
    scanLine = lint.getScanline(); 

    for (i = 0; i < width; i++) { 
     offset = i * channels; 

     // Adjust the following code depending on your source image. 
     // I need the to set the alpha channel to 0xFF000000 since my destination image 
     // is TRANSLUCENT : BufferedImage bi = CONFIG.createCompatibleImage(width, height, Transparency.TRANSLUCENT); 
     // my source was 3 channels RGB without transparency 
     nextPixel = (scanLine[offset] << 16) | (scanLine[offset + 1] << 8) | (scanLine[offset + 2]) | 0xFF000000; 

     // I'm placing the pixels on a memory mapped file 
     mem.putInt(nextPixel); 
    } 

} 
4

В ответ зэка в указывает, PNGJ отличается от BufferedImage: это более низкий уровень, в том, что он не пытается изображать пиксели изображения в абстрактном общем формате (независимо от конкретного PNG формат), но вместо этого дает вам значения в формате, который отображается непосредственно в формате PNG и цветовой модели.

Это означает, что, например, если изображение PNG представляет собой RGB, вы получите три компонента RGB как прецедентные (целочисленные) значения. Если изображение PNG индексируется, вы получите индекс (целочисленное значение, указывающее на палитру). Если изображение PNG имеет серое значение, вы получите серое значение как одно целое число. И т. Д.

Если вы хотите обработать значения пикселей в более общем виде (дайте мне значения RGB, независимо от базовой цветовой модели), вы можете сделать преобразование самостоятельно или воспользоваться вспомогательными методами в ImageLineHelper класс. В частности, посмотрите на методы convert2rgba() и getPixelARGB8().

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

(Но, но ... BufferedImage делает это с полной общностью, без двусмысленностей и без проблем, вы говорите? not exactly)

Если вы КИ с ограничением для вашей модели цвета (RGB, 8 бит, нет альфа) (и у вас нет прозрачности TRNS чанка или гамма особенности, или не волнует), то это не совсем просто:

for (int i = 0,j=0 ; i < reader.imgInfo.cols; i++, j+=channels) { 
     int r = scanLine[j]; 
     int g = scanLine[j+1]; 
     int b = scanLine[j+2]; 
    // ... 
} 

Отказ от ответственности: Я PNGJ кодировщик.

Смежные вопросы