仅计算图像的核心图像数据(不包括元数据)的散列

时间:2012-04-09 14:53:33

标签: python exif

我正在编写一个脚本来计算不包括EXIF标签的图像的MD5总和。

为了准确地做到这一点,我需要知道EXIF标记在文件中的位置(开头,中间,结尾),以便我可以将其排除。

如何确定标签在文件中的位置?

我正在扫描的图像格式为TIFF,JPG,PNG,BMP,DNG,CR2,NEF,以及一些视频MOV,AVI和MPG。

4 个答案:

答案 0 :(得分:14)

更容易使用Python Imaging Library提取图片数据(例如iPython中):

In [1]: import Image

In [2]: import hashlib

In [3]: im = Image.open('foo.jpg')

In [4]: hashlib.md5(im.tostring()).hexdigest()
Out[4]: '171e2774b2549bbe0e18ed6dcafd04d5'

这适用于PIL可以处理的任何类型的图像。 tostring方法返回包含像素数据的字符串。

BTW,MD5哈希现在看起来很弱。最好使用SHA512:

In [6]: hashlib.sha512(im.tostring()).hexdigest()
Out[6]: '6361f4a2722f221b277f81af508c9c1d0385d293a12958e2c56a57edf03da16f4e5b715582feef3db31200db67146a4b52ec3a8c445decfc2759975a98969c34'

在我的机器上,计算2500x1600 JPEG的MD5校验和大约需要0.07秒。使用SHA512,需要0.10秒。

对于电影,你可以用它们从中提取帧。 ffmpeg,然后如上所示处理它们。

答案 1 :(得分:8)

一种简单的方法是对核心图像数据进行散列。对于PNG,您可以通过仅计算“关键块”(即以大写字母开头的那些)来完成此操作。 JPEG具有类似但更简单的文件结构。

ImageMagick中的可视化哈希在对图像进行哈希处理时对其进行解压缩。在您的情况下,您可以立即散列压缩的图像数据,因此(如果正确实现)它应该与散列原始文件一样快。

这是一个小Python脚本,说明了这个想法。它可能适用于您,也可能不适合您,但它至少应该表明我的意思:)

import struct
import os
import hashlib

def png(fh):
    hash = hashlib.md5()
    assert fh.read(8)[1:4] == "PNG"
    while True:
        try:
            length, = struct.unpack(">i",fh.read(4))
        except struct.error:
            break
        if fh.read(4) == "IDAT":
            hash.update(fh.read(length))
            fh.read(4) # CRC
        else:
            fh.seek(length+4,os.SEEK_CUR)
    print "Hash: %r" % hash.digest()

def jpeg(fh):
    hash = hashlib.md5()
    assert fh.read(2) == "\xff\xd8"
    while True:
        marker,length = struct.unpack(">2H", fh.read(4))
        assert marker & 0xff00 == 0xff00
        if marker == 0xFFDA: # Start of stream
            hash.update(fh.read())
            break
        else:
            fh.seek(length-2, os.SEEK_CUR)
    print "Hash: %r" % hash.digest()


if __name__ == '__main__':
    png(file("sample.png"))
    jpeg(file("sample.jpg"))

答案 2 :(得分:1)

我会使用元数据剥离器来预处理散列:

从ImageMagick包中你有......

mogrify -strip blah.jpg

如果你这样做

identify -list format 

它显然适用于所有引用的格式。

答案 3 :(得分:0)

您可以使用属于stream套件的ImageMagick

$ stream -map rgb -storage-type short image.tif - | sha256sum
d39463df1060efd4b5a755b09231dcbc3060e9b10c5ba5760c7dbcd441ddcd64  -

$ sha256sum <(stream -map rgb -storage-type short image.tif -)
d39463df1060efd4b5a755b09231dcbc3060e9b10c5ba5760c7dbcd441ddcd64  /dev/fd/63

此示例用于TIFF文件,该文件是RGB,每个样本16位(即每像素48位)。我使用maprgbshort storage-type(如果RGB值是8位,可以在这里使用char

此方法报告详细的Imagemagick signature命令报告的相同identify哈希:

$ identify -verbose image.tif | grep signature
signature: d39463df1060efd4b5a755b09231dcbc3060e9b10c5ba5760c7dbcd441ddcd64

(对于ImageMagick v6.x; identify在版本7上报告的哈希值different与使用stream获得的哈希值相同,但后者可以通过任何能够提取的工具进行复制原始位图数据 - 例如某些图像类型的dcraw。)