PIL图像的简单哈希

时间:2018-04-06 09:25:51

标签: python hash python-imaging-library

背景

我想将PIL图像的信息存储在键值存储中。为此,我对图像进行散列并使用散列作为键。

我尝试了什么

我一直在使用以下代码来计算哈希值:

def hash(img):
   return hashlib.md5(img.tobytes()).hexdigest()

但似乎这不稳定。我还没弄清楚为什么,但是对于不同机器上的相同图像,我会得到不同的哈希值。

问题

是否有一种简单的哈希图像只依赖于图像本身的方式(不是时间戳,系统架构等)?

请注意,我不需要类似的图像来获得类似/相同的哈希值,如image hashing中所示。实际上,我希望不同的图像具有不同的散列,例如改变图像的亮度应改变它的散列。

2 个答案:

答案 0 :(得分:2)

我猜你的目标是在Python中执行图像散列(这与经典散列有很大不同,因为图像的字节表示取决于格式,分辨率等)。

其中一种图像散列技术是平均散列。确保这不是100%准确,但在大多数情况下都可以正常工作。

首先,我们通过减小图像的尺寸和颜色来简化图像,降低图像的复杂性,大大有助于提高其他图像之间的比较精度:

缩小尺寸:

img = img.resize((10, 10), Image.ANTIALIAS)

缩小颜色

img = img.convert("L")

然后,我们找到图像的平均像素值(这显然是平均散列的主要组成部分之一):

pixel_data = list(img.getdata())
avg_pixel = sum(pixel_data)/len(pixel_data)

最后计算哈希值,我们将图像中的每个像素与平均像素值进行比较。如果像素大于或等于平均像素,那么我们得到1,否则它是0.然后我们将这些位转换为基数16表示:

bits = "".join(['1' if (px >= avg_pixel) else '0' for px in pixel_data])
hex_representation = str(hex(int(bits, 2)))[2:][::-1].upper()

如果要将此图像与其他图像进行比较,请执行上述操作,并找出平均哈希图像的十六进制表示之间的相似性。您可以使用简单的hamming distance或更复杂的算法,例如Levenshtein distanceRatcliff/Obershelp pattern recognition(SequenceMatcher),Cosine Similarity等。

答案 1 :(得分:1)

认识到您所说的时间戳, ImageMagick 具有这样的功能。首先,一个例子。

在这里我创建了两个像素相同但时间戳至少相差1秒的图像:

convert -size 600x100 gradient:magenta-cyan 1.png
sleep 2
convert -size 600x100 gradient:magenta-cyan 2.png

enter image description here

如果我在macOS上对它们进行校验和,则表明它们由于嵌入的时间戳而有所不同:

md5 -r [12].png

c7454aa225e3e368abeb5290b1d7a080 1.png
66cb4de0b315505de528fb338779d983 2.png

但是,如果我使用 ImageMagick (其中%#是逐个像素的校验和)对只是像素进行校验,它会知道像素相同,因此得到:

identify -format '%# - %f\n' 1.png 2.png
70680e2827ad671f3732c0e1c2e1d33acb957bc0d9e3a43094783b4049225ea5 - 1.png
70680e2827ad671f3732c0e1c2e1d33acb957bc0d9e3a43094783b4049225ea5 - 2.png

事实上,如果我用相同的图像内容制作了一个TIFF文件,无论是使用Motorola还是Intel字节顺序,还是使用NetPBM PPM文件:

convert -size 600x100 gradient:magenta-cyan -define tiff:endian=msb 3motorola.tif
convert -size 600x100 gradient:magenta-cyan -define tiff:endian=lsb 3intel.tif
convert -size 600x100 gradient:magenta-cyan 3.ppm

ImageMagick 知道它们是相同的,尽管文件格式,CPU体系结构和时间戳不同,

identify -format '%# - %f\n' 1.png 3.ppm 3{motorola,intel}.tif

70680e2827ad671f3732c0e1c2e1d33acb957bc0d9e3a43094783b4049225ea5 - 1.png
70680e2827ad671f3732c0e1c2e1d33acb957bc0d9e3a43094783b4049225ea5 - 3.ppm
70680e2827ad671f3732c0e1c2e1d33acb957bc0d9e3a43094783b4049225ea5 - 3motorola.tif
70680e2827ad671f3732c0e1c2e1d33acb957bc0d9e3a43094783b4049225ea5 - 3intel.tif

因此,为回答您的问题,我建议您使用Python子进程模块使用 ImageMagick ,并使用 ImageMagick