【问题标题】:Image comparaison performance java图像比较性能java
【发布时间】:2018-07-27 06:27:02
【问题描述】:

我在下面有这段代码,但它根本没有效率,它非常非常慢,而且我需要比较更多的图片需要更长的时间。

比如我有500张图片,每个过程持续2分钟,500 x 2 min =1000 min!

特殊性是只要有对比的图片,就将其移动到另一个文件夹。然后检索其余文件以比较 i++

有什么想法吗?

public static void main(String[] args) throws IOException {

    String PicturesFolderPath=null;
    String removedFolderPath=null;
    String pictureExtension=null;
    if(args.length>0) {
         PicturesFolderPath=args[0];
         removedFolderPath=args[1];
         pictureExtension=args[2];
    }


    if(StringUtils.isBlank(pictureExtension)) {
        pictureExtension="jpg";
    }

    if(StringUtils.isBlank(removedFolderPath)) {
        removedFolderPath=Paths.get(".").toAbsolutePath().normalize().toString()+"/removed";
    }

    if(StringUtils.isBlank(PicturesFolderPath)) {
        PicturesFolderPath=Paths.get(".").toAbsolutePath().normalize().toString();
    }

    System.out.println("path to find pictures folder "+PicturesFolderPath);
    System.out.println("path to find removed pictures folder "+removedFolderPath);

    Collection<File> fileList = FileUtils.listFiles(new File(PicturesFolderPath), new String[] { pictureExtension }, false);

    System.out.println("there is "+fileList.size()+" files founded with extention "+pictureExtension);

    Iterator<File> fileIterator=fileList.iterator();
    //Iterator<File> loopFileIterator=fileList.iterator();

    File dest=new File(removedFolderPath);

    while(fileIterator.hasNext()) {
        File file=fileIterator.next();

        System.out.println("process image :"+file.getName());

        //each new iteration we retrieve the files staying
        Collection<File> list = FileUtils.listFiles(new File(PicturesFolderPath), new String[] { pictureExtension }, false);
        for(File f:list) {
            if(compareImage(file,f) && !file.getName().equals(f.getName()) ) {
                String filename=file.getName();
                System.out.println("file :"+file.getName() +" equal to "+f.getName()+" and will be moved on removed folder");
                File existFile=new File(removedFolderPath+"/"+file.getName());
                    if(existFile.exists()) {
                        existFile.delete();
                    }
                    FileUtils.moveFileToDirectory(file, dest, false);
                    fileIterator.remove();
                    System.out.println("file :"+filename+" removed");
                    break;

                }           
        }

    }

}


 // 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) { 
        e.printStackTrace();
        return  false;
    }
}

【问题讨论】:

  • 在这里查看替代方法:stackoverflow.com/questions/11006394/…
  • md5直接比较怎么样?
  • 我认为仅比较 md5 是不够的,文件名称不同,我认为 md5 使用文件名不?它和 ImageIO 一样高效吗?谢谢大家
  • 并在每个文件上循环,然后每个像素都可能非常长我会尝试但比我的代码长
  • 注意MD5不关心文件名,只关心内容。

标签: java image performance image-processing compare


【解决方案1】:

已经提到的answer 应该对您有所帮助,因为考虑到图片的widthheight 应该会很快排除更多候选对。

但是,您仍然有一个大问题:对于每个新文件,您都会读取所有旧文件。比较次数呈二次方增长,每一步都执行ImageIO.read,它肯定很慢。

您需要一些指纹,可以非常快速地进行比较。您不能对整个文件内容使用指纹识别,因为它受到元数据的侵扰,但您可以单独对图像数据进行指纹识别。

只需遍历文件的图像数据(就像你做的那样),然后计算它的 MD5 哈希值。将其存储为例如String 中的HashSet,您将获得非常快速的查找。

一些未经测试的代码

对于您要比较的每个图像文件,您计算(使用Guava's hashing

HashCode imageFingerprint(File file) {
    Hasher hasher = Hashing.md5().newHasher();
    BufferedImage image = ImageIO.read(file);
    DataBuffer buffer = image.getData().getDataBuffer();
    int size = buffer.getSize();
    for(int i=0; i<size; i++) {
        hasher.putInt(buffer.getElem(i));
    }
    return hasher.hash();
}

计算仅适用于图像数据,就像问题中的compareImage,因此元数据被忽略。

您无需在目录中搜索重复项,而是计算其所有文件的指纹并将它们存储在HashSet&lt;HashCode&gt; 中。对于一个新文件,您计算它的指纹并在集合中查找它。

【讨论】:

  • 谢谢你之前说过,md5是不能接受的,因为图片来自互联网,同一张图片可以有不同的元数据,md5是基于文件元数据的。提到的答案与我的代码相同,但没有缓冲图像,也许它可以很快....也许我可以从迭代器中删除检查的文件,实际上我们走得更远,我们必须检查的文件更少(文件已经检查)谢谢你的时间!
  • @cyril md5 不基于任何元数据。 md5 计算 您输入的内容的散列。我写过,你应该用你用于比较的相同数据来提供 md5。不包括元数据。
  • 你有例子吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-10-22
  • 2012-12-01
  • 1970-01-01
  • 2012-01-23
  • 2023-03-12
  • 1970-01-01
  • 2012-01-27
相关资源
最近更新 更多