フィンガープリントで画像の重複を見つける方法を探しています。これは画像にハッシュ関数を適用することによって行われ、各画像には一意のハッシュ値があることを理解しています。
私は画像処理にかなり慣れていないため、ハッシュについてはあまり知りません。ハッシュ関数を適用してハッシュ値を生成するにはどうすればよいですか?
前もって感謝します
フィンガープリントで画像の重複を見つける方法を探しています。これは画像にハッシュ関数を適用することによって行われ、各画像には一意のハッシュ値があることを理解しています。
私は画像処理にかなり慣れていないため、ハッシュについてはあまり知りません。ハッシュ関数を適用してハッシュ値を生成するにはどうすればよいですか?
前もって感謝します
ハッシュには注意する必要があります。JPEG や PNG などの一部の画像形式では、画像内に日付/時刻やその他の情報が保存されるため、2 つの同一の画像が や などの通常のツールとは異なって表示されmd5
ますcksum
。
ここに例があります。ImageMagickを使用して、ターミナルのコマンド ラインで 128x128 の同じ赤い正方形の 2 つの画像を作成します。
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を使用して、メタデータではなく「画像データのみ」をチェックサムすることをお勧めします-もちろん、日付が重要でない限り:
identify -format %# a.png
e74164f4bab2dd8f7f612f8d2d77df17106bac77b9566aa888d31499e9cf8564
identify -format %# b.png
e74164f4bab2dd8f7f612f8d2d77df17106bac77b9566aa888d31499e9cf8564
画像は同じで、メタデータが異なるだけなので、どちらも同じです。
もちろん、2 つの画像が「似ている」かどうかを判断する「Perceptual Hashing」の方が興味があるかもしれません。もしそうなら、ここを見てください。
または、明るさ、方向、またはトリミングのわずかな違いを許可することに興味があるかもしれませんが、これはまったく別のトピックです.
サイズ変更された画像を含むほぼ重複を見つけることに興味がある場合は、差分ハッシュを適用できます。ハッシュの詳細については、こちらをご覧ください。以下のコードは、Python 3 で動作するようにReal Pythonブログ投稿から編集されています。さまざまな種類のハッシュに関する情報を含む、上記にリンクされているハッシュ ライブラリを使用しています。スクリプトをコピーして貼り付けるだけで、スクリプトを編集せずにコマンドラインから両方を直接実行できるはずです。
この最初のスクリプト ( index.py
) は、各画像の差分ハッシュを作成し、そのハッシュを、そのハッシュを持つ画像ファイル名と共に、シェルフ、またはデータベースのように後でアクセスできる永続的な辞書に入れます。
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
上記のリンクのブログ投稿から変更されたもので、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)
ハッシュ関数を 1 つの (場合によっては大きな) 文字列を別の文字列に変換するものと考えるだけでも問題ありません。上記のコード m.update() では、encoded_string (非常に大きな base64 文字列) を m.hexdigest() を呼び出して取得する小さな 16 進文字列に変換するだけです。
ここで md5 ライブラリの python ドキュメントを読むことができますが、使用している言語に似たものがあるはずです。