Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java识别2个相同的图像_Java_Image - Fatal编程技术网

使用Java识别2个相同的图像

使用Java识别2个相同的图像,java,image,Java,Image,我的网络爬虫有一个问题,我试图从一个特定的网站检索图像。问题是,我经常看到的图像在URL中完全相同但不同,即它们的地址 是否有任何Java库或实用程序可以识别两个图像的内容是否完全相同(即像素级) 我的输入将是我可以下载它们的图像的URL 我认为您不需要图像库来完成这项工作—只需获取URL内容并将两个流作为字节数组进行比较即可 当然,除非您对识别类似的图像感兴趣。取决于您希望获得的详细信息: 下载图片 下载时生成一个哈希 创建一个目录,其中目录名是哈希值(如果该目录不存在) 如果目录包含2个或

我的网络爬虫有一个问题,我试图从一个特定的网站检索图像。问题是,我经常看到的图像在URL中完全相同但不同,即它们的地址

是否有任何Java库或实用程序可以识别两个图像的内容是否完全相同(即像素级)


我的输入将是我可以下载它们的图像的URL

我认为您不需要图像库来完成这项工作—只需获取URL内容并将两个流作为字节数组进行比较即可


当然,除非您对识别类似的图像感兴趣。

取决于您希望获得的详细信息:

  • 下载图片
  • 下载时生成一个哈希
  • 创建一个目录,其中目录名是哈希值(如果该目录不存在)
  • 如果目录包含2个或更多文件,则比较文件大小
  • 如果文件大小相同,则逐字节将图像与文件中图像的字节进行比较
  • 如果字节是唯一的,则您有一个新映像
无论您是否想要完成所有这些,您都需要:

  • 下载图片
  • 对图像进行逐字节比较

无需依赖任何特殊的图像库,图像只是字节。

查看MessageDigest类。本质上,您创建了它的一个实例,然后将一系列字节传递给它。如果您知道两个“相同”的图像将是相同的文件/字节流,那么字节可以是直接从URL加载的字节。或者,如果需要,您可以从流中创建一个BuffereImage,然后提取像素值,例如:

  MessageDigest md = MessageDigest.getInstance("MD5");
  ByteBuffer bb = ByteBuffer.allocate(4 * bimg.getWidth());
  for (int y = bimg.getHeight()-1; y >= 0; y--) {
    bb.clear();
    for (int x = bimg.getWidth()-1; x >= 0; x--) {
      bb.putInt(bimg.getRGB(x, y));
    }
    md.update(bb.array());
  }
  byte[] digBytes = md.digest();
无论哪种方式,MessageDigest.digest()最终都会为您提供一个字节数组,它是图像的“签名”。如果有帮助,您可以将其转换为十六进制字符串,例如用于放入哈希映射或数据库表,例如:

StringBuilder sb = new StringBuilder();
for (byte b : digBytes) {
  sb.append(String.format("%02X", b & 0xff));
}
String signature = sb.toString();
如果来自两个URL的内容/图像提供相同的签名,则它们是相同的图像

编辑:我忘了提到,如果对像素值进行哈希运算,可能还希望在哈希中包含图像的尺寸。(与此类似——将两个整数写入一个8字节的ByteBuffer,然后用相应的8字节数组更新MessageDigest。)

另一件事是有人提到的是,MD5不耐碰撞。换句话说,有一种技术可以用相同的MD5哈希值构造多字节序列,而不必使用“暴力”的试错方法(平均来说,在发生冲突之前,您需要尝试大约26.4亿或160亿个文件)。这使得MD5不适合您试图抵御此威胁模型的地方。如果您不担心有人可能故意试图欺骗您的重复标识,而您只是担心“偶然”出现重复哈希的可能性,那么MD5绝对可以。事实上,这不仅很好,实际上有点过头了——正如我所说,平均来说,在大约160亿个文件之后,你会期望出现一个“虚假复制”。或者换句话说,你可能有,比如说,10亿个文件,而发生碰撞的几率非常接近于零

如果您担心概述的威胁模型(即,您认为有人可能故意将处理器时间用于构建文件以欺骗您的系统),那么解决方案是使用更强的哈希。Java支持现成的SHA1(只需将“MD5”替换为“SHA1”)。这将使您获得更长的散列(160位而不是128位),但根据目前的知识,查找冲突是不可行的


对于这个目的,我甚至会考虑使用一个像样的64位哈希函数。这仍然允许对数以千万计的图像进行比较,而误报率几乎为零。

您还可以生成文件的MD5签名并忽略重复条目。但这不会帮助您找到类似的图像。

使用以下方法计算MD5:

MessageDigest m=MessageDigest.getInstance("MD5");
m.update(image.getBytes(),0,image.length());
System.out.println("MD5: "+new BigInteger(1,m.digest()).toString(16));

将它们放在hashmap中。

我以前在Java中做过类似的事情,我发现api包中的PixelGrabber类非常有用(如果不是完全必要的话)

此外,您肯定希望查看,它可以对源图像中的数据执行逐像素颜色转换,并将生成的颜色值缩放到目标图像的精度。文档接着说,这些图像甚至可以是相同的图像,在这种情况下,很容易检测它们是否相同

如果你在检测相似性,你需要使用某种形式的平均方法,正如你在答案中提到的

如果可以的话,还可以查看Horstman的Core Java(第8版)第2卷第7章,因为这里有大量关于图像转换等的示例,但是,再次请确保浏览Java.awt.image包,因为您应该发现您已经为自己准备好了几乎所有的东西:)


祝你好运

已经建议使用散列,识别两个文件是否相同非常容易,但您说的是像素级。 如果您想识别两个图像,即使它们的格式不同(.png/.jpg/.gif/),即使它们被缩放,我建议: (使用图像库,如果图像为中/大,则无16x16图标):

  • 将图像缩放到某个固定大小,这取决于样本
  • 使用RGB-YUV转换将其转换为灰度,然后从中提取Y(非常简单) 3.计算每幅图像的汉明距离,并设置一个阈值,以确定它们是否相同
  • 你将两幅图像的所有灰度像素的差值相加,得到一个数字
    for each imageUrl in myList
        Perform HTTP HEAD imageUrl
        Pull ETag value from request
        If ETag is in my map of known ETags
           move on to next image
        Else
           Download image
           Store ETag in map