Commit 331df584 authored by André Anjos's avatar André Anjos 💬
Browse files

[extractors] Porting and cleanup

parent ebc2f696
#!/usr/bin/env python #!/usr/bin/env python
# Pedro Tome <Pedro.Tome@idiap.ch> # vim: set fileencoding=utf-8 :
import configurations
import tools
import preprocessing
import features
import tests
import script
#import utils
def get_config(): def get_config():
"""Returns a string containing the configuration information. """Returns a string containing the configuration information.
""" """
import pkg_resources import bob.extension
return bob.extension.get_config(__name__)
packages = pkg_resources.require(__name__)
this = packages[0]
deps = packages[1:]
retval = "%s: %s (%s)\n" % (this.key, this.version, this.location)
retval += " - python dependencies:\n"
for d in deps: retval += " - %s: %s (%s)\n" % (d.key, d.version, d.location)
return retval.strip()
# gets sphinx autodoc done right - don't remove it # gets sphinx autodoc done right - don't remove it
__all__ = [_ for _ in dir() if not _.startswith('_')] __all__ = [_ for _ in dir() if not _.startswith('_')]
...@@ -5,18 +5,14 @@ ...@@ -5,18 +5,14 @@
import bob.ip.base import bob.ip.base
import bob.io.base import bob.io.base
import numpy import numpy
import math from bob.bio.base.features.Extractor import Extractor
#from math import pi
#from mumpy import sqrt
import scipy.signal
from facereclib.features.Extractor import Extractor
from .. import utils
#from facereclib.utils import histogram
class LocalBinaryPatterns (Extractor): class LocalBinaryPatterns (Extractor):
"""LBP feature extractor
"""LBP feature extractor, paramters fixed based on
L. Mirmohamadsadeghi and A. Drygajlo. Palm vein recognition uisng local texture patterns, IET Biometrics, pp. 1-9, 2013. Parameters fixed based on L. Mirmohamadsadeghi and A. Drygajlo. Palm vein
recognition uisng local texture patterns, IET Biometrics, pp. 1-9, 2013.
""" """
def __init__( def __init__(
...@@ -34,9 +30,8 @@ class LocalBinaryPatterns (Extractor): ...@@ -34,9 +30,8 @@ class LocalBinaryPatterns (Extractor):
lbp_add_average = False, lbp_add_average = False,
# histogram options # histogram options
sparse_histogram = False, sparse_histogram = False,
split_histogram = None split_histogram = None,
):
):
# call base class constructor # call base class constructor
Extractor.__init__( Extractor.__init__(
...@@ -53,15 +48,15 @@ class LocalBinaryPatterns (Extractor): ...@@ -53,15 +48,15 @@ class LocalBinaryPatterns (Extractor):
lbp_compare_to_average = lbp_compare_to_average, lbp_compare_to_average = lbp_compare_to_average,
lbp_add_average = lbp_add_average, lbp_add_average = lbp_add_average,
sparse_histogram = sparse_histogram, sparse_histogram = sparse_histogram,
split_histogram = split_histogram split_histogram = split_histogram,
) )
# block parameters # block parameters
self.m_block_size = block_size if isinstance(block_size, (tuple, list)) else (block_size, block_size) self.m_block_size = block_size if isinstance(block_size, (tuple, list)) else (block_size, block_size)
self.m_block_overlap = block_overlap if isinstance(block_overlap, (tuple, list)) else (block_overlap, block_overlap) self.m_block_overlap = block_overlap if isinstance(block_overlap, (tuple, list)) else (block_overlap, block_overlap)
if self.m_block_size[0] < self.m_block_overlap[0] or self.m_block_size[1] < self.m_block_overlap[1]: if self.m_block_size[0] < self.m_block_overlap[0] or self.m_block_size[1] < self.m_block_overlap[1]:
raise ValueError("The overlap is bigger than the block size. This won't work. Please check your setup!") raise ValueError("The overlap is bigger than the block size. This won't work. Please check your setup!")
self.m_lbp = bob.ip.base.LBP( self.m_lbp = bob.ip.base.LBP(
neighbors = lbp_neighbor_count, neighbors = lbp_neighbor_count,
radius = float(lbp_radius), radius = float(lbp_radius),
...@@ -70,76 +65,78 @@ class LocalBinaryPatterns (Extractor): ...@@ -70,76 +65,78 @@ class LocalBinaryPatterns (Extractor):
add_average_bit = lbp_add_average, add_average_bit = lbp_add_average,
uniform = lbp_uniform, uniform = lbp_uniform,
rotation_invariant = lbp_rotation_invariant, rotation_invariant = lbp_rotation_invariant,
border_handling = 'wrap' border_handling = 'wrap',
) )
self.m_split = split_histogram self.m_split = split_histogram
self.m_sparse = sparse_histogram self.m_sparse = sparse_histogram
if self.m_sparse and self.m_split: if self.m_sparse and self.m_split:
raise ValueError("Sparse histograms cannot be split! Check your setup!") raise ValueError("Sparse histograms cannot be split! Check your setup.")
def __fill__(self, lbphs_array, lbphs_blocks, j): def __fill__(self, lbphs_array, lbphs_blocks, j):
"""Copies the given array into the given blocks""" """Copies the given array into the given blocks"""
# fill array in the desired shape # fill array in the desired shape
#For debugging #For debugging
#import ipdb; ipdb.set_trace() #import ipdb; ipdb.set_trace()
for b in range(self.m_n_blocks): for b in range(self.m_n_blocks):
lbphs_array[b * self.m_n_bins : (b+1) * self.m_n_bins] = lbphs_blocks[b][:] lbphs_array[b * self.m_n_bins : (b+1) * self.m_n_bins] = lbphs_blocks[b][:]
def lbp_features(self, finger_image, mask): def lbp_features(self, finger_image, mask):
"""Computes and returns the LBP features for the given input fingervein image""" """Computes and returns the LBP features for the given input fingervein
image"""
# For debugging
#import ipdb; ipdb.set_trace() # For debugging
#import ipdb; ipdb.set_trace()
finger_image = finger_image.astype(numpy.float64) finger_image = finger_image.astype(numpy.float64)
finger_mask = numpy.zeros(mask.shape) finger_mask = numpy.zeros(mask.shape)
finger_mask[mask == True] = 1 finger_mask[mask == True] = 1
# Mask the vein image with the finger region # Mask the vein image with the finger region
finger_image = finger_image*finger_mask finger_image = finger_image*finger_mask
# Computes LBP histograms # Computes LBP histograms
abs_blocks = bob.ip.base.lbphs(finger_image, self.m_lbp, self.m_block_size, self.m_block_overlap) abs_blocks = bob.ip.base.lbphs(finger_image, self.m_lbp, self.m_block_size, self.m_block_overlap)
# Converts to Blitz array (of different dimensionalities) # Converts to Blitz array (of different dimensionalities)
self.m_n_bins = abs_blocks.shape[1] self.m_n_bins = abs_blocks.shape[1]
self.m_n_blocks = abs_blocks.shape[0] self.m_n_blocks = abs_blocks.shape[0]
shape = self.m_n_bins * self.m_n_blocks shape = self.m_n_bins * self.m_n_blocks
# create new array # create new array
lbphs_array = numpy.zeros(shape, 'float64') lbphs_array = numpy.zeros(shape, 'float64')
#For debugging #For debugging
#import ipdb; ipdb.set_trace() #import ipdb; ipdb.set_trace()
# fill the array with the absolute values of the Gabor wavelet transform # fill the array with the absolute values of the Gabor wavelet transform
self.__fill__(lbphs_array, abs_blocks, 0) self.__fill__(lbphs_array, abs_blocks, 0)
# return the concatenated list of all histograms # return the concatenated list of all histograms
return lbphs_array return lbphs_array
def __call__(self, image): def __call__(self, image):
"""Reads the input image, extract the features based on LBP of the fingervein image, and writes the resulting template""" """Reads the input image, extract the features based on LBP of the fingervein image, and writes the resulting template"""
#For debugging #For debugging
finger_image = image[0] #Normalized image with histogram equalization finger_image = image[0] #Normalized image with histogram equalization
finger_mask = image[1] finger_mask = image[1]
return self.lbp_features(finger_image, finger_mask) return self.lbp_features(finger_image, finger_mask)
def save_feature(self, feature, feature_file): def save_feature(self, feature, feature_file):
f = bob.io.base.HDF5File(feature_file, 'w') f = bob.io.base.HDF5File(feature_file, 'w')
f.set('feature', feature) f.set('feature', feature)
def read_feature(self, feature_file): def read_feature(self, feature_file):
f = bob.io.base.HDF5File(feature_file, 'r') f = bob.io.base.HDF5File(feature_file, 'r')
image = f.read('feature') image = f.read('feature')
return (image) return image
\ No newline at end of file
...@@ -2,25 +2,26 @@ ...@@ -2,25 +2,26 @@
# vim: set fileencoding=utf-8 : # vim: set fileencoding=utf-8 :
# Pedro Tome <Pedro.Tome@idiap.ch> # Pedro Tome <Pedro.Tome@idiap.ch>
import math
import numpy
import bob.core import bob.core
import bob.io.base import bob.io.base
import numpy from bob.bio.base.features.Extractor import Extractor
import math
#from math import pi
#from mumpy import sqrt
import scipy.signal
from facereclib.features.Extractor import Extractor
from .. import utils from .. import utils
class MaximumCurvature (Extractor): class MaximumCurvature (Extractor):
"""MiuraMax feature extractor
"""MiuraMax feature extractor based on
N. Miura, A. Nagasaka, and T. Miyatake, Extraction of Finger-Vein Pattern Using Maximum Curvature Points in Image Profiles. Based on N. Miura, A. Nagasaka, and T. Miyatake, Extraction of Finger-Vein
Proceedings on IAPR conference on machine vision applications, 9 (2005), pp. 347--350 Pattern Using Maximum Curvature Points in Image Profiles. Proceedings on IAPR
conference on machine vision applications, 9 (2005), pp. 347--350
""" """
def __init__( def __init__(
self, self,
sigma = 5, #Sigma used for determining derivatives sigma = 5, #Sigma used for determining derivatives
...@@ -33,65 +34,66 @@ class MaximumCurvature (Extractor): ...@@ -33,65 +34,66 @@ class MaximumCurvature (Extractor):
sigma = sigma, sigma = sigma,
gpu = gpu gpu = gpu
) )
# block parameters # block parameters
self.sigma = sigma self.sigma = sigma
self.gpu = gpu self.gpu = gpu
def maximum_curvature(self, image, mask): def maximum_curvature(self, image, mask):
"""Computes and returns the Maximum Curvature features for the given input fingervein image""" """Computes and returns the Maximum Curvature features for the given input
fingervein image"""
if image.dtype != numpy.uint8: if image.dtype != numpy.uint8:
image = bob.core.convert(image,numpy.uint8,(0,255),(0,1)) image = bob.core.convert(image,numpy.uint8,(0,255),(0,1))
#No es necesario pasarlo a uint8, en matlab lo dejan en float64. Comprobar si varian los resultados en vera database y ajustar. #No es necesario pasarlo a uint8, en matlab lo dejan en float64. Comprobar si varian los resultados en vera database y ajustar.
finger_mask = numpy.zeros(mask.shape) finger_mask = numpy.zeros(mask.shape)
finger_mask[mask == True] = 1 finger_mask[mask == True] = 1
winsize = numpy.ceil(4*self.sigma) winsize = numpy.ceil(4*self.sigma)
x = numpy.arange(-winsize, winsize+1) x = numpy.arange(-winsize, winsize+1)
y = numpy.arange(-winsize, winsize+1) y = numpy.arange(-winsize, winsize+1)
X, Y = numpy.meshgrid(x, y) X, Y = numpy.meshgrid(x, y)
h = (1/(2*math.pi*self.sigma**2))*numpy.exp(-(X**2 + Y**2)/(2*self.sigma**2)) h = (1/(2*math.pi*self.sigma**2))*numpy.exp(-(X**2 + Y**2)/(2*self.sigma**2))
hx = (-X/(self.sigma**2))*h hx = (-X/(self.sigma**2))*h
hxx = ((X**2 - self.sigma**2)/(self.sigma**4))*h hxx = ((X**2 - self.sigma**2)/(self.sigma**4))*h
hy = hx.T hy = hx.T
hyy = hxx.T hyy = hxx.T
hxy = ((X*Y)/(self.sigma**4))*h hxy = ((X*Y)/(self.sigma**4))*h
# Do the actual filtering # Do the actual filtering
fx = utils.imfilter(image, hx, self.gpu, conv=False) fx = utils.imfilter(image, hx, self.gpu, conv=False)
fxx = utils.imfilter(image, hxx, self.gpu, conv=False) fxx = utils.imfilter(image, hxx, self.gpu, conv=False)
fy = utils.imfilter(image, hy, self.gpu, conv=False) fy = utils.imfilter(image, hy, self.gpu, conv=False)
fyy = utils.imfilter(image, hyy, self.gpu, conv=False) fyy = utils.imfilter(image, hyy, self.gpu, conv=False)
fxy = utils.imfilter(image, hxy, self.gpu, conv=False) fxy = utils.imfilter(image, hxy, self.gpu, conv=False)
f1 = 0.5*numpy.sqrt(2)*(fx + fy) # \ # f1 = 0.5*numpy.sqrt(2)*(fx + fy) # \ #
f2 = 0.5*numpy.sqrt(2)*(fx - fy) # / # f2 = 0.5*numpy.sqrt(2)*(fx - fy) # / #
f11 = 0.5*fxx + fxy + 0.5*fyy # \\ # f11 = 0.5*fxx + fxy + 0.5*fyy # \\ #
f22 = 0.5*fxx - fxy + 0.5*fyy # // # f22 = 0.5*fxx - fxy + 0.5*fyy # // #
img_h, img_w = image.shape #Image height and width img_h, img_w = image.shape #Image height and width
# Calculate curvatures # Calculate curvatures
k = numpy.zeros((img_h, img_w, 4)) k = numpy.zeros((img_h, img_w, 4))
k[:,:,0] = (fxx/((1 + fx**2)**(3/2)))*finger_mask # hor # k[:,:,0] = (fxx/((1 + fx**2)**(3/2)))*finger_mask # hor #
k[:,:,1] = (fyy/((1 + fy**2)**(3/2)))*finger_mask # ver # k[:,:,1] = (fyy/((1 + fy**2)**(3/2)))*finger_mask # ver #
k[:,:,2] = (f11/((1 + f1**2)**(3/2)))*finger_mask # \ # k[:,:,2] = (f11/((1 + f1**2)**(3/2)))*finger_mask # \ #
k[:,:,3] = (f22/((1 + f2**2)**(3/2)))*finger_mask # / # k[:,:,3] = (f22/((1 + f2**2)**(3/2)))*finger_mask # / #
# Scores # Scores
Vt = numpy.zeros(image.shape) Vt = numpy.zeros(image.shape)
Wr = 0 Wr = 0
# Horizontal direction # Horizontal direction
bla = k[:,:,0] > 0 bla = k[:,:,0] > 0
for y in range(0,img_h): for y in range(0,img_h):
for x in range(0,img_w): for x in range(0,img_w):
if (bla[y,x]): if (bla[y,x]):
Wr = Wr + 1 Wr = Wr + 1
if ( Wr > 0 and (x == (img_w-1) or not bla[y,x]) ): if ( Wr > 0 and (x == (img_w-1) or not bla[y,x]) ):
...@@ -100,23 +102,23 @@ class MaximumCurvature (Extractor): ...@@ -100,23 +102,23 @@ class MaximumCurvature (Extractor):
pos_end = x pos_end = x
else: else:
pos_end = x - 1 pos_end = x - 1
pos_start = pos_end - Wr + 1 # Start pos of concave pos_start = pos_end - Wr + 1 # Start pos of concave
if (pos_start == pos_end): if (pos_start == pos_end):
I=numpy.argmax(k[y,pos_start,0]) I=numpy.argmax(k[y,pos_start,0])
else: else:
I=numpy.argmax(k[y,pos_start:pos_end+1,0]) I=numpy.argmax(k[y,pos_start:pos_end+1,0])
pos_max = pos_start + I pos_max = pos_start + I
Scr = k[y,pos_max,0]*Wr Scr = k[y,pos_max,0]*Wr
Vt[y,pos_max] = Vt[y,pos_max] + Scr Vt[y,pos_max] = Vt[y,pos_max] + Scr
Wr = 0 Wr = 0
# Vertical direction # Vertical direction
bla = k[:,:,1] > 0 bla = k[:,:,1] > 0
for x in range(0,img_w): for x in range(0,img_w):
for y in range(0,img_h): for y in range(0,img_h):
if (bla[y,x]): if (bla[y,x]):
Wr = Wr + 1 Wr = Wr + 1
if ( Wr > 0 and (y == (img_h-1) or not bla[y,x]) ): if ( Wr > 0 and (y == (img_h-1) or not bla[y,x]) ):
...@@ -124,20 +126,20 @@ class MaximumCurvature (Extractor): ...@@ -124,20 +126,20 @@ class MaximumCurvature (Extractor):
# Reached edge of image # Reached edge of image
pos_end = y pos_end = y
else: else:
pos_end = y - 1 pos_end = y - 1
pos_start = pos_end - Wr + 1 # Start pos of concave pos_start = pos_end - Wr + 1 # Start pos of concave
if (pos_start == pos_end): if (pos_start == pos_end):
I=numpy.argmax(k[pos_start,x,1]) I=numpy.argmax(k[pos_start,x,1])
else: else:
I=numpy.argmax(k[pos_start:pos_end+1,x,1]) I=numpy.argmax(k[pos_start:pos_end+1,x,1])
pos_max = pos_start + I pos_max = pos_start + I
Scr = k[pos_max,x,1]*Wr Scr = k[pos_max,x,1]*Wr
Vt[pos_max,x] = Vt[pos_max,x] + Scr Vt[pos_max,x] = Vt[pos_max,x] + Scr
Wr = 0 Wr = 0
# Direction: \ # # Direction: \ #
bla = k[:,:,2] > 0 bla = k[:,:,2] > 0
for start in range(0,img_w+img_h-1): for start in range(0,img_w+img_h-1):
...@@ -149,11 +151,11 @@ class MaximumCurvature (Extractor): ...@@ -149,11 +151,11 @@ class MaximumCurvature (Extractor):
x = 0 x = 0
y = start - img_w + 1 y = start - img_w + 1
done = False done = False
while (not done): while (not done):
if(bla[y,x]): if(bla[y,x]):
Wr = Wr + 1 Wr = Wr + 1
if ( Wr > 0 and (y == img_h-1 or x == img_w-1 or not bla[y,x]) ): if ( Wr > 0 and (y == img_h-1 or x == img_w-1 or not bla[y,x]) ):
if (y == img_h-1 or x == img_w-1): if (y == img_h-1 or x == img_w-1):
# Reached edge of image # Reached edge of image
...@@ -162,10 +164,10 @@ class MaximumCurvature (Extractor): ...@@ -162,10 +164,10 @@ class MaximumCurvature (Extractor):
else: else:
pos_x_end = x - 1 pos_x_end = x - 1
pos_y_end = y - 1 pos_y_end = y - 1
pos_x_start = pos_x_end - Wr + 1 pos_x_start = pos_x_end - Wr + 1
pos_y_start = pos_y_end - Wr + 1 pos_y_start = pos_y_end - Wr + 1
if (pos_y_start == pos_y_end and pos_x_start == pos_x_end): if (pos_y_start == pos_y_end and pos_x_start == pos_x_end):
d = k[pos_y_start, pos_x_start, 2] d = k[pos_y_start, pos_x_start, 2]
elif (pos_y_start == pos_y_end): elif (pos_y_start == pos_y_end):
...@@ -174,23 +176,23 @@ class MaximumCurvature (Extractor): ...@@ -174,23 +176,23 @@ class MaximumCurvature (Extractor):
d = numpy.diag(k[pos_y_start:pos_y_end+1, pos_x_start, 2]) d = numpy.diag(k[pos_y_start:pos_y_end+1, pos_x_start, 2])
else: else:
d = numpy.diag(k[pos_y_start:pos_y_end+1, pos_x_start:pos_x_end+1, 2]) d = numpy.diag(k[pos_y_start:pos_y_end+1, pos_x_start:pos_x_end+1, 2])
I = numpy.argmax(d) I = numpy.argmax(d)
pos_x_max = pos_x_start + I pos_x_max = pos_x_start + I
pos_y_max = pos_y_start + I pos_y_max = pos_y_start + I
Scr = k[pos_y_max,pos_x_max,2]*Wr Scr = k[pos_y_max,pos_x_max,2]*Wr
Vt[pos_y_max,pos_x_max] = Vt[pos_y_max,pos_x_max] + Scr Vt[pos_y_max,pos_x_max] = Vt[pos_y_max,pos_x_max] + Scr
Wr = 0 Wr = 0
if((x == img_w-1) or (y == img_h-1)): if((x == img_w-1) or (y == img_h-1)):
done = True done = True
else: else:
x = x + 1 x = x + 1
y = y + 1 y = y + 1
# Direction: / # Direction: /
bla = k[:,:,3] > 0 bla = k[:,:,3] > 0
for start in range(0,img_w+img_h-1): for start in range(0,img_w+img_h-1):
...@@ -202,7 +204,7 @@ class MaximumCurvature (Extractor): ...@@ -202,7 +204,7 @@ class MaximumCurvature (Extractor):
x = 0 x = 0
y = img_w+img_h-start-1