以编程方式确定使用Java是否两个图像看起来相同 [英] Programmatically determine if 2 images look the same using Java

查看:104
本文介绍了以编程方式确定使用Java是否两个图像看起来相同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In JAVA I am trying to programmatically tell if 2 images are equal when displayed on the screen (AKA same image even though they have different color spaces. Is there a piece of code that will return a boolean when presented 2 images?

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

One of the examples I have is a RGB PNG that I converted to a greyscale PNG. Both images look the same and I would like to prove this programmatically. Another example is two images where they display the exact same color pixels to the screen but the color used for 100% transparent pixels has changed.

推荐答案

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

I looked at all of the solutions and determined that they could tell you how different the images were or worked for some types of images, but not all of them. Here is the solution I came up with...

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 <code>File</code> to use.
     * @return The resulting <code>BufferedImage</code>
     */
    @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 <code>true</code> if they are equal, otherwise 
     *         <code>false</code>.
     */
    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 <code>true</code> 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 <code>true</code> 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;
    }
}

这篇关于以编程方式确定使用Java是否两个图像看起来相同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆