diff --git a/README.rst b/README.rst index 4953eea235e76c106a8a197c981349960010821e..a069354015bc8429cbcbcf14af891e33ececf0d2 100644 --- a/README.rst +++ b/README.rst @@ -21,6 +21,8 @@ Run face recognition algorithms ================================= +This package is part of the ``bob.bio`` packages, which allow to run comparable and reproducible biometric recognition experiments on publicly available databases. + This package contains functionality to run face recognition experiments. It is an extension to the `bob.bio.base <http://pypi.python.org/pypi/bob.bio.base>`_ package, which provides the basic scripts. In this package, utilities that are specific for face recognition are contained, such as: diff --git a/bob/bio/face/algorithm/LGBPHS.py b/bob/bio/face/algorithm/Histogram.py similarity index 99% rename from bob/bio/face/algorithm/LGBPHS.py rename to bob/bio/face/algorithm/Histogram.py index 9d060987bc59e15ed50aa6b2c3598bc9817e1874..01399c552a70c97ae4ae9f705ee4576445cdbe01 100644 --- a/bob/bio/face/algorithm/LGBPHS.py +++ b/bob/bio/face/algorithm/Histogram.py @@ -8,7 +8,7 @@ import numpy from bob.bio.base.algorithm import Algorithm -class LGBPHS (Algorithm): +class Histogram (Algorithm): """Tool chain for computing local Gabor binary pattern histogram sequences""" def __init__( diff --git a/bob/bio/face/algorithm/__init__.py b/bob/bio/face/algorithm/__init__.py index ae17f3c05fd46ab2d70b5ced7560ec967704b9a7..6f36b2ed5ba29005db230d148343ea359b0b7511 100644 --- a/bob/bio/face/algorithm/__init__.py +++ b/bob/bio/face/algorithm/__init__.py @@ -1,5 +1,5 @@ from .GaborJet import GaborJet -from .LGBPHS import LGBPHS +from .Histogram import Histogram # gets sphinx autodoc done right - don't remove it __all__ = [_ for _ in dir() if not _.startswith('_')] diff --git a/bob/bio/face/config/algorithm/lgbphs.py b/bob/bio/face/config/algorithm/histogram.py similarity index 76% rename from bob/bio/face/config/algorithm/lgbphs.py rename to bob/bio/face/config/algorithm/histogram.py index 635647ac09c0c3968d624e6ab8dad3c7ee2b9c34..ef961bd5055b06e5e76fc2f7fddfe4aa6c70ef33 100644 --- a/bob/bio/face/config/algorithm/lgbphs.py +++ b/bob/bio/face/config/algorithm/histogram.py @@ -3,7 +3,7 @@ import bob.bio.face import bob.math -algorithm = bob.bio.face.algorithm.LGBPHS( +algorithm = bob.bio.face.algorithm.Histogram( distance_function = bob.math.histogram_intersection, is_distance_function = False ) diff --git a/bob/bio/face/config/extractor/lgbphs.py b/bob/bio/face/config/extractor/lgbphs.py index f4f6e9f2595d951dd86807a779463b90d96483c8..c6d5108142d9e3c8373957d3085b617de7a4497c 100644 --- a/bob/bio/face/config/extractor/lgbphs.py +++ b/bob/bio/face/config/extractor/lgbphs.py @@ -6,8 +6,8 @@ import math # feature extraction extractor = bob.bio.face.extractor.LGBPHS( # block setup - block_size = 10, - block_overlap = 4, + block_size = 8, + block_overlap = 0, # Gabor parameters gabor_sigma = math.sqrt(2.) * math.pi, # LBP setup (we use the defaults) diff --git a/bob/bio/face/script/baselines.py b/bob/bio/face/script/baselines.py index 0358684e47700b9d353bb617bc6ca0f249cb41b7..a112252e0b9511b3fed715c1ff7d82e7eb5d0693 100755 --- a/bob/bio/face/script/baselines.py +++ b/bob/bio/face/script/baselines.py @@ -123,7 +123,7 @@ CONFIGURATIONS = { 'lgbphs': dict( preprocessor = ('tan-triggs-crop', 'tan-triggs'), extractor = 'lgbphs', - algorithm = 'lgbphs', + algorithm = 'histogram', ), 'bic': dict( diff --git a/bob/bio/face/test/test_algorithms.py b/bob/bio/face/test/test_algorithms.py index 180315f69705b9918b7d252e413fc7f23e185a9a..5874af5d63b4684371fb6559e6c21b83537032fe 100644 --- a/bob/bio/face/test/test_algorithms.py +++ b/bob/bio/face/test/test_algorithms.py @@ -77,37 +77,37 @@ def test_gabor_jet(): assert abs(jets.score_for_multiple_probes(model, [feature, feature]) - 1.) < 1e-8 -def test_lgbphs(): - lgbphs = bob.bio.base.load_resource("lgbphs", "algorithm") - assert isinstance(lgbphs, bob.bio.face.algorithm.LGBPHS) - assert isinstance(lgbphs, bob.bio.base.algorithm.Algorithm) - assert not lgbphs.performs_projection - assert not lgbphs.requires_projector_training - assert not lgbphs.use_projected_features_for_enrollment - assert not lgbphs.split_training_features_by_client - assert not lgbphs.requires_enroller_training +def test_histogram(): + histogram = bob.bio.base.load_resource("histogram", "algorithm") + assert isinstance(histogram, bob.bio.face.algorithm.Histogram) + assert isinstance(histogram, bob.bio.base.algorithm.Algorithm) + assert not histogram.performs_projection + assert not histogram.requires_projector_training + assert not histogram.use_projected_features_for_enrollment + assert not histogram.split_training_features_by_client + assert not histogram.requires_enroller_training # read input feature1 = bob.bio.base.load(pkg_resources.resource_filename('bob.bio.face.test', 'data/lgbphs_sparse.hdf5')) feature2 = bob.bio.base.load(pkg_resources.resource_filename('bob.bio.face.test', 'data/lgbphs_with_phase.hdf5')) # enroll model from sparse features - model1 = lgbphs.enroll([feature1, feature1]) + model1 = histogram.enroll([feature1, feature1]) assert model1.shape == feature1.shape assert numpy.allclose(model1, feature1) # enroll from non-sparse features - model2 = lgbphs.enroll([feature2, feature2]) + model2 = histogram.enroll([feature2, feature2]) assert model2.shape == feature2.shape assert numpy.allclose(model2, feature2) # score without phase and sparse reference = 40960. - assert abs(lgbphs.score(model1, feature1) - reference) < 1e-5 - assert abs(lgbphs.score_for_multiple_probes(model1, [feature1, feature1]) - reference) < 1e-5 + assert abs(histogram.score(model1, feature1) - reference) < 1e-5 + assert abs(histogram.score_for_multiple_probes(model1, [feature1, feature1]) - reference) < 1e-5 # score with phase, but non-sparse # reference doubles since we have two times more features reference *= 2. - assert abs(lgbphs.score(model2, feature2) - reference) < 1e-5 - assert abs(lgbphs.score_for_multiple_probes(model2, [feature2, feature2]) - reference) < 1e-5 + assert abs(histogram.score(model2, feature2) - reference) < 1e-5 + assert abs(histogram.score_for_multiple_probes(model2, [feature2, feature2]) - reference) < 1e-5 diff --git a/doc/baselines.rst b/doc/baselines.rst index 97fc3a83f611b7119ed30f0452f50204503f16db..a40d06b527fb650b9e46193f44ddd1996501fbb0 100644 --- a/doc/baselines.rst +++ b/doc/baselines.rst @@ -2,7 +2,7 @@ .. author: Manuel Günther <manuel.guenther@idiap.ch> .. date: Thu Sep 20 11:58:57 CEST 2012 -.. _baselines: +.. _bob.bio.face.baselines: ============================= Executing Baseline Algorithms @@ -140,17 +140,17 @@ Additionally, the following algorithms can be executed, when the :ref:`bob.bio.c - feature : :py:class:`bob.bio.csu.extractor.LRPCA` - algorithm : :py:class:`bob.bio.csu.algorithm.LRPCA` -* ``lda_ir``: The LDA-IR (a.k.a. CohortLDA [LBP+12]_) extracts color information from images after, and computes a PCA+LDA projection on two color layers. +* ``lda-ir``: The LDA-IR (a.k.a. CohortLDA [LBP+12]_) extracts color information from images after, and computes a PCA+LDA projection on two color layers. - preprocessor : :py:class:`bob.bio.csu.preprocessor.LDAIR` - feature : :py:class:`bob.bio.csu.extractor.LDAIR` - algorithm : :py:class:`bob.bio.csu.algorithm.LDAIR` .. note:: - The ``lrpca`` and ``ldair`` algorithms require hand-labeled eye locations. + The ``lrpca`` and ``lda-ir`` algorithms require hand-labeled eye locations. Therefore, they can not be run on the default ``atnt`` database. -.. _baseline_results: +.. _bob.bio.base.baseline_results: Baseline Results ---------------- @@ -183,12 +183,15 @@ For the `AT&T database`_ the results should be as follows: +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+ | eigenface | lda | gaborgraph | lgbphs | gmm | isv | plda | bic | +=============+=============+=============+=============+=============+=============+=============+=============+ - | 8.368% | 9.763% | 4.579% | 8.500% | 1.237% | 0.053% | 7.921% | 3.526% | + | 8.368% | 9.763% | 4.579% | 8.500% | 0.684% | 0.421% | 7.921% | 3.526% | +-------------+-------------+-------------+-------------+-------------+-------------+-------------+-------------+ +.. note:: + The results for ``gmm`` and ``isv`` were run with the parallelized scripts. + Though the results obtained with the sequential script should be similar, it might be that they are not identical. .. note:: - The ``lrpca`` and ``lda_ir`` algorithms require hand-labeled eye positions to run. + The ``lrpca`` and ``lda-ir`` algorithms require hand-labeled eye positions to run. Since the AT&T database does not provide eye positions, it is not possible to provide baseline results on AT&T for these two algorithms. .. include:: links.rst diff --git a/doc/conf.py b/doc/conf.py index 87fe2b217d1e905d4c76ac5b7c9aec5ae375d5ad..8e77047f112e0b780f2050050e2867a8b742f283 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -246,8 +246,14 @@ autodoc_default_flags = ['members', 'undoc-members', 'inherited-members', 'show- # For inter-documentation mapping: from bob.extension.utils import link_documentation -intersphinx_mapping = link_documentation(['python', 'numpy', 'bob.bio.gmm', 'bob.bio.csu']) +intersphinx_mapping = link_documentation(['python', 'numpy', 'bob.bio.gmm', 'bob.bio.csu', 'bob.db.lfw']) +def skip(app, what, name, obj, skip, options): + # Do not skip the __call__ function as we have special implementations for them. + if name in ("__call__"): + return False + return skip + def setup(app): - pass + app.connect("autodoc-skip-member", skip) diff --git a/doc/img/CMC.png b/doc/img/CMC.png index 4adf6a233298de74b96cfeaa2c17d88ae49de7e7..040e374242919317a45daa1994f359acdf48dcff 100644 Binary files a/doc/img/CMC.png and b/doc/img/CMC.png differ diff --git a/doc/img/DET.png b/doc/img/DET.png index f8ef499c16c3c13b8f44073aae17727776b41371..e0732263822c3b480b6c35f32a002a1c42e7cf6a 100644 Binary files a/doc/img/DET.png and b/doc/img/DET.png differ diff --git a/doc/img/ROC.png b/doc/img/ROC.png index 10825c3117f34bc8b78b174f28701e8b691ae902..fbb17b175ad6cc730a75fa895d9d036ce9cc0aac 100644 Binary files a/doc/img/ROC.png and b/doc/img/ROC.png differ diff --git a/doc/implementation.rst b/doc/implementation.rst index 76d9d4b74bd14353689f6ca6f70eb1f094ee0e8a..aad0c60f97c1a9b555a28b6029ad477d30db72f5 100644 --- a/doc/implementation.rst +++ b/doc/implementation.rst @@ -133,7 +133,7 @@ Here is the list of files and replacement strings for all databases that are reg - Images (taken from MBGC-V1): ``[YOUR_MBGC-V1_DIRECTORY]`` -* Labeled Faces in the Wild (LFW): ``'lfw-restricted'``, `'lfw-unrestricted'`` +* Labeled Faces in the Wild (LFW): ``'lfw-restricted'``, ``'lfw-unrestricted'`` - Images (aligned with funneling): ``[YOUR_LFW_FUNNELED_DIRECTORY]`` @@ -170,7 +170,7 @@ Preprocessors ~~~~~~~~~~~~~ Photometric enhancement algorithms are -- by default -- registered without face cropping, as ``'base'`` (no enhancement), ``'histogram'`` (histogram equalization), ``'tan-triggs'``, ``'self-quotient'`` (self quotient image) and ``'inorm-lbp'``. -These resources should only be used, when original images are already cropped (such as in the `AT&T database`_. +These resources should only be used, when original images are already cropped (such as in the `AT&T database`_). The default face cropping is performed by aligning the eye locations such that the eyes (in subject perspective) are located at: right eye: ``(16, 15)``, left eye: ``(16, 48)``, and the image is cropped to resolution ``(80, 64)`` pixels. This cropper is registered under the resource key ``'face-crop-eyes'``. @@ -192,6 +192,19 @@ Only four types of features are registered as resources here: * ``'dct-blocks'``: DCT blocks with 12 pixels and full overlap, extracting 35 DCT features per block * ``'eigenface'``: Pixel vectors projected to face space keeping 95 % variance -* ``'grid-graph'``: Gabor jets in grid graphs, with 4 pixels distance between nodes +* ``'grid-graph'``: Gabor jets in grid graphs, with 8 pixels distance between nodes +* ``'lgbphs'``: Local Gabor binary pattern histogram sequences with block-size of 8 and no overlap + +.. _bob.bio.face.algorithms: + +Face Recognition Algorithms +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``'gabor-jet'``: Compares graphs of Gabor jets with using a dedicated Gabor jet similarity function [GHW12]_ +* ``'histogram'``: Compares histograms using histogram comparison functions +* ``'bic-jet'``: Uses the :py:class:`bob.bio.base.algorithm.BIC` with vectors of Gabor jet similarities + + .. note:: One particularity of this resource is that the function to compute the feature vectors to be classified in the BIC algorithm is actually implemented *in the configuration file*. + .. include:: links.rst diff --git a/doc/implemented.rst b/doc/implemented.rst index 5ac328e000bcbc90d6e5ce3d26fd98d6163ac5dc..b56a7c48f8a16b227eda6b89f61afe9764f867f4 100644 --- a/doc/implemented.rst +++ b/doc/implemented.rst @@ -37,7 +37,7 @@ Face Recognition Algorithms .. autosummary:: bob.bio.face.algorithm.GaborJet - bob.bio.face.algorithm.LGBPHS + bob.bio.face.algorithm.Histogram Preprocessors diff --git a/doc/index.rst b/doc/index.rst index 1ab1626863ae62c0181e14aee2ba7ee88453cea7..1682a3600eb8b993bc1ef035a80f6f73076a87a4 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -45,15 +45,8 @@ Reference Manual :maxdepth: 2 implemented - py_api .. include:: references.rst -ToDo-List -========= - -This documentation is still under development. -Here is a list of things that needs to be done: - .. todolist:: diff --git a/setup.py b/setup.py index 499ac975b721fc99e36fad30889625422cd7cfce..ee4592c50f3eeb85072f8b833bcadd971a4b1f59 100644 --- a/setup.py +++ b/setup.py @@ -155,7 +155,7 @@ setup( 'bob.bio.algorithm': [ 'gabor-jet = bob.bio.face.config.algorithm.gabor_jet:algorithm', # Gabor jet comparison - 'lgbphs = bob.bio.face.config.algorithm.lgbphs:algorithm', # LGBPHS histograms + 'histogram = bob.bio.face.config.algorithm.histogram:algorithm', # LGBPHS histograms 'bic-jets = bob.bio.face.config.algorithm.bic_jets:algorithm', # BIC on gabor jets ], },