使用Java以编程方式确定2个图像是否相同

在JAVA中,我试图以编程方式判断屏幕上显示的图像是否相等(即使它们具有不同的颜色空间,也是相同的图像。是否有一段代码在呈现2个图像时将返回布尔值?

我的一个例子是RGB PNG,我转换为灰度PNG。 两个图像看起来都一样,我想以编程方式certificate这一点。 另一个例子是两个图像,它们向屏幕显示完全相同的颜色像素,但用于100%透明像素的颜色已经改变。

对于灰度图像,我使用均方误差作为衡量两幅图像之前的差异的方法。 只需将每个图像中的相应像素插入公式即可。

这不仅可以告诉你它们是否完全相同,而且它可以告诉你两个图像是如何不同的,尽管它们是相当粗糙的。

https://en.wikipedia.org/wiki/Mean_squared_error

编辑:

注意:这是C#代码而不是Java(道歉,但这是我最初写的),但它应该很容易转移。

//Calculates the MSE between two images private double MSE(Bitmap original, Bitmap enhanced) { Size imgSize = original.Size; double total = 0; for (int y = 0; y < imgSize.Height; y++) { for (int x = 0; x < imgSize.Width; x++) { total += System.Math.Pow(original.GetPixel(x, y).R - enhanced.GetPixel(x, y).R, 2); } } return (total / (imgSize.Width * imgSize.Height)); } 

我查看了所有解决方案,并确定他们可以告诉您图像对于某些类型的图像有多么不同或不同,但不是全部。 这是我提出的解决方案……

 package image.utils; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.awt.color.ColorSpace; import java.awt.image.BufferedImage; import java.awt.image.ColorConvertOp; import java.awt.image.PixelGrabber; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import javax.swing.ImageIcon; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility methods used to interact with images. */ public class ImageUtils { private final static Logger logger = LoggerFactory.getLogger(ImageUtils.class); private static final boolean equals(final int[] data1, final int[] data2) { final int length = data1.length; if (length != data2.length) { logger.debug("File lengths are different."); return false; } for(int i = 0; i < length; i++) { if(data1[i] != data2[i]) { //If the alpha is 0 for both that means that the pixels are 100% //transparent and the color does not matter. Return false if //only 1 is 100% transparent. if((((data1[i] >> 24) & 0xff) == 0) && (((data2[i] >> 24) & 0xff) == 0)) { logger.debug("Both pixles at spot {} are different but 100% transparent.", Integer.valueOf(i)); } else { logger.debug("The pixel {} is different.", Integer.valueOf(i)); return false; } } } logger.debug("Both groups of pixels are the same."); return true; } private static final int[] getPixels(final BufferedImage img, final File file) { final int width = img.getWidth(); final int height = img.getHeight(); int[] pixelData = new int[width * height]; final Image pixelImg; if (img.getColorModel().getColorSpace() == ColorSpace.getInstance(ColorSpace.CS_sRGB)) { pixelImg = img; } else { pixelImg = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(img, null); } final PixelGrabber pg = new PixelGrabber(pixelImg, 0, 0, width, height, pixelData, 0, width); try { if(!pg.grabPixels()) { throw new RuntimeException(); } } catch (final InterruptedException ie) { throw new RuntimeException(file.getPath(), ie); } return pixelData; } /** * Gets the {@link BufferedImage} from the passed in {@link File}. * * @param file The File to use. * @return The resulting BufferedImage */ @SuppressWarnings("unused") final static BufferedImage getBufferedImage(final File file) { Image image; try (final FileInputStream inputStream = new FileInputStream(file)) { // ImageIO.read(file) is broken for some images so I went this // route image = Toolkit.getDefaultToolkit().createImage(file.getCanonicalPath()); //forces the image to be rendered new ImageIcon(image); } catch(final Exception e2) { throw new RuntimeException(file.getPath(), e2); } final BufferedImage converted = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB); final Graphics2D g2d = converted.createGraphics(); g2d.drawImage(image, 0, 0, null); g2d.dispose(); return converted; } /** * Compares file1 to file2 to see if they are the same based on a visual * pixel by pixel comparison. This has issues with marking images different * when they are not. Works perfectly for all images. * * @param file1 First file to compare * @param file2 Second image to compare * @return true if they are equal, otherwise * false. */ private final static boolean visuallyCompareJava(final File file1, final File file2) { return equals(getPixels(getBufferedImage(file1), file1), getPixels(getBufferedImage(file2), file2)); } /** * Compares file1 to file2 to see if they are the same based on a visual * pixel by pixel comparison. This has issues with marking images different * when they are not. Works perfectly for all images. * * @param file1 Image 1 to compare * @param file2 Image 2 to compare * @return true if both images are visually the same. */ public final static boolean visuallyCompare(final File file1, final File file2) { logger.debug("Start comparing \"{}\" and \"{}\".", file1.getPath(), file2.getPath()); if(file1 == file2) { return true; } boolean answer = visuallyCompareJava(file1, file2); if(!answer) { logger.info("The files \"{}\" and \"{}\" are not pixel by pixel the same image. Manual comparison required.", file1.getPath(), file2.getPath()); } logger.debug("Finish comparing \"{}\" and \"{}\".", file1.getPath(), file2.getPath()); return answer; } /** * @param file The image to check * @return true if the image contains one or more pixels with * some percentage of transparency (Alpha) */ public final static boolean containsAlphaTransparency(final File file) { logger.debug("Start Alpha pixel check for {}.", file.getPath()); boolean answer = false; for(final int pixel : getPixels(getBufferedImage(file), file)) { //If the alpha is 0 for both that means that the pixels are 100% //transparent and the color does not matter. Return false if //only 1 is 100% transparent. if(((pixel >> 24) & 0xff) != 255) { logger.debug("The image contains Aplha Transparency."); return true; } } logger.debug("The image does not contain Aplha Transparency."); logger.debug("End Alpha pixel check for {}.", file.getPath()); return answer; } } 

如果您的意思完全相同,请比较每个像素。

如果你的意思是比较RGB图像和灰度图像,你需要首先将RGB转换为灰度,为此,你需要知道你以前如何做RGB-> Greyscale,有不同的方法这样做你可以得到不同的结果。

编辑,如果它在RGB-> Greyscale中使用的方法是线性的,你可以通过比较3个像素计算公式中的a,b,c: grey = a*R + b*G + c*B

我尝试的最简单的方法之一是获取两个图像的像素数组,并将它们与Arrays.equals方法进行比较。 代码示例:

 package image_processing; import java.awt.image.BufferedImage; import java.awt.image.DataBufferByte; import java.io.File; import java.io.IOException; import java.util.Arrays; import javax.imageio.ImageIO; public class CheckPixels { public static void main(String args[]) throws IOException { File pic1 = new File("D:\\ani\\img1.png"); File pic2 = new File("D:\\ani\\img2.png"); if (Arrays.equals(returnPixelVal(pic1), returnPixelVal(pic2))) { System.out.println("Match"); } else { System.out.println("No match"); } } public static byte[] returnPixelVal(File in) { BufferedImage img = null; File f = null; byte[] pixels = null; // read image try { f = in; img = ImageIO.read(f); pixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData(); } catch (IOException e) { System.out.println(e); } return pixels; } } 

你可以试试这个

示例 [Broken Link]

他们解释了他们如何比较两张图片……