いっきのblog

技術とか色々

pythonを使ってORBとPerceptual Hashで画像の類似度を比べてみる

どうも、くずきです。
今回はPythonを使って画像の類似度を求めました。
なぜやりたいのかというと、インスタグラムなどのSNSで画像を設定していない人を除外したい。つまり、

f:id:kzkohashi:20180105204819j:plain

この画像か、近しい画像を設定している人が見つけ出せれば良い。

比較対象の画像

ファイル名 画像 説明
01.jpg 今回の比較画像
02.jpg f:id:kzkohashi:20180105204927j:plain 女性の画像(インスタから持ってきたのでここではモザイク)
03.jpg f:id:kzkohashi:20180105204924j:plain 男性の画像(インスタから持ってきたのでここではモザイク)
05.jpg f:id:kzkohashi:20180105204819j:plain 比較画像と同じ
06.png f:id:kzkohashi:20180105205044p:plain 比較画像の男風
07.png f:id:kzkohashi:20180105205057p:plain 比較画像の女風
08.png f:id:kzkohashi:20180105205132p:plain 化粧してる風な背景が比較画像に近い
11.jpg f:id:kzkohashi:20180105205448j:plain 背景青い人の画像
12.jpg f:id:kzkohashi:20180105205152j:plain 背景青い人の画像
13.jpg f:id:kzkohashi:20180105205155j:plain 比較画像に少し文字載せたやつ
15.jpg f:id:kzkohashi:20180105205159j:plain 比較画像にかなり文字載せたやつ

ORBを使って類似度を求める

qiita.com

この方の記事の特徴点のマッチングの部分を参考にさせていただきました。
コードはほぼそのままお借りさせていただいたので、結果のみ。

TARGET_FILE: 01.jpg

02.jpg 86.5
03.jpg 76.0
05.jpg 0.0
06.png 57.0
07.png 20.0
08.png 93.0
11.jpg 66.0
12.jpeg 74.5
13.jpg 3.5
15.jpg 59.0

0になれば一致してる画像とみなされている。
06.png15.jpgは除外したかったが思った以上に数値が高くなってしまい、閾値が設定しづらい。同じものが移動したり、回転したりしても特徴点を捉えることで同じものと認識する方法のためこういう結果なのは仕方ない。。

Perceptual Hashを使って類似度を求める

次に、画像をハッシュ値(64bit)に変換して、その距離を測ることによって類似度を求めるPerceptual Hashというアルゴリズムを試してみる。

hideack.hatenablog.com

この方達の記事が参考になる。
Pythonimagehashというライブラリで実装済みのため、それを利用する。

コード

from PIL import Image
import imagehash
import numpy
import scipy
import scipy.fftpack


TARGET_FILE = '01.jpg'
IMG_DIR = '/Users/SayKicho/images/'
target_img_path = IMG_DIR + TARGET_FILE
target_hash = imagehash.average_hash(Image.open(target_img_path))
files = os.listdir(IMG_DIR)

print('TARGET_FILE: %s' % (TARGET_FILE), target_hash)
print('files: %s' % (files))
for file in files:
    if file == '.DS_Store' or file == TARGET_FILE:
        continue

    comparing_img_path = IMG_DIR + file
    try:
        hash = imagehash.average_hash(Image.open(comparing_img_path))
        haming = target_hash - hash
    except cv2.error:
        ret = 100000

    print(file, hash, haming)

比較画像のハッシュ値(target_hash)から比較対象のハッシュ値(hash)を引き算してるところでハミング距離をだしてます。

TARGET_FILE: 01.jpg 00183c18183cffff

02.jpg ffe7c70707010302 51
03.jpg f4e0e9c7c7838330 47
05.jpg 00183c18183cffff 0
06.png 00383c3c18183cff 9
07.png 0018183c18187fff 7
08.png 0018181c1c18183c 16
11.jpg 00000306fcffffff 20
12.jpeg 103f1f8f82c7cfcf 28
13.jpg 00183c18183cffff 0
15.jpg 00181818181cffff 3

一番右がハミング距離。これが0になれば同じ画像と認識される。
さきほどORBのほうで値が高くなってしまった、06.png15.jpgの画像がかなり低く抑えられている。閾値はだいたい10くらいにしておけば近しい画像と認識されそう。

急ぎ足で書いてしまったけど、Perceptual Hashはあくまでも64bitのハッシュ値をもとめるアルゴリズムの総称をいっているので、細かくいうとAverage Hash, Perceptive Hash, Differece Hashなどがある。以下の記事に少し詳しく書いてあるので、気になる方はみとくといいかも。

stmind.hatenablog.com

感想

今回はPerceptual HashAverage Hashが一番効果よかったのでそれを用いて、インスタグラムの設定していない画像を見つけ出すことに成功した。
あまり画像周りに詳しくないので、他のアルゴリズムなども勉強しないとなー。