能否检测到重复的图片文件?

13

我有超过10K个产品文件,问题是其中很多图片是重复的。

如果没有图片,会显示一个标准的“无图像”图片。

如何检测该图片是否为标准的“无图像”文件?

更新 该图片有不同的名称,但除此之外完全相同。

人们说可以用哈希算法,那么我应该怎么做呢?

im = cStringIO.StringIO(file.read())
img = im.open(im)
md5.md5(img)

这是否真的是相同的图像(二进制),还是只是具有相同名称的图像? - Felix Kling
3
“duplicate”指什么?是相同的名称吗?是相同的校验和?还是完全相同的字节? - S.Lott
1
我们确实需要更多的信息。除了已经提出的问题,这些是如何存储的?它们被存储为包含图像文件和其他文件的目录吗?它们被存储在数据库中吗?它们以其他方式存储吗?系统是什么样子的?所有“无图像”产品是否使用相同的文件作为它们的图像,还是每个产品都复制了同一张图片的副本? - Chris Thompson
6个回答

15

顺便提一句,对于图像,我发现光栅数据的哈希比文件哈希更有效。

ImageMagick提供了可靠的方法来计算此类哈希值,并且有不同的Python绑定可用。它有助于检测具有不同无损压缩和不同元数据的相同图像。

使用示例:

>>> import PythonMagick
>>> img = PythonMagick.Image("image.png")
>>> img.signature()
'e11cfe58244d7cf98a79bfdc012857a9391249dca3aedfc0fde4528eed7f7ba7'

1
这种方法比使用文件哈希来比较PNG和BMP要好得多,如果两个相同的图像具有不同的EXIF数据或编码技术,则应被视为相似。 - Vortico
谢谢你,丹尼尔。这对我非常有用,因为我的一些图像已经被标记了,而另一些则没有。这让我可以找到重复的图像,而不管它们的元数据如何。 - Phistrom
1
提供有关此功能的适当ImageMagick文档链接将非常有帮助。例如,对于不一定知道自己在寻找什么的人,ImageMagick光栅数据哈希的谷歌搜索可能或可能不会为他们提供有用的信息。 - jptros
@jptros 我已经添加了示例代码,但请记住PythonMagick不再维护。还有一些其他IM的Python绑定,它们得到更好的维护,但我没有它们的示例代码。 - Daniel Kluev
1
安装ImageMagick和Python 3.x遇到了问题,它仍然只能用于2.5吗? - usario121233

5

我之前写了一个脚本。首先,它会扫描所有文件,并在字典中记录它们的大小。最终得到:

images[some_size] = ['x/a.jpg', 'b/f.jpg', 'n/q.jpg']
images[some_other_size] = ['q/b.jpg']

然后,对于字典中有超过1个元素的每个键(图像大小),我会读取一定量的文件并进行哈希处理。类似于:

possible_dupes = [size for size in images if len(images[size]) > 1]
for size in possible_dupes:
    hashes = defaultdict(list)
    for fname in images[size]:
        m = md5.new()
        hashes[ m.update( file(fname,'rb').read(10000) ).digest() ] = fname
    for k in hashes:
       if len(hashes[k]) <= 1: continue
       for fname in hashes[k][1:]:
           os.remove(fname)

这些都是我脑海中的想法,还没有测试过代码,但你可以理解这个思路。

所有没有运行长度压缩的微软位图文件,只要具有相同的像素尺寸,它们的大小就是一样的。对于内部名称长度相同的XPM文件,以及没有压缩的PNG文件和Netpbm图像,它们的大小也是一样的……这个列表还可以继续下去。但我同意; 检查大小将有助于避免无意义的碰撞。 - amphetamachine

5

假设您所说的是相同的图像数据。

计算“无图像”图像的哈希值,并将其与其他图像的哈希值进行比较。如果哈希值相同,则为同一文件。


1
这也是检测其他重复内容的好方法。开始计算图像的哈希值,然后对于每个图像,确保它不存在。如果存在,则表示有重复。如果不存在,则将其添加到数据库并继续进行。 - Chris Thompson
实际上,如果Blankman正在寻找特定文件的副本(而不是在集合中查找所有副本集),哈希是适得其反的 - 请参阅我的答案。 - Gilles 'SO- stop being evil'
@Gilles:有意思。是的,我知道你得完全阅读所有文件,但我从未说过这是最好或最快的方法;) 给你一个+1。 - Felix Kling
那么,我如何对图像进行哈希? - Blankman
@Blankman:看一下 hashlib 模块:http://docs.python.org/library/hashlib.html - Felix Kling

3

我在Fedora上安装PythonMagick时遇到了问题,但是另一个ImageMagick绑定库Wand可以正常工作。

from wand.image import Image

img = Image(filename="image.jpg")
print(img.signature)

请确保先安装好所有内容:

yum install python3-wand ImageMagick

2
如果您正在寻找特定图像的精确副本:将此图像加载到内存中,然后循环遍历您的图像集合;跳过任何大小不相同的文件;比较具有相同大小的文件的内容,在第一个差异处停止。
在这种情况下计算哈希实际上是适得其反的,因为您必须完全读取每个文件(而不能在第一个差异处停止),并对其执行消耗 CPU 的任务。
另一方面,如果有几组重复项,则计算每个文件的哈希更好。
如果您还在寻找视觉近似重复项,则 findimagedupes 可以帮助您。

他可以计算哈希值,同时保存图像的大小并跳过大小不同的图像。测试计算哈希值和逐字节比较两个图像哪个更耗时是明智的选择。 - Jaka
2
计算所有这些哈希值可能看起来是一种浪费,但将N个文件相互比较的时间复杂度为O(N*N)。对于足够数量的文件,使用在set()dict()中计算哈希值并进行比较的O(N)算法会更加高效。请注意,您不需要对整个文件进行哈希 - 前面的几KB大小的数据通常已经足够作为第一次检查。 - John La Rooy

0

对它们进行散列。冲突是重复的(至少,数学上不可能它们不是同一个文件)。


我猜你是指“不太可能”而不是“不可能”。 - David Z
1
你应该 始终 考虑哈希碰撞的可能性。将碰撞的 代价 乘以 碰撞概率 得到 预期代价。通常,预期代价很小,因为即使代价是一百万美元,碰撞的概率也非常小。但是,婴儿照片等是无法替代的,所以有时需要额外努力 ;) - John La Rooy
@gnibbler 这就是为什么我们要保留备份的原因。 - amphetamachine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接