如何使用Java比较图像相似性

18

最近,我有机会参与一个项目,其中涉及图像处理技术,并且我的任务是在给定一张新图片时从图像库中找到匹配的图片。我开始了这个项目,通过Google搜索“如何使用Java比较图像”,我得到了一些有关查找两个图像相似性的好文章。几乎所有这些文章都基于四个基本步骤,它们是:

1.Locating the Region of Interest (Where the Objects appear in the given image),
2.Re-sizing the ROIs in to a common size,
3.Substracting ROIs,
4.Calculating the Black and White Ratio of the resultant image after subtraction.
尽管这个算法听起来可以用来比较图像,但在我的项目中使用JAI实现后,它需要相当长的时间。因此,我必须找到一个替代方法。
有什么建议吗?

你有没有考虑使用OpenCV?https://dev59.com/THI-5IYBdhLWcg3wCz3y - Matt Ball
4个回答

12
    **// This API will compare two image file //
// return true if both image files are equal else return false//**
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<sizeA; i++) { 
                if(dbA.getElem(i) != dbB.getElem(i)) {
                    return false;
                }
            }
            return true;
        }
        else {
            return false;
        }
    } 
    catch (Exception e) { 
        System.out.println("Failed to compare image files ...");
        return  false;
    }
}

3
这将比较两个图像是否相同,我要求找到两个图像之间的相似度。 - sum2000
只是想确认一下,如果两个不同的图像尺寸相同,会返回什么? - ChanGan
嗨,Sandip,如何在文件A和文件B的位置传递两个图像?你能否稍微详细地解释一下? - ChanGan

8

根据图像之间的差异程度,你可以使用以下伪代码来实现。它非常原始,但应该非常高效。你可以通过选择随机或有规律的像素来加速处理。

for x = 0 to image.size:
    for y = 0 to image.size:
        diff += abs(image1.get(x,y).red - image2.get(x,y).red)
        diff += abs(image1.get(x,y).blue - image2.get(x,y).blue)
        diff += abs(image1.get(x,y).green - image2.get(x,y).green)
    end
end

return ((float)(diff)) / ( x * y * 3)

这真的提供足够的精度吗? - sum2000
3
我认为你要找的不是精度,而是准确性。例如,如果您将图像向下和向左偏移3个像素,这将表明这些图像几乎完全不同。但是您必须问自己,这样做是否合适? - corsiKa
无论它的工作效果如何(这取决于您是对每个像素还是一组像素进行处理),它在处理黑白图像时同样有效。 - corsiKa

6

这个API将会比较两个图片文件,并返回相似度的百分比。

public float compareImage(File fileA, File fileB) {

    float percentage = 0;
    try {
        // take buffer data from both 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();
        int count = 0;
        // compare data-buffer objects //
        if (sizeA == sizeB) {

            for (int i = 0; i < sizeA; i++) {

                if (dbA.getElem(i) == dbB.getElem(i)) {
                    count = count + 1;
                }

            }
            percentage = (count * 100) / sizeA;
        } else {
            System.out.println("Both the images are not of same size");
        }

    } catch (Exception e) {
        System.out.println("Failed to compare image files ...");
    }
    return percentage;
}

请在代码的第一行顶部找到带参数的方法名称,在那里我们可以传递两个带有文件路径的图像(例如:C://Documents//image1.jpg)。 - Sireesha K
7
您应该提到这是基于Sandip Ganguli所回答的代码。 - Brian Risk
Android Studio 不支持 BufferedImage。 - apurv thakkar

-1
    BufferedImage img1 = ImageIO.read(file);
    BufferedImage img2 = ImageIO.read(file2);

    // Comprueba si cada pixel es igual
    for (int x = 0; x < img1.getWidth(); x++) {
        for (int y = 0; y < img1.getHeight(); y++) {
            Assert.assertEquals(img1.getRGB(x, y), img2.getRGB(x, y));
        }
    }

这甚至比之前的两个计算每个像素相等或不同的答案更糟糕,因为你只是把一个assertEquals扔进去了。这个答案没有存在的理由。 - Christoph Rackwitz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接