はじめに
OpenCV Pythonを使ってdhashを利用した画像の類似度計算を行いたかったのですが、メソッドが存在しなかったため手実装しました。
OpenCVとnumpyを利用しています。
ライブラリに頼る場合
https://pypi.org/project/dhash/
というライブラリがあるようです。
実装もこれを参考にしました。
実装方法
上記ライブラリの実装を見てみます。
- Convert the image to grayscale
- Downsize it to a 9x9 thumbnail (size=8 means an 8+1 by 8+1 image)
- Produce a 64-bit “row hash”: a 1 bit means the pixel intensity is increasing in the x direction, 0 means it’s decreasing
- Do the same to produce a 64-bit “column hash” in the y direction
- Combine the two values to produce the final 128-bit hash value
GrayScaleに変換した後リサイズ、横方向と縦方向で差分を取って結合、という手順のようです。
dhash.py
import numpy as np
import cv2
image = cv2.imread('画像のパス')
# 8 * 8 の64bitハッシュを作成する
hash_size = 8
# グレースケール変換
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# リサイズ方法はINTER_AREAが縮小向け
resized_image_gray = cv2.resize(image_gray, (hash_size + 1, hash_size + 1), cv2.INTER_AREA)
# 差分計算 横方向と縦方向それぞれ計算する
dhash_h = resized_image_gray[:-1, 1:] > resized_image_gray[:-1, :-1]
dhash_v = resized_image_gray.T[:-1, 1:] > resized_image_gray.T[:-1, :-1]
# 横方向と縦方向を結合
dhash = np.concatenate((dhash_h.reshape(-1), dhash_v.reshape(-1)))
dhashで類似度を比較する場合、ハミング距離を用いるようです。
distance.py
hamming_distance = np.count_nonzero(dhash != dhash)
同じハッシュを渡せば0が返ります。
参考
https://pypi.org/project/dhash/
https://i.botch.me/2019/08/26/dhashを生成するライブラリ作った/
https://tech.unifa-e.com/entry/2017/11/27/111546