通过指纹比较图像
Image Comparison by Finger Printing
我正在寻找通过指纹识别查找图像重复项的方法。我知道这是通过对图像应用哈希函数来完成的,每个图像都有一个唯一的哈希值。
我对图像处理还很陌生,对散列算法了解不多。我应该如何应用哈希函数并生成哈希值?
提前致谢
实现此目的的方法有很多,但最简单的方法是将图像转换为 base64 字符串,然后使用标准哈希库。在 python 中,它看起来像:
import base64
import md5
with open("foo.png", "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
m = md5.new()
m.update(encoded_string)
fingerprint = m.hexdigest()
print(fingerprint)
如果您只是将哈希函数视为将一个(可能很大的)字符串转换为另一个字符串,您应该没问题。在上面的代码中,m.update() 只是将 encoded_string(一个非常大的 base64 字符串)转换为一个较小的十六进制字符串,我们通过调用 m.hexdigest().
您可以阅读 md5 库的 python 文档 here 但无论您使用何种语言,都应该有类似的内容。
您需要小心散列,某些图像格式(例如 JPEG 和 PNG)会在图像中存储 dates/times 和其他信息,这会使两张相同的图像看起来与普通工具不同,例如md5
和 cksum
.
这是一个例子。使用 ImageMagick
在终端的命令行中制作两个相同的 128x128 红色方块图像
convert -size 128x128 xc:red a.png
convert -size 128x128 xc:red b.png
现在检查他们的 MD5 和:
md5 [ab].png
MD5 (a.png) = b4b82ba217f0b36e6d3ba1722f883e59
MD5 (b.png) = 6aa398d3aaf026c597063c5b71b8bd1a
或者他们的校验和:
cksum [ab].png
4158429075 290 a.png
3657683960 290 b.png
糟糕,根据md5
和cksum
,它们是不同的。为什么?因为日期相隔 1 秒。
我建议您使用 ImageMagick 校验和 "just the image data" 而不是元数据 - 当然,除非日期对你很重要:
identify -format %# a.png
e74164f4bab2dd8f7f612f8d2d77df17106bac77b9566aa888d31499e9cf8564
identify -format %# b.png
e74164f4bab2dd8f7f612f8d2d77df17106bac77b9566aa888d31499e9cf8564
现在它们是一样的,因为图像是一样的 - 只是元数据不同。
当然,您可能对 "Perceptual Hashing" 更感兴趣,如果两张图片 "look similar"。如果是,请查看 .
或者您可能对允许在亮度、方向或裁剪方面存在细微差异感兴趣——这完全是另一个话题。
如果您有兴趣查找 near 重复项,其中包括已调整大小的图像,您可以应用差异哈希。关于散列的更多信息 here. The code below is edited from Real Python 博客 post 使其在 python 中工作 3. 它使用链接到上面的散列库,其中包含关于不同类型散列的信息。您应该能够直接从命令行复制和粘贴脚本并 运行 它们,而无需编辑脚本。
第一个脚本 (index.py
) 为每个图像创建一个差异散列,然后将散列与图像文件名( s) 具有该散列的:
from PIL import Image
import imagehash
import argparse
import shelve
import glob
# This is just so you can run it from the command line
ap = argparse.ArgumentParser()
ap.add_argument('-d', '--dataset', required = True,
help = 'path to imput dataset of images')
ap.add_argument('-s', '--shelve', required = True,
help = 'output shelve database')
args = ap.parse_args()
# open the shelve database
db = shelve.open(args.shelve, writeback = True)
# loop over the image dataset
for imagePath in glob.glob(args.dataset + '/*.jpg'):
# load the image and compute the difference in hash
image = Image.open(imagePath)
h = str(imagehash.dhash(image))
print(h)
# extract the filename from the path and update the database using the hash
# as the key and the filename append to the list of values
filename = imagePath[imagePath.rfind('/') + 1:]
db[h] = db.get(h, []) + [filename]
db.close()
运行 命令行:
python index.py --dataset ./image_directory --shelve db.shelve
运行 在 Jupyter 笔记本中
%run index.py --dataset ./image_directory --shelve db.shelve
现在所有的东西都存储在一个架子里,你可以用你想查看的图片文件名查询架子,它会打印出匹配的图片的文件名,同时打开匹配的图片(search.py
):
from PIL import Image
import imagehash
import argparse
import shelve
# arguments for command line
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
help="path to dataset of images")
ap.add_argument("-s", "--shelve", required=True,
help="output the shelve database")
ap.add_argument("-q", "--query", required=True,
help="path to the query image")
args = ap.parse_args()
# open the shelve database
db = shelve.open(args.shelve)
# Load the query image, compute the difference image hash, and grab the images
# from the database that have the same hash value
query = Image.open(args.query)
h = str(imagehash.dhash(query))
filenames = db[h]
print("found {} images".format(len(filenames)))
# loop over the images
for filename in filenames:
print(filename)
image = Image.open(args.dataset + "/" + filename)
image.show()
# close the shelve database
db.close()
运行 在命令行上查看 image_directory
与 ./directory/someimage.jpg
具有相同哈希值的图像
python search.py —dataset ./image_directory —shelve db.shelve —query ./directory/someimage.jpg
同样,这是从上面链接的 Real Python
博客 post 修改而来的,它是为 python2.7 编写的,应该可以解决问题!只需根据需要更改命令行即可。如果我没记错的话,python 2/3 问题只是 argparse
而不是图像库。
我正在寻找通过指纹识别查找图像重复项的方法。我知道这是通过对图像应用哈希函数来完成的,每个图像都有一个唯一的哈希值。
我对图像处理还很陌生,对散列算法了解不多。我应该如何应用哈希函数并生成哈希值?
提前致谢
实现此目的的方法有很多,但最简单的方法是将图像转换为 base64 字符串,然后使用标准哈希库。在 python 中,它看起来像:
import base64
import md5
with open("foo.png", "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
m = md5.new()
m.update(encoded_string)
fingerprint = m.hexdigest()
print(fingerprint)
如果您只是将哈希函数视为将一个(可能很大的)字符串转换为另一个字符串,您应该没问题。在上面的代码中,m.update() 只是将 encoded_string(一个非常大的 base64 字符串)转换为一个较小的十六进制字符串,我们通过调用 m.hexdigest().
您可以阅读 md5 库的 python 文档 here 但无论您使用何种语言,都应该有类似的内容。
您需要小心散列,某些图像格式(例如 JPEG 和 PNG)会在图像中存储 dates/times 和其他信息,这会使两张相同的图像看起来与普通工具不同,例如md5
和 cksum
.
这是一个例子。使用 ImageMagick
在终端的命令行中制作两个相同的 128x128 红色方块图像convert -size 128x128 xc:red a.png
convert -size 128x128 xc:red b.png
现在检查他们的 MD5 和:
md5 [ab].png
MD5 (a.png) = b4b82ba217f0b36e6d3ba1722f883e59
MD5 (b.png) = 6aa398d3aaf026c597063c5b71b8bd1a
或者他们的校验和:
cksum [ab].png
4158429075 290 a.png
3657683960 290 b.png
糟糕,根据md5
和cksum
,它们是不同的。为什么?因为日期相隔 1 秒。
我建议您使用 ImageMagick 校验和 "just the image data" 而不是元数据 - 当然,除非日期对你很重要:
identify -format %# a.png
e74164f4bab2dd8f7f612f8d2d77df17106bac77b9566aa888d31499e9cf8564
identify -format %# b.png
e74164f4bab2dd8f7f612f8d2d77df17106bac77b9566aa888d31499e9cf8564
现在它们是一样的,因为图像是一样的 - 只是元数据不同。
当然,您可能对 "Perceptual Hashing" 更感兴趣,如果两张图片 "look similar"。如果是,请查看
或者您可能对允许在亮度、方向或裁剪方面存在细微差异感兴趣——这完全是另一个话题。
如果您有兴趣查找 near 重复项,其中包括已调整大小的图像,您可以应用差异哈希。关于散列的更多信息 here. The code below is edited from Real Python 博客 post 使其在 python 中工作 3. 它使用链接到上面的散列库,其中包含关于不同类型散列的信息。您应该能够直接从命令行复制和粘贴脚本并 运行 它们,而无需编辑脚本。
第一个脚本 (index.py
) 为每个图像创建一个差异散列,然后将散列与图像文件名( s) 具有该散列的:
from PIL import Image
import imagehash
import argparse
import shelve
import glob
# This is just so you can run it from the command line
ap = argparse.ArgumentParser()
ap.add_argument('-d', '--dataset', required = True,
help = 'path to imput dataset of images')
ap.add_argument('-s', '--shelve', required = True,
help = 'output shelve database')
args = ap.parse_args()
# open the shelve database
db = shelve.open(args.shelve, writeback = True)
# loop over the image dataset
for imagePath in glob.glob(args.dataset + '/*.jpg'):
# load the image and compute the difference in hash
image = Image.open(imagePath)
h = str(imagehash.dhash(image))
print(h)
# extract the filename from the path and update the database using the hash
# as the key and the filename append to the list of values
filename = imagePath[imagePath.rfind('/') + 1:]
db[h] = db.get(h, []) + [filename]
db.close()
运行 命令行:
python index.py --dataset ./image_directory --shelve db.shelve
运行 在 Jupyter 笔记本中
%run index.py --dataset ./image_directory --shelve db.shelve
现在所有的东西都存储在一个架子里,你可以用你想查看的图片文件名查询架子,它会打印出匹配的图片的文件名,同时打开匹配的图片(search.py
):
from PIL import Image
import imagehash
import argparse
import shelve
# arguments for command line
ap = argparse.ArgumentParser()
ap.add_argument("-d", "--dataset", required=True,
help="path to dataset of images")
ap.add_argument("-s", "--shelve", required=True,
help="output the shelve database")
ap.add_argument("-q", "--query", required=True,
help="path to the query image")
args = ap.parse_args()
# open the shelve database
db = shelve.open(args.shelve)
# Load the query image, compute the difference image hash, and grab the images
# from the database that have the same hash value
query = Image.open(args.query)
h = str(imagehash.dhash(query))
filenames = db[h]
print("found {} images".format(len(filenames)))
# loop over the images
for filename in filenames:
print(filename)
image = Image.open(args.dataset + "/" + filename)
image.show()
# close the shelve database
db.close()
运行 在命令行上查看 image_directory
与 ./directory/someimage.jpg
python search.py —dataset ./image_directory —shelve db.shelve —query ./directory/someimage.jpg
同样,这是从上面链接的 Real Python
博客 post 修改而来的,它是为 python2.7 编写的,应该可以解决问题!只需根据需要更改命令行即可。如果我没记错的话,python 2/3 问题只是 argparse
而不是图像库。