我正在寻找一个用于编目图像的 ID 系统。我不能使用 md5() ,因为如果我更改图像的 EXIF 标签,它会改变。
我目前正在使用 imagemagick 计算的 SHA1 校验和。它工作得很好,但在较大的图像上确实非常慢(对于 21 兆像素的 JPG,四核至强大约需要 15 秒)。
是否有任何其他“视觉”方法可以更快地唯一识别图像?
我正在寻找一个用于编目图像的 ID 系统。我不能使用 md5() ,因为如果我更改图像的 EXIF 标签,它会改变。
我目前正在使用 imagemagick 计算的 SHA1 校验和。它工作得很好,但在较大的图像上确实非常慢(对于 21 兆像素的 JPG,四核至强大约需要 15 秒)。
是否有任何其他“视觉”方法可以更快地唯一识别图像?
您可以尝试在实际位图数据而不是 JPEG 文件上运行 MD5。我在我的机器(也是四核 Xeon)上进行了测试,在 23 兆像素的图像上运行了大约 900 毫秒。
uint32_t width = MagickGetImageWidth(imageWand);
uint32_t height = MagickGetImageHeight(imageWand);
uint8_t *imageData = malloc(width * height * 3);
MagickExportImagePixels(imageWand,
0, 0, width, height, "RGB", CharPixel, imageData);
unsigned char *imageDigest = MD5(imageData, width * height * 3, NULL);
free(imageData);
“视觉校验和”是什么意思?您提到的算法(md5/sha/crc)以基于字节的方式工作,但不考虑图像的视觉信息。如果您将其中一张图像转换为 JPEG,这两个文件将显示相同的图像,但具有完全不同的 md5/sha/crc 校验和。
如果您唯一担心的是 exif 编辑,您可以制作图像的临时副本,使用 exiv2 库从中删除所有元数据,然后运行校验和算法。我想这比手动缩小图像要快得多。您还可以通过仅使用源文件的前 n 千字节作为校验和来加快计算速度。
如果您的所有图像文件都直接来自相机,那么您的情况会更好:您可以使用 exiv2(通常只有几千字节)提取预先生成的 exif 缩略图并计算其校验和。
关于缩小方法:还要注意 ImageMagick 将来可能会更改其缩放算法,这会使您的校验和无效(缩小版本的字节结构会随之改变)。
正如 Todd Yandell 所指出的,MD5 可能已经足够快了。如果没有,您可以通过使用 32 位或 64 位CRC作为校验和来获得更快的结果。主要区别在于任何人都可以使用相同的 CRC 来制作新图像。很容易被欺骗。有人很难欺骗 MD5 校验和。一个小的区别是 CRC 的位数少得多,但除非你有大量的图像,否则冲突仍然不太可能。
exiftool
声称能够从 JPEG 文件中提取二进制图像,这样您就可以在不解压缩的情况下计算校验和,但我无法从手册页中弄清楚如何做到这一点。
我在笔记本电脑 Intel Core 2 Duo L7100 CPU 上做了一些实验,8MP JPEG 大约需要 1 秒才能压缩成 PPM 格式,然后再花 1 秒来完成校验和。md5sum
使用,sum
和校验和时间没有显着差异sha1sum
。因此,您最好的选择可能是找到一种无需解压缩即可提取二进制数据的方法。
我还注意到,即使它使用更少的像素,您的校验和也会几乎一样好。比较这两个:
djpeg -scale 1/8 big.jpg | /usr/bin/sha1sum # 0.70s
djpeg big.jpg | /usr/bin/sha1sum # 2.15s
您应该考虑到有人可能会裁剪图像或修改调色板、颜色深度或其他任何内容,那么即使在视觉上原始图像和修改后的图像看起来仍然非常相似,平面校验和也会有所不同。也许有一种有效的算法可以裁剪或重新着色,例如 Google 图片用于搜索相似图片。