我在下面有此代码,但它根本没有效率,它非常非常慢,并且我需要比较更多图片才能花费更长的时间。
例如,我有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;
}
}
答案 0 :(得分:0)
已经提到的answer应该会对您有所帮助,因为考虑图片的width
和height
应该很快排除更多的候选对。
但是,您仍然有一个大问题:对于每个新文件,您都读取了所有旧文件。比较的次数呈二次方增长,并且每一步都进行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<HashCode>
中。对于新文件,您可以计算其指纹并在集中查找它。