有没有一种简单的方法来比较BufferedImage实例?

2022-09-02 03:37:58

我正在开发一个Java应用程序的一部分,该应用程序将图像作为字节数组,将其读取到实例中并将其传递给第三方库进行处理。java.awt.image.BufferedImage

对于单元测试,我想获取一个映像(从磁盘上的文件中),并断言它等于代码已处理的相同映像。

  • 的预期是使用 从磁盘上的PNG文件中读取。BufferedImageImageIO.read(URL)
  • 我的测试代码将同一文件读入 a,并将其作为 PNG 写入字节数组,以提供给被测系统。BufferedImage

当被测系统将字节数组写入新的字节数组时,我想断言两个图像以有意义的方式相等。使用(继承自 )不起作用(当然)。比较值也不起作用,因为输出字符串包含对象引用信息。BufferedImageequals()ObjectBufferedImage.toString()

有人知道任何捷径吗?我宁愿不要在大型应用程序的一小部分中引入第三方库进行单个单元测试。


答案 1

这是最好的方法。无需保留变量来判断图像是否仍然相等。如果条件为假,只需立即返回 false。短路评估有助于节省比较失败后在像素上循环的时间,就像小号舔的答案中的情况一样。

/**
 * 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()) {
    return false;
  }

  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;
      }
    }
  }

  return true;
}

答案 2

如果速度是一个问题,并且两者具有相同的位深度,排列等(似乎在这里必须如此),您可以这样做:BufferedImages

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

弄清楚它是哪种类型,例如DataBufferInt

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

对数据缓冲器的大小和库进行一些“健全性检查”,然后循环

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));
}

这接近于您可以获得的速度,因为您一次获取一大块数据,而不是一次抓取一个。


推荐