From 76b6f099924a9baa61edeb13df1f8ff60371726e Mon Sep 17 00:00:00 2001 From: Manuel Guenther <manuel.guenther@idiap.ch> Date: Fri, 26 Jun 2015 16:48:06 +0200 Subject: [PATCH] Added more documentation --- bob/bio/face/extractor/Eigenface.py | 59 +++++++- bob/bio/face/preprocessor/Base.py | 67 +++++++-- bob/bio/face/preprocessor/FaceCrop.py | 131 +++++++++++++----- bob/bio/face/preprocessor/FaceDetect.py | 91 +++++++++++- .../preprocessor/HistogramEqualization.py | 66 +++++++-- .../face/preprocessor/SelfQuotientImage.py | 46 +++++- bob/bio/face/preprocessor/TanTriggs.py | 57 +++++--- buildout.cfg | 3 + doc/references.rst | 4 - 9 files changed, 425 insertions(+), 99 deletions(-) diff --git a/bob/bio/face/extractor/Eigenface.py b/bob/bio/face/extractor/Eigenface.py index b5464cee..70530db9 100644 --- a/bob/bio/face/extractor/Eigenface.py +++ b/bob/bio/face/extractor/Eigenface.py @@ -13,7 +13,20 @@ import logging logger = logging.getLogger("bob.bio.face") class Eigenface (Extractor): - """Extracts grid graphs from the images""" + """Performs a principal component analysis (PCA) on the given data. + + This algorithm computes a PCA projection (:py:class:`bob.learn.linear.PCATrainer`) on the given training images, and projects the images into face space. + In opposition to :py:class:`bob.bio.base.algorithm.PCA`, here the eigenfces are used as features, i.e., to apply advanced face recognition algorithms on top of them. + + **Parameters:** + + subspace_dimension : int or float + If specified as ``int``, defines the number of eigenvectors used in the PCA projection matrix. + If specified as ``float`` (between 0 and 1), the number of eigenvectors is calculated such that the given percentage of variance is kept. + + kwargs : ``key=value`` pairs + A list of keyword arguments directly passed to the :py:class:`bob.bio.base.extractor.Extractor` base class constructor. + """ def __init__(self, subspace_dimension): # We have to register that this function will need a training step @@ -22,17 +35,29 @@ class Eigenface (Extractor): def _check_data(self, data): + """Checks that the given data are appropriate.""" assert isinstance(data, numpy.ndarray) assert data.ndim == 2 assert data.dtype == numpy.float64 - def train(self, image_list, extractor_file): - """Trains the eigenface extractor using the given list of training images""" - [self._check_data(image) for image in image_list] + def train(self, training_images, extractor_file): + """Generates the PCA covariance matrix and writes it into the given extractor_file. + + Beforehand, all images are turned into a 1D pixel vector. + + **Parameters:** + + training_images : [2D :py:class:`numpy.ndarray`] + A list of 2D training images to train the PCA projection matrix with. + + extractor_file : str + A writable file, into which the PCA projection matrix (as a :py:class:`bob.learn.linear.Machine`) will be written. + """ + [self._check_data(image) for image in training_images] # Initializes an array for the data - data = numpy.vstack([image.flatten() for image in image_list]) + data = numpy.vstack([image.flatten() for image in training_images]) logger.info(" -> Training LinearMachine using PCA (SVD)") t = bob.learn.linear.PCATrainer() @@ -54,12 +79,34 @@ class Eigenface (Extractor): def load(self, extractor_file): + """Reads the PCA projection matrix from file. + + **Parameters:** + + extractor_file : str + An existing file, from which the PCA projection matrix are read. + """ # read PCA projector self.machine = bob.learn.linear.Machine(bob.io.base.HDF5File(extractor_file)) def __call__(self, image): - """Projects the data using the stored covariance matrix""" + """__call__(image) -> feature + + Projects the given image using the stored covariance matrix. + + Beforehand, the image is turned into a 1D pixel vector. + + **Parameters:** + + image : 2D :py:class:`numpy.ndarray` + The image to extract the eigenface feature from. + + **Returns:** + + feature : 1D :py:class:`numpy.ndarray` + The extracted eigenface feature. + """ self._check_data(image) # Projects the data return self.machine(image.flatten()) diff --git a/bob/bio/face/preprocessor/Base.py b/bob/bio/face/preprocessor/Base.py index 109069d0..b743431d 100644 --- a/bob/bio/face/preprocessor/Base.py +++ b/bob/bio/face/preprocessor/Base.py @@ -5,27 +5,39 @@ import bob.ip.color from bob.bio.base.preprocessor import Preprocessor class Base (Preprocessor): - """Performs color space adaptations and data type corrections for the given image""" + """Performs color space adaptations and data type corrections for the given image. - def __init__(self, dtype = None, color_channel = 'gray'): - """Parameters of the constructor of this preprocessor: + **Parameters:** - dtype : :py:class:`numpy.dtype` or convertible or ``None`` - The data type that the resulting image will have + dtype : :py:class:`numpy.dtype` or convertible or ``None`` + The data type that the resulting image will have. - color_channel : one of ``('gray', 'red', 'gren', 'blue')`` or ``None`` - The specific color channel, which should be extracted from the image - """ + color_channel : one of ``('gray', 'red', 'gren', 'blue')`` + The specific color channel, which should be extracted from the image. + """ + + def __init__(self, dtype = None, color_channel = 'gray'): Preprocessor.__init__(self, dtype=str(dtype), color_channel=color_channel) self.channel = color_channel self.dtype = dtype def color_channel(self, image): - """Returns the desired channel of the given image. Currently, gray, red, green and blue channels are supported.""" - if self.channel is None: - return image + """color_channel(image) -> channel + + Returns the channel of the given image, which was selected in the constructor. + Currently, gray, red, green and blue channels are supported. + **Parameters:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The image to get the specified channel from. + + **Returns:** + + channel : 2D :py:class:`numpy.ndarray` + The extracted color channel. + """ if image.ndim == 2: if self.channel != 'gray': raise ValueError("There is no rule to extract a " + channel + " image from a gray level image!") @@ -44,13 +56,44 @@ class Base (Preprocessor): def data_type(self, image): + """data_type(image) -> image + + Converts the given image into the data type specified in the constructor of this class. + If no data type was specified, no conversion is performed. + + **Parameters:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The image to convert. + + **Returns:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The image converted to the desired data type, if any. + """ if self.dtype is not None: image = image.astype(self.dtype) return image def __call__(self, image, annotations = None): - """Just perform gray scale conversion, ignore the annotations.""" + """__call__(image, annotations = None) -> image + + Extracts the desired color channel and converts to the desired data type. + + **Parameters:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The image to preprocess. + + annotations : any + Ignored. + + **Returns:** + + image : 2D :py:class:`numpy.ndarray` + The image converted converted to the desired color channel and type. + """ assert isinstance(image, numpy.ndarray) and image.ndim in (2,3) # convert to grayscale image = self.color_channel(image) diff --git a/bob/bio/face/preprocessor/FaceCrop.py b/bob/bio/face/preprocessor/FaceCrop.py index b474f329..e9e8c799 100644 --- a/bob/bio/face/preprocessor/FaceCrop.py +++ b/bob/bio/face/preprocessor/FaceCrop.py @@ -24,7 +24,63 @@ from .Base import Base from bob.bio.base.preprocessor import Preprocessor class FaceCrop (Base): - """Crops the face according to the given annotations""" + """Crops the face according to the given annotations. + + This class is designed to perform a geometric normalization of the face based on the eye locations, using :py:class:`bob.ip.base.FaceEyesNorm`. + Usually, when executing the :py:meth:`crop_face` function, the image and the eye locations have to be specified. + There, the given image will be transformed such that the eye locations will be placed at specific locations in the resulting image. + These locations, as well as the size of the cropped image, need to be specified in the constructor of this class, as ``cropped_positions`` and ``cropped_image_size``. + + Some image databases do not provide eye locations, but rather bounding boxes. + This is not a problem at all. + Simply define the coordinates, where you want your ``cropped_positions`` to be in the cropped image, by specifying the same keys in the dictionary that will be given as ``annotations`` to the :py:meth:`face_crop` function. + + .. note;:: + These locations can even be outside of the cropped image boundary, i.e., when the crop should be smaller than the annotated bounding boxes. + + Sometimes, databases provide pre-cropped faces, where the eyes are located at (almost) the same position in all images. + Usually, the cropping does not conform with the cropping that you like (i.e., image resolution is wrong, or too much background information). + However, the database does not provide eye locations (since they are almost identical for all images). + In that case, you can specify the ``fixed_positions`` in the constructor, which will be taken instead of the ``annotations`` inside the :py:meth:`crop_face` function (in which case the ``annotations`` are ignored). + + Sometimes, the crop of the face is outside of the original image boundaries. + Usually, these pixels will simply be left black, resulting in sharp edges in the image. + However, some feature extractors do not like these sharp edges. + In this case, you can set the ``mask_sigma`` to copy pixels from the valid border of the image and add random noise (see :py:func:`bob.ip.base.extrapolate_mask`). + + + **Parameters:** + + cropped_image_size : (int, int) + The size of the resulting cropped images. + + cropped_positions : dict + The coordinates in the cropped image, where the annotated points should be put to. + This parameter is a dictionary with usually two elements, e.g., ``{'reye':(RIGHT_EYE_Y, RIGHT_EYE_X) , 'leye':(LEFT_EYE_Y, LEFT_EYE_X)}``. + However, also other parameters, such as ``{'topleft' : ..., 'bottomright' : ...}`` are supported, as long as the ``annotations`` in the :py:meth:`__call__` function are present. + + fixed_positions : dict or None + If specified, ignore the annotations from the database and use these fixed positions throughout. + + mask_sigma : float or None + Fill the area outside of image boundaries with random pixels from the border, by adding noise to the pixel values. + To disable extrapolation, set this value to ``None``. + To disable adding random noise, set it to a negative value or 0. + + mask_neighbors : int + The number of neighbors used during mask extrapolation. + See :py:func:`bob.ip.base.extrapolate_mask` for details. + + mask_seed : int or None + The random seed to apply for mask extrapolation. + + .. warning:: + When run in parallel, the same random seed will be applied to all parallel processes. + Hence, results of parallel execution will differ from the results in serial execution. + + kwargs + Remaining keyword parameters passed to the :py:class:`Base` constructor, such as ``color_channel`` or ``dtype``. + """ def __init__( self, @@ -36,38 +92,6 @@ class FaceCrop (Base): mask_seed = None, # The seed for generating random values during extrapolation **kwargs # parameters to be written in the __str__ method ): - """Parameters of the constructor of this preprocessor: - - cropped_image_size : (int, int) - The size of the resulting cropped images. - - cropped_positions : dict - The coordinates in the cropped image, where the annotated points should be put to. - This parameter is a dictionary with usually two elements, e.g., ``{'reye':(RIGHT_EYE_Y, RIGHT_EYE_X) , 'leye':(LEFT_EYE_Y, LEFT_EYE_X)}``. - However, also other parameters, such as ``{'topleft' : ..., 'bottomright' : ...}`` are supported, as long as the ``annotations`` in the :py:meth:`__call__` function are present. - - fixed_positions : dict or None - If specified, ignore the annotations from the database and use these fixed positions throughout. - - mask_sigma : float or None - Fill the area outside of image boundaries with random pixels from the border, by adding noise to the pixel values. - To disable extrapolation, set this value to None. - To disable adding random noise, set it to a negative value or 0. - - mask_neighbors : int - The number of neighbors used during mask extrapolation. - See :py:func:`bob.ip.base.extrapolate_mask` for details. - - mask_seed : int or None - The random seed to apply for mask extrapolation. - - .. warning:: - When run in parallel, the same random seed will be applied to all parallel processes. - Hence, results of parallel execution will differ from the results in serial execution. - - kwargs - Remaining keyword parameters passed to the :py:class:`Base` constructor, such as ``color_channel`` or ``dtype``. - """ Base.__init__(self, **kwargs) @@ -102,7 +126,24 @@ class FaceCrop (Base): def crop_face(self, image, annotations = None): - """Executes the face cropping on the given image and returns the cropped version of it""" + """crop_face(image, annotations = None) -> face + + Executes the face cropping on the given image and returns the cropped version of it. + + **Parameters:** + + image : 2D :py:class:`numpy.ndarray` + The face image to be processed. + + annotations : dict or ``None`` + The annotations that fit to the given image. + ``None`` is only accepted, when ``fixed_positions`` were specified in the constructor. + + **Returns:** + + face : 2D :py:class:`numpy.ndarray` (float) + The cropped face. + """ if self.fixed_positions is not None: annotations = self.fixed_positions if annotations is None: @@ -135,7 +176,27 @@ class FaceCrop (Base): def __call__(self, image, annotations = None): - """Aligns the given image according to the given annotations.""" + """__call__(image, annotations = None) -> face + + Aligns the given image according to the given annotations. + + First, the desired color channel is extracted from the given image. + Afterward, the face is cropped, according to the given ``annotations`` (or to ``fixed_positions``, see :py:meth:`crop_face`). + Finally, the resulting face is converted to the desired data type. + + **Parameters:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The face image to be processed. + + annotations : dict or ``None`` + The annotations that fit to the given image. + + **Returns:** + + face : 2D :py:class:`numpy.ndarray` + The cropped face. + """ # convert to the desired color channel image = self.color_channel(image) # crop face diff --git a/bob/bio/face/preprocessor/FaceDetect.py b/bob/bio/face/preprocessor/FaceDetect.py index 76e959d6..3e8422cb 100644 --- a/bob/bio/face/preprocessor/FaceDetect.py +++ b/bob/bio/face/preprocessor/FaceDetect.py @@ -15,6 +15,53 @@ import logging logger = logging.getLogger("bob.bio.face") class FaceDetect (Base): + """Performs a face detection (and facial landmark localization) in the given image and crops the face. + + This class is designed to perform a geometric normalization of the face based on the detected face. + Face detection is performed using :ref:`bob.ip.facedetect <bob.ip.facedetect>`. + Particularly, the function :py:func:`bob.ip.facedetect.detect_single_face` is executed, which will *always* return *exactly one* bounding box, even if the image contains more than one face, or no face at all. + The speed of the face detector can be regulated using the ``cascade``, ``distance` ``scale_base`` and ``lowest_scale`` parameters. + The number of overlapping detected bounding boxes that should be joined can be selected by ``detection_overlap``. + Please see the documentation of :ref:`bob.ip.facedetect <bob.ip.facedetect>` for more details about these parameters. + + Additionally, facial landmarks can be detected using the :ref:`bob.ip.flandmark`. + If enabled using ``use_flandmark = True`` in the constructor, it is tried to obtain the facial landmarks inside the detected facial area. + If landmarks are found, these are used to geometrically normalize the face. + Otherwise, the eye locations are estimated based on the bounding box. + This is also applied, when ``use_flandmark = False.`` + + The face cropping itself is done by the given ``face_cropper``. + This cropper can either be an instance of :py:class:`FaceCrop` (or any other class that provides a similar ``crop_face`` function), or it can be the resource name of a face cropper, such as ``'face-crop-eyes'``. + + **Parameters:** + + face_cropper : :py:class:`bob.bio.face.preprocessor.FaceCrop` or str + The face cropper to be used to crop the detected face. + Might be an instance of a :py:class:`FaceCrop` or the name of a face cropper resource. + + cascade : str or ``None`` + The file name, where a face detector cascade can be found. + If ``None``, the default cascade for frontal faces :py:func:`bob.ip.facedetect.default_cascade` is used. + + use_flandmark : bool + If selected, :py:class:`bob.ip.flandmark.Flandmark` is used to detect the eye locations. + Otherwise, the eye locations are estimated based on the detected bounding box. + + detection_overlap : float + See :py:func:`bob.ip.facedetect.detect_single_face`. + + distance : int + See the Sampling section in the :ref:`Users Guide of bob.ip.facedetect <bob.ip.facedetect>`. + + scale_base : float + See the Sampling section in the :ref:`Users Guide of bob.ip.facedetect <bob.ip.facedetect>`. + + lowest_scale : float + See the Sampling section in the :ref:`Users Guide of bob.ip.facedetect <bob.ip.facedetect>`. + + kwargs + Remaining keyword parameters passed to the :py:class:`Base` constructor, such as ``color_channel`` or ``dtype``. + """ def __init__( self, @@ -25,12 +72,8 @@ class FaceDetect (Base): distance = 2, scale_base = math.pow(2., -1./16.), lowest_scale = 0.125, - mask_sigma = None, # The sigma for random values areas outside image - mask_neighbors = 5, # The number of neighbors to consider while extrapolating - mask_seed = None, # The seed for generating random values during extrapolation **kwargs ): - """Performs a face detection in the given image (ignoring any annotations).""" # call base class constructors Base.__init__(self, **kwargs) @@ -60,6 +103,7 @@ class FaceDetect (Base): def _landmarks(self, image, bounding_box): + """Try to detect the landmarks in the given bounding box, and return the eye locations.""" # get the landmarks in the face if self.flandmark is not None: # use the flandmark detector @@ -86,6 +130,23 @@ class FaceDetect (Base): def crop_face(self, image, annotations=None): + """crop_face(image, annotations = None) -> face + + Detects the face (and facial landmarks), and used the ``face_cropper`` given in the constructor to crop the face. + + **Parameters:** + + image : 2D :py:class:`numpy.ndarray` + The face image to be processed. + + annotations : any + Ignored. + + **Returns:** + + face : 2D :py:class:`numpy.ndarray` (float) + The detected and cropped face. + """ # detect the face bounding_box, self.quality = bob.ip.facedetect.detect_single_face(image, self.cascade, self.sampler, self.detection_overlap) @@ -96,8 +157,28 @@ class FaceDetect (Base): return self.cropper.crop_face(image, annotations) - def __call__(self, image, annotations=None): + """__call__(image, annotations = None) -> face + + Aligns the given image according to the detected face bounding box or the detected facial features. + + First, the desired color channel is extracted from the given image. + Afterward, the face is detected and cropped, see :py:meth:`crop_face`. + Finally, the resulting face is converted to the desired data type. + + **Parameters:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The face image to be processed. + + annotations : any + Ignored. + + **Returns:** + + face : 2D :py:class:`numpy.ndarray` + The cropped face. + """ # convert to the desired color channel image = self.color_channel(image) diff --git a/bob/bio/face/preprocessor/HistogramEqualization.py b/bob/bio/face/preprocessor/HistogramEqualization.py index 84cebf99..ac05968f 100644 --- a/bob/bio/face/preprocessor/HistogramEqualization.py +++ b/bob/bio/face/preprocessor/HistogramEqualization.py @@ -25,24 +25,26 @@ from .utils import load_cropper from bob.bio.base.preprocessor import Preprocessor class HistogramEqualization (Base): - """Crops the face according to the eye positions (if given), and performs histogram equalization on the resulting image""" + """Crops the face (if desired) and performs histogram equalization to photometrically enhance the image. + + **Parameters:** + + face_cropper : str or :py:class:`bob.bio.face.preprocessor.FaceCrop` or :py:class:`bob.bio.face.preprocessor.FaceDetect` or ``None`` + The face image cropper that should be applied to the image. + If ``None`` is selected, no face cropping is performed. + Otherwise, the face cropper might be specified as a registered resource, a configuration file, or an instance of a preprocessor. + + .. note:: The given class needs to contain a ``crop_face`` method. + + kwargs + Remaining keyword parameters passed to the :py:class:`Base` constructor, such as ``color_channel`` or ``dtype``. + """ def __init__( self, face_cropper, **kwargs ): - """Parameters of the constructor of this preprocessor: - - face_cropper : str or `bob.bio.face.preprocessor.FaceCrop` or `bob.bio.face.preprocessor.FaceDetect` - The face image cropper that should be applied to the image. - It might be specified as a registered resource, a configuration file, or an instance of a preprocessor. - - .. note:: The given class needs to contain a ``crop_face`` method. - - kwargs - Remaining keyword parameters passed to the :py:class:`Base` constructor, such as ``color_channel`` or ``dtype``. - """ Base.__init__(self, **kwargs) @@ -56,14 +58,50 @@ class HistogramEqualization (Base): def equalize_histogram(self, image): - """Performs the histogram equalization""" + """equalize_histogram(image) -> equalized + + Performs the histogram equalization on the given image. + + **Parameters:** + + image : 2D :py:class:`numpy.ndarray` + The image to berform histogram equalization with. + The image will be transformed to type ``uint8`` before computing the histogram. + + **Returns:** + + equalized : 2D :py:class:`numpy.ndarray` (float) + The photometrically enhanced image. + """ heq = numpy.ndarray(image.shape) bob.ip.base.histogram_equalization(numpy.round(image).astype(numpy.uint8), heq) return heq def __call__(self, image, annotations = None): - """Crops the face using the specified face cropper and performs Histogram Equalization preprocessing.""" + """__call__(image, annotations = None) -> face + + Aligns the given image according to the given annotations. + + First, the desired color channel is extracted from the given image. + Afterward, the face is eventually cropped using the ``face_cropper`` specified in the constructor. + Then, the image is photometrically enhanced using histogram equalization. + Finally, the resulting face is converted to the desired data type. + + **Parameters:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The face image to be processed. + + annotations : dict or ``None`` + The annotations that fit to the given image. + Might be ``None``, when the ``face_cropper`` is ``None`` or of type :py:class:`FaceDetect`. + + **Returns:** + + face : 2D :py:class:`numpy.ndarray` + The cropped and photometrically enhanced face. + """ image = self.color_channel(image) if self.cropper is not None: image = self.cropper.crop_face(image, annotations) diff --git a/bob/bio/face/preprocessor/SelfQuotientImage.py b/bob/bio/face/preprocessor/SelfQuotientImage.py index 20ab2c05..5fc84359 100644 --- a/bob/bio/face/preprocessor/SelfQuotientImage.py +++ b/bob/bio/face/preprocessor/SelfQuotientImage.py @@ -26,7 +26,23 @@ from .utils import load_cropper from bob.bio.base.preprocessor import Preprocessor class SelfQuotientImage (Base): - """Crops the face according to the eye positions (if given), computes the self quotient image.""" + """Crops the face (if desired) and applies self quotient image algorithm [WLW04]_ to photometrically enhance the image. + + **Parameters:** + + face_cropper : str or :py:class:`bob.bio.face.preprocessor.FaceCrop` or :py:class:`bob.bio.face.preprocessor.FaceDetect` or ``None`` + The face image cropper that should be applied to the image. + If ``None`` is selected, no face cropping is performed. + Otherwise, the face cropper might be specified as a registered resource, a configuration file, or an instance of a preprocessor. + + .. note:: The given class needs to contain a ``crop_face`` method. + + sigma : float + Please refer to the [WLW04]_ original paper (see :py:class:`bob.ip.base.SelfQuotientImage` documentation). + + kwargs + Remaining keyword parameters passed to the :py:class:`Base` constructor, such as ``color_channel`` or ``dtype``. + """ def __init__( self, @@ -47,15 +63,33 @@ class SelfQuotientImage (Base): self.cropper = load_cropper(face_cropper) size = max(1, int(3. * sigma)) - self.sqi = bob.ip.base.SelfQuotientImage(size_min = size, sigma = sigma) + self.self_quotient = bob.ip.base.SelfQuotientImage(size_min = size, sigma = sigma) + + def __call__(self, image, annotations = None): + """__call__(image, annotations = None) -> face - def self_quotient(self, image): - return self.sqi(image) + Aligns the given image according to the given annotations. + First, the desired color channel is extracted from the given image. + Afterward, the face is eventually cropped using the ``face_cropper`` specified in the constructor. + Then, the image is photometrically enhanced using the self quotient image algorithm [WLW04]_. + Finally, the resulting face is converted to the desired data type. - def __call__(self, image, annotations = None): - """Crops the face using the specified face cropper and performs Self-Quotient Image preprocessing.""" + **Parameters:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The face image to be processed. + + annotations : dict or ``None`` + The annotations that fit to the given image. + Might be ``None``, when the ``face_cropper`` is ``None`` or of type :py:class:`FaceDetect`. + + **Returns:** + + face : 2D :py:class:`numpy.ndarray` + The cropped and photometrically enhanced face. + """ image = self.color_channel(image) if self.cropper is not None: image = self.cropper.crop_face(image, annotations) diff --git a/bob/bio/face/preprocessor/TanTriggs.py b/bob/bio/face/preprocessor/TanTriggs.py index 2a9e594d..84b97e5b 100644 --- a/bob/bio/face/preprocessor/TanTriggs.py +++ b/bob/bio/face/preprocessor/TanTriggs.py @@ -25,7 +25,23 @@ from .utils import load_cropper from bob.bio.base.preprocessor import Preprocessor class TanTriggs (Base): - """Crops the face (if desired) and applies Tan&Triggs algorithm""" + """Crops the face (if desired) and applies Tan&Triggs algorithm [TT10]_ to photometrically enhance the image. + + **Parameters:** + + face_cropper : str or :py:class:`bob.bio.face.preprocessor.FaceCrop` or :py:class:`bob.bio.face.preprocessor.FaceDetect` or ``None`` + The face image cropper that should be applied to the image. + If ``None`` is selected, no face cropping is performed. + Otherwise, the face cropper might be specified as a registered resource, a configuration file, or an instance of a preprocessor. + + .. note:: The given class needs to contain a ``crop_face`` method. + + gamma, sigma0, sigma1, size, threshold, alpha + Please refer to the [TT10]_ original paper (see :py:class:`bob.ip.base.TanTriggs` documentation). + + kwargs + Remaining keyword parameters passed to the :py:class:`Base` constructor, such as ``color_channel`` or ``dtype``. + """ def __init__( self, @@ -39,21 +55,6 @@ class TanTriggs (Base): **kwargs ): - """Parameters of the constructor of this preprocessor: - - cropper : str or `bob.bio.face.preprocessor.FaceCrop` or `bob.bio.face.preprocessor.FaceDetect` - The face image cropper that should be applied to the image. - It might be specified as a registered resource, a configuration file, or an instance of a preprocessor. - - .. note:: The given class needs to contain a ``crop_face`` method. - - gamma, sigma0, sigma1, size, threshold, alpha - Please refer to the [TT10]_ original paper (see :py:func:`bob.ip.base.TanTriggs` documentation). - - kwargs - Remaining keyword parameters passed to the :py:class:`Base` constructor, such as ``color_channel`` or ``dtype``. - """ - Base.__init__(self, **kwargs) # call base class constructor with its set of parameters @@ -73,7 +74,29 @@ class TanTriggs (Base): def __call__(self, image, annotations = None): - """Crops the face using the specified face cropper and performs Tan&Triggs preprocessing.""" + """__call__(image, annotations = None) -> face + + Aligns the given image according to the given annotations. + + First, the desired color channel is extracted from the given image. + Afterward, the face is eventually cropped using the ``face_cropper`` specified in the constructor. + Then, the image is photometrically enhanced using the Tan&Triggs algorithm [TT10]_. + Finally, the resulting face is converted to the desired data type. + + **Parameters:** + + image : 2D or 3D :py:class:`numpy.ndarray` + The face image to be processed. + + annotations : dict or ``None`` + The annotations that fit to the given image. + Might be ``None``, when the ``face_cropper`` is ``None`` or of type :py:class:`FaceDetect`. + + **Returns:** + + face : 2D :py:class:`numpy.ndarray` + The cropped and photometrically enhanced face. + """ image = self.color_channel(image) if self.cropper is not None: image = self.cropper.crop_face(image, annotations) diff --git a/buildout.cfg b/buildout.cfg index 492af341..e49506f0 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -23,7 +23,9 @@ extensions = bob.buildout auto-checkout = * develop = src/bob.bio.base src/bob.bio.gmm + src/bob.db.frgc . + ; options for bob.buildout debug = false @@ -33,6 +35,7 @@ newest = false [sources] bob.bio.base = git https://github.com/bioidiap/bob.bio.base bob.bio.gmm = git https://github.com/bioidiap/bob.bio.gmm +bob.db.frgc = git https://github.com/bioidiap/bob.db.frgc [scripts] diff --git a/doc/references.rst b/doc/references.rst index c9243106..71072ec8 100644 --- a/doc/references.rst +++ b/doc/references.rst @@ -15,7 +15,6 @@ References .. [WMM+11] *R. Wallace, M. McLaren, C. McCool and S. Marcel*. **Inter-session variability modelling and joint factor analysis for face authentication**. International Joint Conference on Biometrics. 2011. .. [Pri07] *S. J. D. Prince*. **Probabilistic linear discriminant analysis for inferences about identity**. Proceedings of the International Conference on Computer Vision. 2007. .. [ESM+13] *L. El Shafey, Chris McCool, Roy Wallace and Sébastien Marcel*. **A scalable formulation of probabilistic linear discriminant analysis: applied to face recognition**. IEEE Transactions on Pattern Analysis and Machine Intelligence, 35(7):1788-1794, 7/2013. -.. [MWP98] *B. Moghaddam, W. Wahid and A. Pentland*. **Beyond eigenfaces: probabilistic matching for face recognition**. IEEE International Conference on Automatic Face and Gesture Recognition, pages 30-35. 1998. .. [WM12] *R. Wallace and M. McLaren*. **Total variability modelling for face verification**. IET Biometrics, vol.1, no.4, 188-199, 12/2012 @@ -28,6 +27,3 @@ References .. [GW09] *M. Günther and R.P. Würtz*. **Face detection and recognition using maximum likelihood classifiers on Gabor graphs**. International Journal of Pattern Recognition and Artificial Intelligence, 23(3):433-461, 2009. .. [GWM12] *M. Günther, R. Wallace and S. Marcel*. **An Open Source Framework for Standardized Comparisons of Face Recognition Algorithms**. Computer Vision - ECCV 2012. Workshops and Demonstrations, LNCS, 7585, 547-556, 2012. - -.. [PBD+11] *P.J. Phillips, J.R. Beveridge, B.A. Draper, G. Givens, A.J. O'Toole, D.S. Bolme, J. Dunlop, Y.M. Lui, H. Sahibzada and S. Weimer*. **An introduction to the Good, the Bad, & the Ugly face recognition challenge problem**. Automatic Face Gesture Recognition and Workshops (FG 2011), pages 346-353. 2011. -.. [LBP+12] *Y.M. Lui, D.S. Bolme, P.J. Phillips, J.R. Beveridge and B.A. Draper*. **Preliminary studies on the Good, the Bad, and the Ugly face recognition challenge problem**. Computer Vision and Pattern Recognition Workshops (CVPRW), pages 9-16. 2012. -- GitLab