2016-11-15 4 views
0

У меня возникли проблемы с получением данных о пикселях.Получение пиксельных значений из байт-массива

Моя программа делает скриншоты, каждый цикл хранит предыдущий снимок экрана.

Моя цель - выполнить сравнение на уровне пикселей между текущим скриншотом и старым.

Ive побежал этот код, который говорит мне, что формат скриншотов в: System.out.println(image.getType());

Выход этого (для моей программы) 1 означает сво BufferedImage.TYPE_INT_RGB

Из того, что Ive читать, типы определите, в каком порядке значения пикселей находятся в массиве байтов.

Я использую этот код, чтобы преобразовать мой Буферизированный изображение в массив байтов (Буферизованные изображение создается с помощью класса awt.Robot):

public byte[] convertToByteArray(BufferedImage img){ 
     byte[] imageInByte = null; 
     try { 



      // convert BufferedImage to byte array 
      ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
      ImageIO.write(img, "png", baos); 
      baos.flush(); 
      imageInByte = baos.toByteArray(); 
      baos.close(); 

     } catch (IOException ex) { 
      Logger.getLogger(OverlayWindow.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     return imageInByte; 
} 

Наконец я использовать метод сравнения, чтобы проверить массив байтов , Пока это печатает только цветовые значения массива:

final byte[] pixels = convertToByteArray(image); 
    final int pixelLength = 3; 
     for (int pixel = 0, row = 0, col = 0; pixel < 1; pixel += pixelLength) { 
     int argb = 0; 
     argb += -16777216; // 255 alpha 
     argb += ((int) pixels[pixel] & 0xff); // blue 
     argb += (((int) pixels[pixel + 1] & 0xff) << 8); // green 
     argb += (((int) pixels[pixel + 2] & 0xff) << 16); // red 


     int r = (argb >> 16) & 0xff, g = (argb >> 8)& 0xff, b = argb & 0xff; 
     System.out.println("R = " + r); 
     System.out.println("G = " + g); 
     System.out.println("B = " + b); 

     col++; 
     if (col == width) { 
      col = 0; 
      row++; 
     } 




    } 

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

-Edit-

Я избежать использования getRGB соображений производительности. Итерация через два больших изображения, вызывающих getRGB, каждый раз очень дорого в моем приложении.

+0

Мы не собираемся знать, что происходит - у вас есть полная работающая программа со всеми подробностями, которые вы делаете? – gpasch

+0

Прежде всего, «пиксели» не являются значениями пикселей, это байты сжатого файла PNG ... Так что это не сработает. Во-вторых, если у вас уже есть значения пикселей в виде отдельных выборок R, G и B (что предполагает ваш код), зачем пытаться упаковать их в 32-битный формат ARGB и снова распаковать их? Сначала я предлагаю использовать 'int argb = image.getRGB (x, y);', а затем расщепляюсь на R, G и B, как вы уже это делали. Тогда оптимизируйте оттуда, если это не достаточно быстро ... – haraldK

+0

Я обновил свой вопрос. Итак, массив байтов - проблема? Я попытался использовать это, чтобы получить массив байтов изначально: '((DataBufferByte) bufferedImage.getData(). GetDataBuffer()). GetData();' это вызывает следующую ошибку при попытке запуска: 'java.lang.ClassCastException : java.awt.image.DataBufferInt не может быть отброшен в java.awt.image.DataBufferByte', так что было бы правильным способом получить массив байтов для сравнения пикселей? – user3712476

ответ

2

Самый простой способ получить доступ к значениям пикселей в BufferedImage является использование Растр:

BufferedImage image = ... 
for (int y=0 ; y < image.getHeight() ; y++) 
    for (int x=0 ; x < image.getWidth() ; x++) 
     for (int c=0 ; c < image.getRaster().getNumBands() ; c++) 
      final int value = image.getRaster().getSample(x, y, c) ; // Returns the value of the channel C of the pixel (x,y) 

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

/* This method takes a BufferedImage encoded with TYPE_INT_ARGB and copies the pixel values into an image encoded with TYPE_4BYTE_ABGR.*/ 
public static void IntToByte(BufferedImage source, BufferedImage result) 
    { 
    final byte[] bb = ((DataBufferByte)result.getRaster().getDataBuffer()).getData() ; 
    final int[] ib = ((DataBufferInt)source.getRaster().getDataBuffer()).getData() ; 

    switch (source.getType()) 
     { 
     case BufferedImage.TYPE_INT_ARGB : 
      for (int i=0, b=0 ; i < ib.length ; i++, b+=4) 
       { 
       int p = ib[i] ; 
       bb[b] = (byte)((p & 0xFF000000) >> 24) ; 
       bb[b+3] = (byte)((p & 0xFF0000) >> 16) ; 
       bb[b+2] = (byte)((p & 0xFF00) >> 8) ; 
       bb[b+1] = (byte)(p & 0xFF) ; 
       } 
      break ; 
     // Many other case to manage... 
     } 
    } 
+0

- это 'BufferedImage.TYPE_INT_RGB' тот же тип форматирования, что и' BufferedImage.TYPE_INT_ARGB'? Также мне не нужно кодировать его на другое изображение, но я вижу, где вы показываете, как получить значения пикселей, моя единственная проблема с этим: '((DataBufferByte) result.getRaster(). GetDataBuffer()). GetData()' throws исключение: 'java.lang.ClassCastException: java.awt.image.DataBufferInt не может быть добавлено в java.awt.image.DataBufferByte' – user3712476

+0

BufferedImage.TYPE_INT_RGB и BufferedImage.TYPE_INT_ARGB - это одна и та же кодировка в один int, это только альфа-канал, который присутствует или нет. – FiReTiTi

+0

Исключением является то, что вы хотите бросить DataBufferInt в DataBufferByte. Таким образом, вы пытаетесь получить доступ к изображению, закодированному с помощью int, путем перевода его в байты. Как я уже сказал, при использовании DataBuffer вам нужно управлять всеми кодировками. – FiReTiTi