diff --git a/bob/bio/vein/algorithm/HammingDistance.py b/bob/bio/vein/algorithm/HammingDistance.py index cb7827530249eb6825595e3549f8058913d9f21e..cfa5c2968bc69ffe8b69507807577a4f11784e7e 100644 --- a/bob/bio/vein/algorithm/HammingDistance.py +++ b/bob/bio/vein/algorithm/HammingDistance.py @@ -1,62 +1,37 @@ #!/usr/bin/env python # vim: set fileencoding=utf-8 : -import bob.ip.base -import numpy -import scipy.signal +from bob.bio.base.algorithm import Distance +import scipy.spatial.distance -from bob.bio.base.algorithm import Algorithm +class HammingDistance (Distance): + """This class calculates the Hamming distance between two binary images. + + Each binary image is first flattened by concatenating its rows to form a one-dimensional vector. The Hamming distance is then calculated between the two binary vectors. + The Hamming distance is computed using :py:func:`scipy.spatial.distance.hamming`, which returns a scalar ``float`` to represent the proportion of mismatching corresponding bits between the two binary vectors. + + **Parameters:** + + ``distance_function`` : function + Set this parameter to ``scipy.spatial.distance.hamming`` to ensure we are calculating the Hamming distance + + ``is_distance_function`` : bool + Set this flag to ``False`` to ensure that Hamming distances are returned as positive values rather than negative -class HammingDistance (Algorithm): - """Finger vein matching: hamming distance """ + def __init__( self, - # some similarity functions might need a GaborWaveletTransform class, so we have to provide the parameters here as well... - ch = 8, # Maximum search displacement in y-direction - cw = 5, # Maximum search displacement in x-direction + distance_function = scipy.spatial.distance.hamming, + is_distance_function = False # setting this to False ensures that Hamming distances are returned as positive values rather than negative ): - # call base class constructor - Algorithm.__init__( + # Call base class constructor + Distance.__init__( self, - - ch = ch, - cw = cw, - - multiple_model_scoring = None, - multiple_probe_scoring = None - ) - - self.ch = ch - self.cw = cw - - def enroll(self, enroll_features): - """Enrolls the model by computing an average graph for each model""" - # return the generated model - return numpy.vstack(enroll_features) - - - def score(self, model, probe): - """Computes the score of the probe and the model - Return score - Value between 0 and 0.5, larger value is better match - """ - I=probe.astype(numpy.float64) - R=model.astype(numpy.float64) - h, w = R.shape - crop_R = R[self.ch:h-self.ch, self.cw:w-self.cw] - rotate_R = numpy.zeros((crop_R.shape[0], crop_R.shape[1])) - bob.ip.base.rotate(crop_R, rotate_R, 180) - #FFT for scoring! - #Nm=bob.sp.ifft(bob.sp.fft(I)*bob.sp.fft(rotate_R)) - Nm = scipy.signal.convolve2d(I, rotate_R, 'valid'); - t0, s0 = numpy.unravel_index(Nm.argmax(), Nm.shape) - Nmm = Nm[t0,s0] - #Nmm = Nm.max() - #mi = numpy.argwhere(Nmm == Nm) - #t0, s0 = mi.flatten()[:2] - score = Nmm/(sum(sum(crop_R)) + sum(sum(I[t0:t0+h-2*self.ch, s0:s0+w-2*self.cw]))) - return score + distance_function = distance_function, + is_distance_function = is_distance_function + ) \ No newline at end of file diff --git a/bob/bio/vein/tests/test.py b/bob/bio/vein/tests/test.py index 8a594b22dfc5335b6091cd279b85d30ece16f113..fb4c4e1951236cfb4cb20d59158237934805c99e 100644 --- a/bob/bio/vein/tests/test.py +++ b/bob/bio/vein/tests/test.py @@ -685,3 +685,26 @@ def test_correlation(): total = time.clock() - start print('scipy+correlate2d, %d iterations - %.2e per iteration' % (N, total/N)) ''' + + +def test_hamming_distance(): + + from ..algorithm.HammingDistance import HammingDistance + HD = HammingDistance() + + # Tests on simple binary arrays: + # 1.) Maximum HD (1.0): + model_1 = numpy.array([0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0]) + probe_1 = numpy.array([[1, 0, 0, 0, 1, 0], [0, 1, 1, 1, 0, 1]]) + score_max = HD.score(model_1, probe_1) + assert score_max == 1.0 + # 2.) Minimum HD (0.0): + model_2 = numpy.array([0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1]) + probe_2 = numpy.array([[0, 1, 1, 1, 0, 1], [0, 1, 1, 1, 0, 1]]) + score_min = HD.score(model_2, probe_2) + assert score_min == 0.0 + # 3.) HD of exactly half (0.5) + model_3 = numpy.array([0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0]) + probe_3 = numpy.array([[0, 1, 1, 1, 0, 1], [0, 1, 1, 1, 0, 1]]) + score_half = HD.score(model_3, probe_3) + assert score_half == 0.5 \ No newline at end of file