Pet*_*ter 5 python hash python-imaging-library
我想将PIL图像的信息存储在键值存储中。为此,我对图像进行哈希处理并将哈希值用作键。
我一直在使用以下代码来计算哈希值:
def hash(img):
return hashlib.md5(img.tobytes()).hexdigest()
Run Code Online (Sandbox Code Playgroud)
但这似乎不稳定。我还没有弄清楚为什么,但是对于不同机器上的同一图像,我得到了不同的哈希值。
有没有一种简单的散列图像的方法,该方法仅取决于图像本身(而不取决于时间戳,系统体系结构等)?
请注意,我不需要类似的图像来获得类似/相同的哈希,就像在图像哈希中一样。实际上,我希望不同的图像具有不同的哈希,例如,更改图像的亮度应更改其哈希。
认识到你所说的时间戳,ImageMagick正是有这样的功能。首先,举一个例子。
在这里,我创建了两个像素相同但时间戳至少相差 1 秒的图像:
convert -size 600x100 gradient:magenta-cyan 1.png
sleep 2
convert -size 600x100 gradient:magenta-cyan 2.png
Run Code Online (Sandbox Code Playgroud)
如果我在 macOS 上对它们进行校验,它会告诉我它们由于嵌入的时间戳而不同:
md5 -r [12].png
c7454aa225e3e368abeb5290b1d7a080 1.png
66cb4de0b315505de528fb338779d983 2.png
Run Code Online (Sandbox Code Playgroud)
但是,如果我仅使用ImageMagick对像素进行校验和(其中是逐像素校验和),它就知道像素是相同的,我得到:%#
identify -format '%# - %f\n' 1.png 2.png
70680e2827ad671f3732c0e1c2e1d33acb957bc0d9e3a43094783b4049225ea5 - 1.png
70680e2827ad671f3732c0e1c2e1d33acb957bc0d9e3a43094783b4049225ea5 - 2.png
Run Code Online (Sandbox Code Playgroud)
事实上,如果我创建一个TIFF具有相同图像内容的文件,无论是摩托罗拉还是英特尔字节顺序,还是 NetPBMPPM文件:
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
因此,在回答您的问题时,我建议您使用Python subprocess 模块使用ImageMagick并使用ImageMagick。
我猜你的目标是在 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)
Run Code Online (Sandbox Code Playgroud)
最后计算哈希,我们将图像中的每个像素与平均像素值进行比较。如果像素大于或等于平均像素,那么我们得到 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()
Run Code Online (Sandbox Code Playgroud)
如果您想将此图像与其他图像进行比较,请执行上述操作,并找到平均散列图像的十六进制表示之间的相似性。您可以使用像汉明距离这样简单的东西,也可以使用更复杂的算法,例如Levenshtein distance、Ratcliff/Obershelp 模式识别(SequenceMatcher)、余弦相似度等。
| 归档时间: |
|
| 查看次数: |
1839 次 |
| 最近记录: |