当前位置: 首页 > 面试题库 >

使用Java以编程方式确定2张图像是否看起来相同

卫学真
2023-03-14
问题内容

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

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


问题答案:

我查看了所有解决方案,并确定它们可以告诉您某些类型的图像在图像上或工作上有何不同,但并非全部。这是我想出的解决方案…

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


 类似资料:
  • 问题内容: 在C语言中,如何以编程方式找出Linux / Ubuntu上是否已在运行某个进程,以避免该进程两次启动?我正在寻找类似于pidof的东西。 问题答案: 您可以进入这些条目并在文件中检查过程,也可以在链接上执行操作(以下使用第一种方法)。

  • 问题内容: 有没有一种方法可以在运行时以编程方式告知Google App Engine应用程序在本地运行还是在托管运行?我正在寻找一种在本地开发环境中运行时调用一些自定义存根代码,并在运行托管时进行不同调用的方法。 问题答案: 您可以在AppEngine 1.3中使用。

  • 考虑到JAXB注释的对象,是否有办法确定类/字段/方法在封送过程中是否会导致xsi: type? 是XmlElement注释, 我唯一需要担心的情况? 我正在编写一个Lua解组器,在这里我们删除了很多常见的xml类型信息,我正在尝试找出如何将传入的Lua与JAXB匹配。 谢谢 --更新-- 下面是一个简单的示例,说明了问题: 当我收到一个动物对象时,我可以查询动物的注释来检测它应该是狗或猫而不是动

  • 问题内容: 在运行时是否可以以编程方式检查持有给定对象锁的线程的名称? 问题答案: 您只能说出当前线程是否持有普通锁()。没有本机代码,您将无法获得对具有锁的线程的引用。 但是,如果您要对线程进行任何复杂的处理,则可能需要熟悉java.util.concurrent包。该确实让你得到它的所有者(但其受保护的方法,所以你必须要扩展这个)。根据您的应用程序的不同,很可能是通过使用并发包,您会发现根本不

  • 问题内容: 说我有两个JavaBeans 和。 如果创建一个Person对象的列表,我想编组成这样的东西: 可以使用这里描述的技术: 使用JAXB解组/编组List 通过使用和注释JaxbList,可以将其编组为上述XML。 但是,能够重用相同的类来封送对象列表也很好。实际上,我将有许多其他类型的bean。我可以这样: 但是,理想情况下,最好用类名的复数形式替换“列表”,用类名替换“ item”。

  • 给定一个卷,如何确定它是否加密?我发现了像DADiskCopyDescription()和NSURL的getResourceValue:forKey:error这样的东西:它们提供了丰富的信息,但并没有提供卷是否加密。 即使没有公共API,从操作系统附带的命令行工具中抓取输出也是可以接受的。我发现最接近的是“diskutil info /dev/disk0”,但同样没有加密信息。令人讨厌的是,当您