ざっと調べてみました。おおざっぱですが、以下のような流れと理解しました。
- 元画像をグレースケール+固定サイズに正規化
- 正規化した画像をDCTにて成分値(行列)を算出
- 低周波成分(8x8行列)のみを抽出
- 各低周波成分について平均よりも大きい or 小さいで2値化(8x8行列)
- 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 15:30
2017/08/10 15:42
2017/08/10 15:47