diff --git a/bob/bio/vein/configurations/preprocessors/finger_crop_None_CircGabor.py b/bob/bio/vein/configurations/preprocessors/finger_crop_None_CircGabor.py index da45dd702e4a2ac25e02877885d262f7fcc09007..d14474ccf716004c31bfe6a22c5eec452be72307 100644 --- a/bob/bio/vein/configurations/preprocessors/finger_crop_None_CircGabor.py +++ b/bob/bio/vein/configurations/preprocessors/finger_crop_None_CircGabor.py @@ -2,23 +2,4 @@ # vim: set fileencoding=utf-8 : from ...preprocessors import FingerCrop - -# Contour localization mask -CONTOUR_MASK_HEIGHT = 4 # Height of the mask -CONTOUR_MASK_WIDTH = 40 # Width of the mask - -PADDING_OFFSET = 5 -PADDING_THRESHOLD = 0.2 #Threshold for padding black zones - -FINGERCONTOUR = 'leemaskMod' # Options: 'leemaskMatlab', 'konomask' -POSTPROCESSING = 'CircGabor' # Options: None, 'HE', 'HFE', 'CircGabor' - -# define the preprocessor -preprocessor = FingerCrop( - mask_h=CONTOUR_MASK_HEIGHT, - mask_w=CONTOUR_MASK_WIDTH, - padding_offset=PADDING_OFFSET, - padding_threshold=PADDING_THRESHOLD, - fingercontour=FINGERCONTOUR, - postprocessing=POSTPROCESSING, - ) +preprocessor = FingerCrop(postprocessing='CircGabor') diff --git a/bob/bio/vein/configurations/preprocessors/finger_crop_None_HE.py b/bob/bio/vein/configurations/preprocessors/finger_crop_None_HE.py index 8abf66a78d252c30d9200bb1e6d39a4521bac747..49cd2fdcda75b7d4d3352ca01068658803ff818c 100644 --- a/bob/bio/vein/configurations/preprocessors/finger_crop_None_HE.py +++ b/bob/bio/vein/configurations/preprocessors/finger_crop_None_HE.py @@ -2,24 +2,4 @@ # vim: set fileencoding=utf-8 : from ...preprocessors import FingerCrop - -# Contour localization mask -CONTOUR_MASK_HEIGHT = 4 # Height of the mask -CONTOUR_MASK_WIDTH = 40 # Width of the mask - -PADDING_OFFSET = 5 -PADDING_THRESHOLD = 0.2 #Threshold for padding black zones - -PREPROCESSING = None -FINGERCONTOUR = 'leemaskMod' # Options: 'leemaskMatlab', 'konomask' -POSTPROCESSING = 'HE' # Options: None, 'HE', 'HFE', 'CircGabor' - -# define the preprocessor -preprocessor = FingerCrop( - mask_h=CONTOUR_MASK_HEIGHT, - mask_w=CONTOUR_MASK_WIDTH, - padding_offset=PADDING_OFFSET, - padding_threshold=PADDING_THRESHOLD, - fingercontour=FINGERCONTOUR, - postprocessing=POSTPROCESSING, - ) +preprocessor = FingerCrop(postprocessing='HFE') diff --git a/bob/bio/vein/configurations/preprocessors/finger_crop_None_HFE.py b/bob/bio/vein/configurations/preprocessors/finger_crop_None_HFE.py index 023aba1fbad0a8e6e6984d51844fbd018407cd12..49cd2fdcda75b7d4d3352ca01068658803ff818c 100644 --- a/bob/bio/vein/configurations/preprocessors/finger_crop_None_HFE.py +++ b/bob/bio/vein/configurations/preprocessors/finger_crop_None_HFE.py @@ -2,26 +2,4 @@ # vim: set fileencoding=utf-8 : from ...preprocessors import FingerCrop - - -# Contour localization mask -CONTOUR_MASK_HEIGHT = 4 # Height of the mask -CONTOUR_MASK_WIDTH = 40 # Width of the mask - -PADDING_OFFSET = 5 -PADDING_THRESHOLD = 0.2 #Threshold for padding black zones - -PREPROCESSING = None -FINGERCONTOUR = 'leemaskMod' # Options: 'leemaskMatlab', 'konomask' -POSTPROCESSING = 'HFE' # Options: None, 'HE', 'HFE', 'CircGabor' - -# define the preprocessor -preprocessor = FingerCrop( - mask_h=CONTOUR_MASK_HEIGHT, - mask_w=CONTOUR_MASK_WIDTH, - padding_offset=PADDING_OFFSET, - padding_threshold=PADDING_THRESHOLD, - preprocessing=PREPROCESSING, - fingercontour=FINGERCONTOUR, - postprocessing=POSTPROCESSING, - ) +preprocessor = FingerCrop(postprocessing='HFE') diff --git a/bob/bio/vein/configurations/preprocessors/finger_crop_None_None.py b/bob/bio/vein/configurations/preprocessors/finger_crop_None_None.py index dc88fda131a4bc41f726be2f81f7802623adeb7b..02c3d1b0b9f95b4847bad095da5fba7e259ee818 100644 --- a/bob/bio/vein/configurations/preprocessors/finger_crop_None_None.py +++ b/bob/bio/vein/configurations/preprocessors/finger_crop_None_None.py @@ -2,24 +2,4 @@ # vim: set fileencoding=utf-8 : from ...preprocessors import FingerCrop - - -# Contour localization mask -CONTOUR_MASK_HEIGHT = 4 # Height of the mask -CONTOUR_MASK_WIDTH = 40 # Width of the mask - -PADDING_OFFSET = 5 -PADDING_THRESHOLD = 0.2 #Threshold for padding black zones - -FINGERCONTOUR = 'leemaskMod' # Options: 'leemaskMod', leemaskMatlab', 'konomask' -POSTPROCESSING = None # Options: None, 'HE', 'HFE', 'CircGabor' - -# define the preprocessor -preprocessor = FingerCrop( - mask_h=CONTOUR_MASK_HEIGHT, - mask_w=CONTOUR_MASK_WIDTH, - padding_offset=PADDING_OFFSET, - padding_threshold=PADDING_THRESHOLD, - fingercontour=FINGERCONTOUR, - postprocessing=POSTPROCESSING, - ) +preprocessor = FingerCrop() diff --git a/bob/bio/vein/extractors/MaximumCurvature.py b/bob/bio/vein/extractors/MaximumCurvature.py index fc5d880ef142251ac88e9319f97089f363fb2e18..65f0da9e7dd28fd4dcfef7e6bea5271176a7b4df 100644 --- a/bob/bio/vein/extractors/MaximumCurvature.py +++ b/bob/bio/vein/extractors/MaximumCurvature.py @@ -57,11 +57,11 @@ class MaximumCurvature (Extractor): # Do the actual filtering - fx = utils.imfilter(image, hx, conv=False) - fxx = utils.imfilter(image, hxx, conv=False) - fy = utils.imfilter(image, hy, conv=False) - fyy = utils.imfilter(image, hyy, conv=False) - fxy = utils.imfilter(image, hxy, conv=False) + fx = utils.imfilter(image, hx) + fxx = utils.imfilter(image, hxx) + fy = utils.imfilter(image, hy) + fyy = utils.imfilter(image, hyy) + fxy = utils.imfilter(image, hxy) f1 = 0.5*numpy.sqrt(2)*(fx + fy) # \ # f2 = 0.5*numpy.sqrt(2)*(fx - fy) # / # diff --git a/bob/bio/vein/preprocessors/FingerCrop.py b/bob/bio/vein/preprocessors/FingerCrop.py index 64c2096a94f60f4c36cf8a2e3b1c34a4ca0d4032..89baf2065e0e64db6c659e4125c7b00d7fbee6bd 100644 --- a/bob/bio/vein/preprocessors/FingerCrop.py +++ b/bob/bio/vein/preprocessors/FingerCrop.py @@ -24,16 +24,30 @@ class FingerCrop (Preprocessor): feature extraction. International Journal of Imaging Systems and Technology. Vol. 19, No. 3, pp. 175-178, September 2009. + In this implementation, the finger image is (in this order): + + 1. Padded + 2. The mask is extracted + 3. The finger is normalized (made horizontal) + 3. (optionally) Post processed + Parameters: - mask_h (int, Optional): Height of contour mask in pixels + mask_h (int, Optional): Height of contour mask in pixels, must be an even + number mask_w (int, Optional): Width of the contour mask in pixels - padding_offset (int, Optional): + padding_width (int, Optional): How much padding (in pixels) to add around + the borders of the input image. We normally always keep this value on its + default (5 pixels). - padding_threshold (float, Optional): + padding_constant (int, Optional): What is the value of the pixels added + to the padding. This number should be a value between 0 and 255. (From + Pedro Tome: for UTFVP (high-quality samples), use 0. For the VERA + Fingervein database (low-quality samples), use 51 (that corresponds to + 0.2 in a float image with values between 0 and 1). fingercontour (str, Optional): Select between three finger contour implementations: leemaskMod, leemaskMatlab or konomask. (From Pedro Tome: @@ -46,34 +60,21 @@ class FingerCrop (Preprocessor): equalization, as with :py:func:`bob.ip.base.histogram_equalization`), ``HFE`` (high-frequency emphasis filter, with hard-coded parameters - see implementation) or ``CircGabor`` (circular Gabor filter with band-width - 1.12 octaves and standard deviation of 5 pixels (this is hard-coded). By + 1.12 octaves and standard deviation of 5 pixels (this is hard-coded)). By default, no postprocessing is applied on the image. """ - def __init__( - self, - mask_h = 4, # Height of the mask - mask_w = 40, # Width of the mask - - padding_offset = 5, #Always the same - padding_threshold = 0.2, #0 for UTFVP database (high quality), 0.2 for VERA database (low quality) - - fingercontour = 'leemaskMod', - postprocessing = None, - - **kwargs - ): - """Parameters of the constructor of this preprocessor: - - """ + def __init__(self, mask_h = 4, mask_w = 40, + padding_width = 5, padding_constant = 51, + fingercontour = 'leemaskMod', postprocessing = None, **kwargs): Preprocessor.__init__(self, mask_h = mask_h, mask_w = mask_w, - padding_offset = padding_offset, - padding_threshold = padding_threshold, + padding_width = padding_width, + padding_constant = padding_constant, fingercontour = fingercontour, postprocessing = postprocessing, **kwargs @@ -85,13 +86,17 @@ class FingerCrop (Preprocessor): self.fingercontour = fingercontour self.postprocessing = postprocessing - self.padding_offset = padding_offset - self.padding_threshold = padding_threshold + self.padding_width = padding_width + self.padding_constant = padding_constant def __konomask__(self, image, sigma): - """ M. Kono, H. Ueki and S. Umemura. Near-infrared finger vein patterns for personal identification, - Applied Optics, Vol. 41, Issue 35, pp. 7429-7436 (2002). + """Finger vein mask extractor + + Based on the work of M. Kono, H. Ueki and S. Umemura. Near-infrared finger + vein patterns for personal identification, Applied Optics, Vol. 41, Issue + 35, pp. 7429-7436 (2002). + """ sigma = 5 @@ -113,7 +118,7 @@ class FingerCrop (Preprocessor): hy = (-Y/(2*math.pi*sigma**4))*numpy.exp(-(X**2 + Y**2)/(2*sigma**2)) # Filter the image with the directional kernel - fy = utils.imfilter(image, hy, conv=False) + fy = utils.imfilter(image, hy) # Upper part of filtred image img_filt_up = fy[0:half_img_h,:] @@ -139,48 +144,72 @@ class FingerCrop (Preprocessor): def __leemaskMod__(self, image): + """A method to calculate the finger mask - img_h,img_w = image.shape + Based on the work of Finger vein recognition using minutia-based alignment + and local binary pattern-based feature extraction, E.C. Lee, H.C. Lee and + K.R. Park, International Journal of Imaging Systems and Technology, Volume + 19, Issue 3, September 2009, Pages 175--178, doi: 10.1002/ima.20193 - # Determine lower half starting point vertically - if numpy.mod(img_h,2) == 0: - half_img_h = img_h/2 + 1 - else: - half_img_h = numpy.ceil(img_h/2) + This code is a variant of the Matlab implementation by Bram Ton, available + at: - # Determine lower half starting point horizontally - if numpy.mod(img_w,2) == 0: - half_img_w = img_w/2 + 1 - else: - half_img_w = numpy.ceil(img_w/2) + https://nl.mathworks.com/matlabcentral/fileexchange/35752-finger-region-localisation/content/lee_region.m - # Construct mask for filtering - mask = numpy.zeros((self.mask_h,self.mask_w)) - mask[0:self.mask_h/2,:] = -1 - mask[self.mask_h/2:,:] = 1 + In this variant from Pedro Tome, the technique of filtering the image with + a horizontal filter is also applied on the vertical axis. + + + Parameters: + + image (numpy.ndarray): raw image to use for finding the mask, as 2D array + of unsigned 8-bit integers + + + Returns: + + numpy.ndarray: A 2D boolean array with the same shape of the input image + representing the cropping mask. ``True`` values indicate where the + finger is. - img_filt = utils.imfilter(image, mask, conv=True) + numpy.ndarray: A 2D array with 64-bit floats indicating the indexes where + the mask, for each column, starts and ends on the original image. The + same of this array is (2, number of columns on input image). + + """ + + + img_h,img_w = image.shape + + # Determine lower half starting point + half_img_h = img_h/2 + half_img_w = img_w/2 + + # Construct mask for filtering (up-bottom direction) + mask = numpy.ones((self.mask_h, self.mask_w), dtype='float64') + mask[(self.mask_h/2):,:] = -1.0 + + img_filt = utils.imfilter(image, mask) # Upper part of filtred image - img_filt_up = img_filt[0:half_img_h-1,:] + img_filt_up = img_filt[:half_img_h,:] y_up = img_filt_up.argmax(axis=0) - # Lower part of filtred image - img_filt_lo = img_filt[half_img_h-1:,:] + # Lower part of filtred image + img_filt_lo = img_filt[half_img_h:,:] y_lo = img_filt_lo.argmin(axis=0) - img_filt = utils.imfilter(image, mask.T, conv=True) + img_filt = utils.imfilter(image, mask.T) - # Left part of filtered image - img_filt_lf = img_filt[:,0:half_img_w] + # Left part of filtered image + img_filt_lf = img_filt[:,:half_img_w] y_lf = img_filt_lf.argmax(axis=1) - # Right part of filtred image + # Right part of filtred image img_filt_rg = img_filt[:,half_img_w:] y_rg = img_filt_rg.argmin(axis=1) - finger_mask = numpy.ndarray(image.shape, numpy.bool) - finger_mask[:,:] = False + finger_mask = numpy.zeros(image.shape, dtype='bool') for i in range(0,y_up.size): finger_mask[y_up[i]:y_lo[i]+img_filt_lo.shape[0]+1,i] = True @@ -189,7 +218,8 @@ class FingerCrop (Preprocessor): for i in range(0,y_lf.size): finger_mask[i,0:y_lf[i]+1] = False - # Right region has always the finger ending, crop the padding with the meadian + # Right region has always the finger ending, crop the padding with the + # meadian finger_mask[:,numpy.median(y_rg)+img_filt_rg.shape[1]:] = False # Extract y-position of finger edges @@ -197,59 +227,130 @@ class FingerCrop (Preprocessor): edges[0,:] = y_up edges[0,0:round(numpy.mean(y_lf))+1] = edges[0,round(numpy.mean(y_lf))+1] - edges[1,:] = numpy.round(y_lo + img_filt_lo.shape[0]) edges[1,0:round(numpy.mean(y_lf))+1] = edges[1,round(numpy.mean(y_lf))+1] - return (finger_mask, edges) + return finger_mask, edges def __leemaskMatlab__(self, image): + """A method to calculate the finger mask + + Based on the work of Finger vein recognition using minutia-based alignment + and local binary pattern-based feature extraction, E.C. Lee, H.C. Lee and + K.R. Park, International Journal of Imaging Systems and Technology, Volume + 19, Issue 3, September 2009, Pages 175--178, doi: 10.1002/ima.20193 + + This code is based on the Matlab implementation by Bram Ton, available at: + + https://nl.mathworks.com/matlabcentral/fileexchange/35752-finger-region-localisation/content/lee_region.m + + In this method, we calculate the mask of the finger independently for each + column of the input image. Firstly, the image is convolved with a [1,-1] + filter of size ``(self.mask_h, self.mask_w)``. Then, the upper and lower + parts of the resulting filtered image are separated. The location of the + maxima in the upper part is located. The same goes for the location of the + minima in the lower part. The mask is then calculated, per column, by + considering it starts in the point where the maxima is in the upper part + and goes up to the point where the minima is detected on the lower part. + + + Parameters: + + image (numpy.ndarray): raw image to use for finding the mask, as 2D array + of unsigned 8-bit integers + + + Returns: + + numpy.ndarray: A 2D boolean array with the same shape of the input image + representing the cropping mask. ``True`` values indicate where the + finger is. + + numpy.ndarray: A 2D array with 64-bit floats indicating the indexes where + the mask, for each column, starts and ends on the original image. The + same of this array is (2, number of columns on input image). + + """ img_h,img_w = image.shape # Determine lower half starting point - if numpy.mod(img_h,2) == 0: - half_img_h = img_h/2 + 1 - else: - half_img_h = numpy.ceil(img_h/2) + half_img_h = img_h/2 # Construct mask for filtering - mask = numpy.zeros((self.mask_h,self.mask_w)) - mask[0:self.mask_h/2,:] = -1 - mask[self.mask_h/2:,:] = 1 + mask = numpy.ones((self.mask_h,self.mask_w), dtype='float64') + mask[(self.mask_h/2):,:] = -1.0 - img_filt = utils.imfilter(image, mask, conv=True) + img_filt = utils.imfilter(image, mask) - # Upper part of filtred image - img_filt_up = img_filt[0:numpy.floor(img_h/2),:] + # Upper part of filtered image + img_filt_up = img_filt[:half_img_h,:] y_up = img_filt_up.argmax(axis=0) - # Lower part of filtred image - img_filt_lo = img_filt[half_img_h-1:,:] + # Lower part of filtered image + img_filt_lo = img_filt[half_img_h:,:] y_lo = img_filt_lo.argmin(axis=0) - for i in range(0,y_up.size): - img_filt[y_up[i]:y_lo[i]+img_filt_lo.shape[0],i]=1 - - finger_mask = numpy.ndarray(image.shape, numpy.bool) - finger_mask[:,:] = False - - finger_mask[img_filt==1] = True + # Translation: for all columns of the input image, set to True all pixels + # of the mask from index where the maxima occurred in the upper part until + # the index where the minima occurred in the lower part. + finger_mask = numpy.zeros(image.shape, dtype='bool') + for i in range(img_filt.shape[1]): + finger_mask[y_up[i]:(y_lo[i]+img_filt_lo.shape[0]+1), i] = True # Extract y-position of finger edges - edges = numpy.zeros((2,img_w)) + edges = numpy.zeros((2,img_w), dtype='float64') edges[0,:] = y_up edges[1,:] = numpy.round(y_lo + img_filt_lo.shape[0]) - return (finger_mask, edges) + return finger_mask, edges def __huangnormalization__(self, image, mask, edges): + """Simple finger normalization + + Based on B. Huang, Y. Dai, R. Li, D. Tang and W. Li, Finger-vein + authentication based on wide line detector and pattern normalization, + Proceedings on 20th International Conference on Pattern Recognition (ICPR), + 2010. + + This implementation aligns the finger to the centre of the image using an + affine transformation. Elliptic projection which is described in the + referenced paper is not included. + + In order to defined the affine transformation to be performed, the + algorithm first calculates the center for each edge (column wise) and + calculates the best linear fit parameters for a straight line passing + through those points. + + + Parameters: + + image (numpy.ndarray): raw image to normalize as 2D array of unsigned + 8-bit integers + + mask (numpy.ndarray): mask to normalize as 2D array of booleans + + edges (numpy.ndarray): edges of the mask, 2D array with 2 rows and as + many columns as the input image, containing the start of the mask and + the end of the mask. + + + Returns: + + numpy.ndarray: A 2D boolean array with the same shape and data type of + the input image representing the newly aligned image. + + numpy.ndarray: A 2D boolean array with the same shape and data type of + the input mask representing the newly aligned mask. + + + """ img_h, img_w = image.shape - bl = (edges[0,:] + edges[1,:])/2 # Finger base line + bl = edges.mean(axis=0) #baseline x = numpy.arange(0,img_w) A = numpy.vstack([x, numpy.ones(len(x))]).T @@ -288,41 +389,16 @@ class FingerCrop (Preprocessor): img=Image.fromarray(image) image_norm = img.transform(img.size, Image.AFFINE, Tinvtuple, resample=Image.BICUBIC) - #image_norm = img.transform(img.size, Image.AFFINE, (a,b,c,d,e,f,g,h,i), resample=Image.BICUBIC) image_norm = numpy.array(image_norm) finger_mask = numpy.zeros(mask.shape) - finger_mask[mask == True] = 1 + finger_mask[mask] = 1 img_mask=Image.fromarray(finger_mask) mask_norm = img_mask.transform(img_mask.size, Image.AFFINE, Tinvtuple, resample=Image.BICUBIC) - #mask_norm = img_mask.transform(img_mask.size, Image.AFFINE, (a,b,c,d,e,f,g,h,i), resample=Image.BICUBIC) - mask_norm = numpy.array(mask_norm) - - mask[:,:] = False - mask[mask_norm==1] = True - - return (image_norm,mask) - - - def __padding_finger__(self, image): - - image_new = bob.core.convert(image,numpy.float64,(0,1),(0,255)) - - img_h, img_w = image_new.shape - - padding_w = self.padding_threshold * numpy.ones((self.padding_offset, img_w)) - # up and down - image_new = numpy.concatenate((padding_w,image_new),axis=0) - image_new = numpy.concatenate((image_new,padding_w),axis=0) - - img_h, img_w = image_new.shape - padding_h = self.padding_threshold * numpy.ones((img_h,self.padding_offset)) - # left and right - image_new = numpy.concatenate((padding_h,image_new),axis=1) - image_new = numpy.concatenate((image_new,padding_h),axis=1) + mask_norm = numpy.array(mask_norm).astype('bool') - return bob.core.convert(image_new,numpy.uint8,(0,255),(0,1)) + return (image_norm, mask_norm) def __HE__(self, image): @@ -393,7 +469,7 @@ class FingerCrop (Preprocessor): # Without normalisation #gaborfilter = numpy.exp(-0.5*(X**2/sigma**2+Y**2/sigma**2))*numpy.cos(2*math.pi*fc*numpy.sqrt(X**2+Y**2)) - imageEnhance = utils.imfilter(image, gaborfilter, conv=False) + imageEnhance = utils.imfilter(image, gaborfilter) imageEnhance = numpy.abs(imageEnhance) return bob.core.convert(imageEnhance,numpy.uint8, (0,255), @@ -445,8 +521,9 @@ class FingerCrop (Preprocessor): """Reads the input image, extract the mask of the fingervein, postprocesses """ - # Padding array - image = self.__padding_finger__(image) + # 1. Pads the input image if any padding should be added + image = numpy.pad(image, self.padding_width, 'constant', + constant_values = self.padding_constant) ## Finger edges and contour extraction: if self.fingercontour == 'leemaskMatlab': diff --git a/bob/bio/vein/tests/test.py b/bob/bio/vein/tests/test.py index af994132d1a1ea66d73e29212c2c765978e1b4e9..18072ac9fb614c4ad27590390bc2c3e7f831a932 100644 --- a/bob/bio/vein/tests/test.py +++ b/bob/bio/vein/tests/test.py @@ -29,6 +29,27 @@ def F(parts): return pkg_resources.resource_filename(__name__, os.path.join(*parts)) +def _show_mask_over_image(image, mask, color='red'): + """Plots the mask over the image of a finger, for debugging purposes + + Parameters: + + image (numpy.ndarray): A 2D numpy.ndarray compose of 8-bit unsigned + integers containing the original image + + mask (numpy.ndarray): A 2D numpy.ndarray compose of boolean values + containing the calculated mask + + """ + + from PIL import Image + img = Image.fromarray(image).convert(mode='RGBA') + msk = Image.fromarray((~mask).astype('uint8')*80) + red = Image.new('RGBA', img.size, color=color) + img.paste(red, mask=msk) + img.show() + + def test_finger_crop(): input_filename = F(('preprocessors', '0019_3_1_120509-160517.png')) @@ -40,17 +61,17 @@ def test_finger_crop(): img = bob.io.base.load(input_filename) from bob.bio.vein.preprocessors.FingerCrop import FingerCrop - preprocess = FingerCrop(fingercontour='leemaskMatlab') + preprocess = FingerCrop(fingercontour='leemaskMatlab', padding_width=0) - output_img, finger_mask_norm = preprocess(img) + preproc, mask = preprocess(img) + #_show_mask_over_image(preproc, mask) - # Load Matlab reference - output_img_ref = bob.io.base.load(output_img_filename) - output_fvr_ref = bob.io.base.load(output_fvr_filename) + mask_ref = bob.io.base.load(output_fvr_filename) + preproc_ref = bob.io.base.load(output_img_filename) - # Compare output of python's implementation to matlab reference - # (loose comparison!) - assert numpy.mean(numpy.abs(output_img - output_img_ref)) < 1e2 + # Very loose comparison! + assert numpy.mean(numpy.abs(mask.astype('float64') - mask_ref)) < 1e-2 + assert numpy.mean(numpy.abs(preproc - preproc_ref)) < 1e2 def test_miuramax(): @@ -67,7 +88,7 @@ def test_miuramax(): # Apply Python implementation from bob.bio.vein.extractors.MaximumCurvature import MaximumCurvature - MC = MaximumCurvature(5, False) + MC = MaximumCurvature(5) output_img = MC((input_img, input_fvr)) # Load Matlab reference diff --git a/bob/bio/vein/utils.py b/bob/bio/vein/utils.py index 4579165d1777230ed4ac1d6e172e3d0b4668d24e..f4fdb3bddba4c5daf1f019f147d9e36008d15f42 100644 --- a/bob/bio/vein/utils.py +++ b/bob/bio/vein/utils.py @@ -8,10 +8,10 @@ import bob.sp import bob.core -def imfilter(a, b, conv=True): +def imfilter(a, b): """Applies a 2D filtering between images - This implementation was created to work exactly like the Matlab one. + This implementation was created to work similarly like the Matlab one. Parameters: @@ -23,20 +23,16 @@ def imfilter(a, b, conv=True): with :py:func:`bob.core.convert` and the range reset to ``[0.0, 1.0]``. b (numpy.ndarray): A 64-bit float 2-dimensional :py:class:`numpy.ndarray` - which represents the filter to be applied to the image - - conv (bool, Optional): If set, then rotates the filter ``b`` by 180 degrees - before applying it to the image ``a``, with - :py:func:`bob.ip.base.rotate`. + which represents the filter to be applied to the image. The input filter + has to be rotated by 180 degrees as we use + :py:func:`scipy.signal.convolve2d` to apply it. You can rotate your + filter ``b`` with the help of :py:func:`bob.ip.base.rotate`. """ if a.dtype == numpy.uint8: a = bob.core.convert(a, numpy.float64, (0,1)) - if conv: - b = bob.ip.base.rotate(b, 180) - shape = (a.shape[0] + b.shape[0] - 1, a.shape[1] + b.shape[1] - 1) a_ext = numpy.ndarray(shape=shape, dtype=numpy.float64) bob.sp.extrapolate_nearest(a, a_ext)