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

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

对于unit testing,我想拍摄一张图像(来自磁盘上的文件)并声明它等于代码处理过的相同图像。

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

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

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

这是最好的方法。 无需保留变量来判断图像是否仍然相等。 如果条件为false,则立即返回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()) { 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; } 

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

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

弄清楚它是哪种类型,例如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)); } 

由于您一次抓取一大块数据,而不是一次抓取一大块数据,因此接近最快速度。

您可以编写自己的例程进行比较!

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

这将是一种方式!

我更改了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 } 

除了蛮力“循环”之外我什么都想不到:

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

您可以通过imageio通过OutputStream将该图像写入byte[] 。 在我的代码中,它看起来或多或少像这样:

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

运作良好,但效率不高

 public static boolean compareImage(File fileA, File fileB) { try { // take buffer data from botm image files // BufferedImage biA = ImageIO.read(fileA); DataBuffer dbA = biA.getData().getDataBuffer(); int sizeA = dbA.getSize(); BufferedImage biB = ImageIO.read(fileB); DataBuffer dbB = biB.getData().getDataBuffer(); int sizeB = dbB.getSize(); // compare data-buffer objects // if(sizeA == sizeB) { for(int i=0; i