图像比较性能Java

时间:2018-07-24 09:55:50

标签: java image performance image-processing compare

我在下面有此代码,但它根本没有效率,它非常非常慢,并且我需要比较更多图片才能花费更长的时间。

例如,我有500张照片,每个过程持续2分钟,即500 x 2分钟= 1000分钟!

特异性是一旦有与所比较的图片相同,将其移至另一个文件夹。然后检索其余文件以比较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;
    }
}

1 个答案:

答案 0 :(得分:0)

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

但是,您仍然有一个大问题:对于每个新文件,您都读取了所有旧文件。比较的次数呈二次方增长,并且每一步都进行ImageIO.read,就必须很慢。

您需要一些指纹,可以快速比较它们。您不能对整个文件内容使用指纹作为元数据所困扰的文件,而是可以单独对图像数据进行指纹。

只需遍历文件的图像数据(就像您一样),然后计算该文件的MD5哈希值即可。例如,将其存储为StringHashSet中,您将可以快速查找。

一些未经测试的代码

对于要比较的每个图像文件,您都进行计算(使用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<HashCode>中。对于新文件,您可以计算其指纹并在集中查找它。