質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

4652閲覧

pythonのimagehashでサポートされているperceptual hashのアルゴリズムについて

r3y2u1

総合スコア14

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2017/08/10 07:56

編集2017/08/10 15:13

###前提・実現したいこと
ここに質問したいことを詳細に書いてください
perceptual hashのアルゴリズムについて詳しく教えてもらいたいです。[リンク内容](https://github.com/JohannesBuchner/imagehash/blob/master/imagehash/__init__.py)
###発生している問題・エラーメッセージ```python
コード

def phash(image, hash_size=8, highfreq_factor=4): """ Perceptual Hash computation. Implementation follows http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html @image must be a PIL instance. """ if hash_size < 0: raise ValueError("Hash size must be positive") import scipy.fftpack img_size = hash_size * highfreq_factor image = image.convert("L").resize((img_size, img_size), Image.ANTIALIAS) pixels = numpy.array(image.getdata(), dtype=numpy.float).reshape((img_size, img_size)) //ここまでは何となく理解できるのですがscipy.fftpack.dct(pixels, axis=0)で離散コサイン変換の処理をするところでつまずいています。 dct = scipy.fftpack.dct(scipy.fftpack.dct(pixels, axis=0), axis=1) dctlowfreq = dct[:hash_size, :hash_size] med = numpy.median(dctlowfreq) diff = dctlowfreq > med return ImageHash(diff) /*****ここからは自分で作成したプログラムです。*****/ import os import glob from PIL import Image import imagehash import shutil hash = imagehash.phash(Image.open(r'./testdir/bw.jpg')) #比べる元画像 print(hash) #確認用 files = glob.glob('./testdir/*') #比較したい画像が入っているフォルダ for f in files: (dirname,filename)=os.path.split(f) #ファイル名を取得 otherhash = imagehash.phash(Image.open(f)) #比較する画像 flag = hash - otherhash #ハミング距離 if flag <= 60: #ある値よりflagが小さかったらファイル名とハミング距離を表示 print(filename) print(hash - otherhash) else: print('a') #確認用

エラーメッセージ

###該当のソースコード ```ここに言語を入力 ここにご自身が実行したソースコードを書いてください

###試したことイメージ説明
課題に対してアプローチしたことを記載してください
scipyのscipyのrealtransform.pyの def _dct(x, type, n=None, axis=-1, overwrite_x=False, normalize=None):で離散コサイン変換をしていると思うのですがプログラミング初心者なためあまり理解ができていない状態です。どのような処理を行っているか教えていただきたいです。
###補足情報(言語/FW/ツール等のバージョンなど)
より詳細な情報
can110さんに作成していただいた確認用コードをイメージに載せた画像で動かして見ました。またその結果も載せてあります。
自分で作成したプログラムの元画像のhashは0101000001010000となりました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ざっと調べてみました。おおざっぱですが、以下のような流れと理解しました。

  1. 元画像をグレースケール+固定サイズに正規化
  2. 正規化した画像をDCTにて成分値(行列)を算出
  3. 低周波成分(8x8行列)のみを抽出
  4. 各低周波成分について平均よりも大きい or 小さいで2値化(8x8行列)
  5. 2値化行列を1次元ビットに展開し8x8=64bit値を算出

2~4がaHash(Average Hash or Mean Hash)dHash(Difference Hash)との違いとなります。

アルゴリズムの概要についてはPerceptual Hash
DCTについては離散コサイン変換(DCT)をPythonで実装した[Python]
が参考になりました。

また、以下は動作を理解するための確認用コードです。

Python

1from PIL import Image 2image = Image.open('lena.png') 3 4hash_size = 8 # ハッシュデータサイズ 8x8 = 64[bit] 5highfreq_factor = 4 # どの程度高周波成分を生かすか? 大きいほど低周波成分のみが生きてくる。 6 7import numpy, scipy 8img_size = hash_size * highfreq_factor # サイズ正規化後の(縦横)サイズ [pixel] 9 10# 元画像の正規化 : "L" グレースケール+画像サイズを32x32に。 11image = image.convert("L").resize((img_size, img_size), Image.ANTIALIAS) 12# floatに 13pixels = numpy.array(image.getdata(), dtype=numpy.float).reshape((img_size, img_size)) 14print('pixels',pixels) 15print(pixels.shape) 16 17# DCTにて周波数成分を算出 18# 列、行方向に各1回で2次元? 19import scipy.fftpack 20# 列 21dct0 = scipy.fftpack.dct( pixels, axis=0) 22print('dct0',dct0) 23print(dct0.shape) 24# 行 25dct = scipy.fftpack.dct( dct0, axis=1) 26print('dct',dct) 27print(dct.shape) 28 29# 左上 8x8 部分=低周波成分のみ抽出 30dctlowfreq = dct[:hash_size, :hash_size] 31print('dctlowfreq',dctlowfreq) 32print(dctlowfreq.shape) 33 34# 成分の平均値を算出 35med = numpy.median(dctlowfreq) 36print('med',med) 37 38# 平均 より大きい or 小さい で2値化 39diff = dctlowfreq > med 40print('dif',diff) 41print(diff.shape) 42 43# 後は1次元化ビットデータ→バイナリに 44diff = diff.flatten() 45print(diff) 46# 略

lena.pngでの実行結果例。

pixels [[ 157. 153. 168. ..., 122. 129. 99.] [ 156. 159. 167. ..., 133. 91. 44.] [ 161. 164. 163. ..., 89. 45. 51.] ..., [ 91. 137. 146. ..., 86. 96. 79.] [ 108. 145. 150. ..., 85. 100. 69.] [ 73. 164. 159. ..., 99. 90. 59.]] (32, 32) dct0 [[ 6.32800000e+03 7.07200000e+03 1.05940000e+04 ..., 8.60200000e+03 8.56400000e+03 8.32000000e+03] [ 7.98016665e+02 2.62511492e+02 1.96280228e+02 ..., -7.56732747e+02 -4.41547133e+02 -1.57118303e+02] [ 6.46097040e+02 8.18776417e+02 -2.63514617e+02 ..., -1.50400070e+03 -1.65134257e+03 -1.87834848e+03] ..., [ -2.36991803e+01 9.79124296e-01 6.18355143e+00 ..., -2.66121620e+00 4.29854489e+00 -6.24873463e+01] [ 6.24966135e+01 2.26717368e+00 -1.16876665e+01 ..., -3.47209442e+00 -3.82978202e+01 1.13660396e+02] [ -3.70468280e+01 -1.07048481e+00 3.02842970e+00 ..., 1.94634067e+01 3.25523913e+00 -1.07515692e+02]] (32, 32) dct [[ 5.06036000e+05 -2.94304398e+04 -6.81773745e+03 ..., -3.30672277e+03 -7.48904307e+02 -1.86993620e+03] [ 1.98802074e+04 1.53921290e+04 -1.32546329e+04 ..., 2.80471722e+02 8.32317252e+02 2.72208429e+02] [ -4.93959257e+02 6.38192837e+03 -1.18131952e+04 ..., 8.25563260e+01 -1.49816934e+03 -4.18435435e+00] ..., [ -3.43617926e+02 6.39597213e+01 -2.22653656e+01 ..., 2.05208094e+02 2.23489435e+02 -1.42433561e+02] [ 6.91319107e+02 -2.55544837e+02 -2.31524406e+02 ..., -3.35882969e+02 6.33748893e+02 -1.63967256e+02] [ -4.09150007e+02 1.87268370e+02 -9.60016979e+01 ..., -2.54835022e+02 3.54280412e+02 -8.90047699e+02]] (32, 32) dctlowfreq [[ 5.06036000e+05 -2.94304398e+04 -6.81773745e+03 2.80701261e+04 2.38838080e+04 -1.28880165e+04 -3.51294509e+03 1.15306260e+04] [ 1.98802074e+04 1.53921290e+04 -1.32546329e+04 -4.99924707e+03 -4.94272573e+03 6.32557553e+03 2.62219370e+03 -4.56258784e+03] [ -4.93959257e+02 6.38192837e+03 -1.18131952e+04 1.62273412e+04 -1.12535016e+04 2.03382925e+04 7.74449276e+02 -2.37259333e+03] [ -4.89206193e+03 -3.59678046e+03 1.53594984e+04 -1.14005239e+04 2.36889938e+03 6.87236303e+03 -1.37074421e+04 6.09362931e+03] [ -7.10556545e+03 4.24761315e+03 4.28739884e+03 4.78750339e+03 -4.87325605e+02 2.75701535e+03 -1.04804645e+03 2.59382161e+03] [ -8.83807448e+02 -1.23385051e+03 1.02040065e+04 1.05757043e+03 -8.93986061e+03 -2.86076349e+03 7.12062401e+03 1.09866683e+04] [ 8.03531745e+03 -4.14851498e+03 5.08046787e+03 -4.43660697e+03 -2.94851358e+03 1.65221080e+02 7.82385862e+03 -7.46364918e+03] [ 1.01303000e+04 -5.23021293e+03 -3.17246145e+03 4.61738896e+03 -8.23560153e+02 2.55903708e+03 2.70463560e+03 -6.10959429e+03]] (8, 8) med 469.835177852 dif [[ True False False True True False False True] [ True True False False False True True False] [False True False True False True True False] [False False True False True True False True] [False True True True False True False True] [False False True True False False True True] [ True False True False False False True False] [ True False False True False True True False]] (8, 8) [ True False False True True False False True True True False False False True True False False True False True False True True False False False True False True True False True False True True True False True False True False False True True False False True True True False True False False False True False True False False True False True True False]

投稿2017/08/10 09:13

編集2017/08/10 15:55
can110

総合スコア38233

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

r3y2u1

2017/08/10 15:30

回答、分かりやすい確認用コードありがとうございます。 自分で作成したプログラムの元画像のhashは0101000001010000となったのですが確認用コードのほうではdiff[[True False False False False False False False]となっておりビッグエンディアンで16進数に変換したら10......というような感じになろと思うのですがどこか間違えていますかね?
can110

2017/08/10 15:42

ちゃんとコード確認できていませんが、imagehashでのdef phash(...)関数内のdiffが私の回答のdiffと同じになるはずです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問