Skip to content

Commit

Permalink
whash(): Wavelet based image hash
Browse files Browse the repository at this point in the history
  • Loading branch information
dmpetrov committed Jun 26, 2016
1 parent 56932f0 commit da9386d
Showing 1 changed file with 44 additions and 0 deletions.
44 changes: 44 additions & 0 deletions imagehash/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
from PIL import Image
import numpy
import scipy.fftpack
import pywt

def _binary_array_to_hex(arr):
"""
Expand Down Expand Up @@ -161,4 +162,47 @@ def dhash(image, hash_size=8):
return ImageHash(diff)


def whash(image, hash_size = 8, image_scale = None, mode = 'haar', remove_max_haar_ll = True):
"""
Wavelet Hash computation.
@image must be a PIL instance.
@hash_size must be a power of 2 and less than @image_scale.
@image_scale must be power of 2 and less than image size. By default is equal to max
power of 2 for an input image.
@mode (see modes in pywt library):
'haar' - Haar wavelets, by default
'db4' - Daubechies wavelets
@remove_max_haar_ll - remove the lowest low level (LL) frequency using Haar wavelet.
"""

if image_scale != None:
assert image_scale == int(2**image_scale), "image_scale is not power of 2"
else:
image_scale = 2**int(numpy.log2(min(image.size)))
ll_max_level = int(numpy.log2(image_scale))

level = int(numpy.log2(hash_size))
assert hash_size == 2**level, "hash_size is not power of 2"
assert level <= ll_max_level, "hash_size in a wrong range"
dwt_level = ll_max_level - level

image = image.convert("L").resize((image_scale, image_scale), Image.ANTIALIAS)
pixels = numpy.array(image.getdata(), dtype=numpy.float).reshape((image_scale, image_scale))
pixels /= 255

# Remove low level frequency LL(max_ll) if @remove_max_haar_ll using haar filter
if remove_max_haar_ll:
coeffs = pywt.wavedec2(pixels, 'haar', level = ll_max_level)
coeffs = list(coeffs)
coeffs[0] *= 0
pixels = pywt.waverec2(coeffs, 'haar')

# Use LL(K) as freq, where K is log2(@hash_size)
coeffs = pywt.wavedec2(pixels, mode, level = dwt_level)
dwt_low = coeffs[0]

# Subsitract median and compute hash
med = numpy.median(dwt_low)
diff = dwt_low > med
return ImageHash(diff)

0 comments on commit da9386d

Please sign in to comment.