Подтвердить что ты не робот

Есть ли простой способ сравнить экземпляры BufferedImage?

Я работаю над частью приложения Java, которое принимает изображение в виде байтового массива, считывает его в экземпляр java.awt.image.BufferedImage и передает его в стороннюю библиотеку для обработки.

Для unit test, я хочу взять образ (из файла на диске) и утверждать, что он равен тому же изображению, которое было обработано кодом.

  • Мой ожидаемый BufferedImage читается из PNG файла на диске с помощью ImageIO.read(URL).
  • Мой тестовый код читает один и тот же файл в BufferedImage и записывает его в массив байтов как PNG для предоставления тестируемой системе.

Когда тестируемая система записывает массив байтов в новый BufferedImage, я хочу сказать, что оба изображения одинаково значимым образом. Использование equals() (унаследовано от Object) не работает (конечно). Сравнение значений BufferedImage.toString() также не работает, потому что выходная строка содержит информацию об объекте.

Кто-нибудь знает какие-нибудь ярлыки? Я бы предпочел не приносить стороннюю библиотеку для одного unit test в небольшой части большого приложения.

4b9b3361

Ответ 1

Это лучший подход. Не нужно держать переменную, чтобы определить, равно ли изображение. Просто верните false сразу, когда условие if false. Оценка короткого замыкания помогает сэкономить время на пикселях после сравнения, как это происходит в случае trumpetlick .

/**
 * Compares two images pixel by pixel.
 *
 * @param imgA the first image.
 * @param imgB the second image.
 * @return whether the images are both the same or not.
 */
public static boolean compareImages(BufferedImage imgA, BufferedImage imgB) {
  // The images must be the same size.
  if (imgA.getWidth() == imgB.getWidth() && imgA.getHeight() == imgB.getHeight()) {
    int width = imgA.getWidth();
    int height = imgA.getHeight();

    // Loop over every pixel.
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        // Compare the pixels for equality.
        if (imgA.getRGB(x, y) != imgB.getRGB(x, y)) {
          return false;
        }
      }
    }
  } else {
    return false;
  }

  return true;
}

Ответ 2

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

DataBuffer dbActual = myBufferedImage.getRaster().getDataBuffer();
DataBuffer dbExpected = bufferImageReadFromAFile.getRaster().getDataBuffer();

выяснить, какой тип он, например. a DataBufferInt

DataBufferInt actualDBAsDBInt = (DataBufferInt) dbActual ;
DataBufferInt expectedDBAsDBInt = (DataBufferInt) dbExpected ;

выполните несколько "проверок здравомыслия" для равных по размерам и берегам DataBuffers, затем выполните цикл

for (int bank = 0; bank < actualDBAsDBInt.getNumBanks(); bank++) {
   int[] actual = actualDBAsDBInt.getData(bank);
   int[] expected = expectedDBAsDBInt.getData(bank);

   // this line may vary depending on your test framework
   assertTrue(Arrays.equals(actual, expected));
}

Это приближается так быстро, как вы можете получить, потому что вы захватываете кусок данных за раз, а не по одному.

Ответ 3

Вы можете написать свою собственную рутину для сравнения!

int width;
int height;
boolean imagesEqual = true;

if( image1.getWidth()  == ( width  = image2.getWidth() ) && 
    image1.getHeight() == ( height = image2.getHeight() ) ){

    for(int x = 0;imagesEqual == true && x < width; x++){
        for(int y = 0;imagesEqual == true && y < height; y++){
            if( image1.getRGB(x, y) != image2.getRGB(x, y) ){
                imagesEqual = false;
            }
        }
    }
}else{
    imagesEqual = false;
}

Это будет один из способов!!!

Ответ 4

Я изменил функцию, равную пикселям в Groovy, может быть полезно:

boolean imagesAreEqual(BufferedImage image1, BufferedImage image2) {
    if (image1.width != image2.width || image1.height != image2.height) {
         return false
    }
    for (int x = 1; x < image2.width; x++) {
        for (int y = 1; y < image2.height; y++) {
             if (image1.getRGB(x, y) != image2.getRGB(x, y)) {
                 return false
             }
        }
    }
    return true
}

Ответ 5

Я не могу думать ни о чем кроме грубой силы "do loop":

  BufferedImage bi1, bi2, ...
   ...
  Raster r1 = bi1.getData();
  DataBuffer db1 = r1.getDataBuffer();
  if (db1.getSize() != db2.getSize ())
     ...
  for (int i = 0; i < db1.getSize(); i++) {  
    int px = db1.getElem(i);
  }

Ответ 6

Вы можете записать это изображение через imageio через OutputStream в byte[]. В моем коде это выглядит примерно так:

byte[] encodeJpegLossless(BufferedImage img){...using imageio...}
...
Assert.assertTrue(Arrays.equals(encodeJpegLossless(img1)
                               ,encodeJpegLossless(img2)
                               )
                 );