Java快速图像比较

Java快速图像比较,java,Java,您好,我最近格式化了我的手机,并将照片上传到我的电脑,当我想将照片添加回手机时,我发现我有一些图像的多个副本。我想把我所有的照片合并成一个文件夹,然后上传到我的手机上,所以我写了一个java代码 public class Main { public static int imgCtr = 1; public static File dest = new File("D:\\finalfinal"); public static void main(String[] args) throws

您好,我最近格式化了我的手机,并将照片上传到我的电脑,当我想将照片添加回手机时,我发现我有一些图像的多个副本。我想把我所有的照片合并成一个文件夹,然后上传到我的手机上,所以我写了一个java代码

public class Main {

public static int imgCtr = 1;
public static File dest = new File("D:\\finalfinal");

public static void main(String[] args) throws Exception {
    getContent("D:\\restoreFinal");
    getContent("D:\\restore1");
    getContent("D:\\restore2");
}

public static String getExtension(String fileName) {
    String extension = "";

    int i = fileName.lastIndexOf('.');
    if (i > 0) {
        extension = fileName.substring(i + 1);
    }
    return extension;
}

public static boolean isImage(String extension) {
    if (extension.equalsIgnoreCase("jpg") || extension.equalsIgnoreCase("jpeg")
            || extension.equalsIgnoreCase("png"))
        return true;
    return false;
}

public static boolean compareImages(File a, File b) throws Exception {
    FileInputStream fisA = new FileInputStream(a);
    FileInputStream fisB = new FileInputStream(b);
    byte contentA[] = new byte[(int) a.length()];
    byte contentB[] = new byte[(int) b.length()];
    fisA.read(contentA);
    fisB.read(contentB);
    String strA = new String(contentA);
    String strB = new String(contentB);
    fisA.close();
    fisB.close();
    return strA.equals(strB);
}

public static void getContent(String path) throws Exception {
    File source = new File(path);
    ArrayList<File> content = new ArrayList<File>(Arrays.asList(source.listFiles()));
    while (!content.isEmpty()) {
        File f = content.get(0);
        if (isImage(getExtension(f.getName()))) {
            if (dest.listFiles().length == 0) {
                Path p = Paths.get(dest + "\\i" + imgCtr + "." + getExtension(f.getName()));
                imgCtr++;
                Files.move(f.toPath(), p);
                System.out.println(imgCtr);
            } else {
                File[] alreadyThere = dest.listFiles();
                boolean match = false;
                for (File cmp : alreadyThere) {
                    if (compareImages(f, cmp)) {
                        match = true;
                        break;
                    }
                }
                if (!match) {
                    Path p = Paths.get(dest + "\\i" + imgCtr + "." + getExtension(f.getName()));
                    imgCtr++;
                    Files.move(f.toPath(), p);
                    System.out.println(imgCtr);
                }
            }
        }
        content.remove(0);
    }
}
公共类主{
公共静态int imgCtr=1;
公共静态文件dest=新文件(“D:\\finalfinal”);
公共静态void main(字符串[]args)引发异常{
getContent(“D:\\restoreFinal”);
getContent(“D:\\restore1”);
getContent(“D:\\restore2”);
}
公共静态字符串getExtension(字符串文件名){
字符串扩展名=”;
int i=fileName.lastIndexOf('.');
如果(i>0){
扩展名=fileName.substring(i+1);
}
返回扩展;
}
公共静态布尔isImage(字符串扩展名){
if(extension.equalsIgnoreCase(“jpg”)| | extension.equalsIgnoreCase(“jpeg”)
||扩展名.equalsIgnoreCase(“png”))
返回true;
返回false;
}
公共静态布尔比较图像(文件a、文件b)引发异常{
FileInputStream fisA=新的FileInputStream(a);
FileInputStream fisB=新的FileInputStream(b);
字节contentA[]=新字节[(int)a.length()];
字节contentB[]=新字节[(int)b.length()];
fisA.read(内容a);
财政部阅读(内容b);
String strA=新字符串(contentA);
字符串strB=新字符串(contentB);
fisA.close();
fisB.close();
返回段等于(strB);
}
公共静态void getContent(字符串路径)引发异常{
文件源=新文件(路径);
ArrayList内容=新的ArrayList(Arrays.asList(source.listFiles());
而(!content.isEmpty()){
文件f=content.get(0);
if(isImage(getExtension(f.getName())){
if(dest.listFiles().length==0){
Path p=Path.get(dest+“\\i”+imgCtr+”+getExtension(f.getName());
imgCtr++;
Files.move(f.toPath(),p);
系统输出打印LN(imgCtr);
}否则{
文件[]alreadyThere=dest.listFiles();
布尔匹配=假;
用于(文件cmp:alreadyThere){
if(比较图像(f,cmp)){
匹配=真;
打破
}
}
如果(!匹配){
Path p=Path.get(dest+“\\i”+imgCtr+”+getExtension(f.getName());
imgCtr++;
move(f.toPath(),p);
系统输出打印LN(imgCtr);
}
}
}
内容。删除(0);
}
}
}

我编写了图像比较和字符串比较,因为像素比较花费了很长时间(大约有2k张照片)。但问题是,不知何故,它将一张照片复制了多次,我看不出有任何差别。我搜索了源文件夹,但它任意复制照片,即使没有副本的照片在目标文件夹中也有副本。我怀疑这是关于比较法的,但找不到我的错误


因此,你能帮我找出我的错误,或者建议一种快速、更可靠的方法来比较图像吗?

如果图像没有重新保存或没有通过JPEG等有损文件格式,比较像素是可以的。如果他们没有,那么就从a开始,只有当他们的校验和不能进行更广泛的像素比较时,尽管有损算法需要a。

@MeetTitan你建议比较像素块吗。我相信这仍然需要很长的时间,因为我有类似的照片,或者这是一种比较的方法,比如说,用一种没有n^2复杂性的快速方法来比较top 250x250 px。你可能只想从文件大小和文件校验和比较开始,然后再进行更密集的处理器比较?@AndreM这确实是个好主意。谢谢,但是我如何实现照片的校验和呢。我应该采取一些随机像素或散列字符串,如果我散列字符串,我应该担心与不同图片冲突的散列忽略内容,而改为执行文件。如果校验和和和文件大小相同,那么你应该是好的。如果是jpeg,那又有什么关系呢?因为大多数都是jpeg,很少是pngIf,图像没有被修改过,并且是相同的,那么就没什么关系了。但是,如果将同一图像作为JPEG保存两次,则无法保证像素数据完全相同。记住JPEG是有损的。如果它们来自你的手机,而你只是复制了两次,那么它们就会是一样的。我明白了,谢谢你的帮助,但有一件事我没有想到。通过校验和比较,你建议我创建一个散列并检查它们,对吗?如果是这样,算法将是:1-比较大小2-如果匹配比较校验和(所以在这里,如果它不匹配,这意味着图像是不同的),但问题是,我甚至没有麻烦校验和,失去了一些速度,但得到了图像的全部内容。尽管如此,我还是得到了一些复制品。我认为校验和不会阻止这一点看到答案中的第一个链接,在这里再次共享:抱歉,编辑了之前的评论,在没有写下我所有的问题的情况下添加了它。您是否建议如果校验和匹配(这意味着它们匹配)比较像素以查看任何差异?