diff --git a/bob/bio/face/config/database/morph.py b/bob/bio/face/config/database/morph.py new file mode 100644 index 0000000000000000000000000000000000000000..c42d79cc4d1d11b19876840cac24c00f1f6a2300 --- /dev/null +++ b/bob/bio/face/config/database/morph.py @@ -0,0 +1,9 @@ +from bob.bio.face.database import MorphDatabase + +# In case protocol is comming from chain loading +# https://www.idiap.ch/software/bob/docs/bob/bob.extension/stable/py_api.html#bob.extension.config.load +if "protocol" not in locals(): + protocol = "verification_fold1" + + +database = MorphDatabase(protocol=protocol) diff --git a/bob/bio/face/database/__init__.py b/bob/bio/face/database/__init__.py index a7ef08a73f923b185fbe9b13e02fff77a9a9b236..3c0429f2e189eaacd4280f9ee99cdf78e3da237f 100644 --- a/bob/bio/face/database/__init__.py +++ b/bob/bio/face/database/__init__.py @@ -13,6 +13,7 @@ from .ijbc import IJBCBioDatabase from .replaymobile import ReplayMobileBioDatabase from .fargo import FargoBioDatabase from .meds import MEDSDatabase +from .morph import MorphDatabase # gets sphinx autodoc done right - don't remove it @@ -45,5 +46,6 @@ __appropriate__( ReplayMobileBioDatabase, FargoBioDatabase, MEDSDatabase, + MorphDatabase, ) __all__ = [_ for _ in dir() if not _.startswith("_")] diff --git a/bob/bio/face/database/meds.py b/bob/bio/face/database/meds.py index db2424e1dd9f83ee21f6b1e9a0e0ee3d08fad2ce..81576a93f1ea78c04225de1858fa7dea0c12434f 100644 --- a/bob/bio/face/database/meds.py +++ b/bob/bio/face/database/meds.py @@ -30,7 +30,62 @@ dataset_protocol_path = os.path.join( class MEDSDatabase(CSVDatasetZTNorm): """ - The MEDS-II (Multiple Encounter Data Set II) database interface + The MEDS II database was developed by NIST to support and assists their biometrics evaluation program. + It is composed by 518 identities from both men/women (labeled as M and F) and five different race annotations (Asian, Black, American Indian, Unknown and White) + (labeled as A, B, I, U and W. + + Unfortunately, the distribution of gender and race is extremely unbalanced as it can be + observed in their statistics. Furthermore, only 256 subjects has + more than one image sample (obviously it is not possible to do a biometric evaluation with one sample per subject). + For this reason, this interface contains a subset of the data, which is composed only by 383 subjects (White and Black men only). + + This dataset contains three verification protocols and they are: + `verification_fold1`, `verification_fold2` and `verification_fold1`. + Follow below the identities distribution in each set for the for each protocol: + + + +--------------------+---------------+-----------+-----------+-----------+ + | | Training set | Dev. Set | Eval. Set | + +--------------------+---------------+-----------+ + + + | | T-References | Z-Probes | | | + +====================+===============+===========+===========+===========+ + | verification_fold1 | 80 | 80 | 111 | 112 | + +--------------------+---------------+-----------+-----------+-----------+ + | verification_fold2 | 80 | 80 | 111 | 112 | + +--------------------+---------------+-----------+-----------+-----------+ + | verification_fold3 | 80 | 80 | 111 | 112 | + +--------------------+---------------+-----------+-----------+-----------+ + + Example + ------- + + Fetching biometric references:: + + >>> from bob.bio.face.database import MEDSDatabase + >>> database = MEDSDatabase(protocol="verification_fold1") + >>> database.references() + + + Fetching probes:: + + >>> from bob.bio.face.database import MEDSDatabase + >>> database = MEDSDatabase(protocol="verification_fold1") + >>> database.probes() + + + Fetching refererences for T-Norm normalization:: + + >>> from bob.bio.face.database import MEDSDatabase + >>> database = MEDSDatabase(protocol="verification_fold1") + >>> database.trerefences() + + + Fetching probes for Z-Norm normalization:: + + >>> from bob.bio.face.database import MEDSDatabase + >>> database = MEDSDatabase(protocol="verification_fold1") + >>> database.zprobes() + .. warning:: Use the command below to set the path of the real data:: @@ -54,7 +109,7 @@ class MEDSDatabase(CSVDatasetZTNorm): ] get_file(filename, urls) - self.annotation_type = ("eyes-center",) + self.annotation_type = "eyes-center" self.fixed_positions = None database = CSVDataset( diff --git a/bob/bio/face/database/morph.py b/bob/bio/face/database/morph.py new file mode 100644 index 0000000000000000000000000000000000000000..4790fe71acc2c55cea0a986325c699d5115accba --- /dev/null +++ b/bob/bio/face/database/morph.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : +# Tiago de Freitas Pereira <tiago.pereira@idiap.ch> + +""" + MEDS database implementation +""" + +from bob.bio.base.database import ( + CSVDataset, + CSVDatasetZTNorm, +) +from bob.pipelines.datasets import CSVToSampleLoader +from bob.bio.face.database.sample_loaders import EyesAnnotations +from bob.extension import rc +from bob.extension.download import get_file +import bob.io.base +from sklearn.pipeline import make_pipeline + + +class MorphDatabase(CSVDatasetZTNorm): + """ + The MORPH dataset is relatively old, but is getting some traction recently mostly because its richness + with respect to sensitive attributes. + It is composed by 55,000 samples from 13,000 subjects from men and women and five + race clusters (called ancestry) and they are the following: African, European, Asian, Hispanic and Others. Figure 8 + present some samples from this database. + + This dataset contains faces from five ethnicities (African, European, Asian, Hispanic, "Other") + and two genders (Male and Female). + Furthermore, this interface contains three verification protocols and they are: + `verification_fold1`, `verification_fold2` and `verification_fold1`. + Follow below the identities distribution in each set for the for each protocol: + + +--------------------+---------------+-----------+-----------+-----------+ + | | Training set | Dev. Set | Eval. Set | + +--------------------+---------------+-----------+ + + + | | T-References | Z-Probes | | | + +====================+===============+===========+===========+===========+ + | verification_fold1 | 69 | 66 | 6738 | 6742 | + +--------------------+---------------+-----------+-----------+-----------+ + | verification_fold2 | 69 | 67 | 6734 | 6737 | + +--------------------+---------------+-----------+-----------+-----------+ + | verification_fold3 | 70 | 66 | 6736 | 6740 | + +--------------------+---------------+-----------+-----------+-----------+ + + .. warning:: + Use the command below to set the path of the real data:: + + $ bob config set bob.db.morph.directory [PATH-TO-MORPH-DATA] + + Parameters + ---------- + + protocol: str + One of the database protocols. Options are `verification_fold1`, `verification_fold2` and `verification_fold3` + + """ + + def __init__(self, protocol): + + # Downloading model if not exists + urls = [ + "https://www.idiap.ch/software/bob/databases/latest/morph.tar.gz", + "http://www.idiap.ch/software/bob/databases/latest/morph.tar.gz", + ] + filename = get_file("morph.tar.gz", urls) + + self.annotation_type = "eyes-center" + self.fixed_positions = None + + database = CSVDataset( + filename, + protocol, + csv_to_sample_loader=make_pipeline( + CSVToSampleLoader( + data_loader=bob.io.base.load, + dataset_original_directory=rc["bob.db.morph.directory"] + if rc["bob.db.morph.directory"] + else "", + extension=".JPG", + ), + EyesAnnotations(), + ), + ) + + super().__init__(database) diff --git a/bob/bio/face/database/sample_loaders.py b/bob/bio/face/database/sample_loaders.py index ef5871c21dfc4424547d2dcf4995bc65ed53798b..607145ea69ed22831199765542cf924b5acdee86 100644 --- a/bob/bio/face/database/sample_loaders.py +++ b/bob/bio/face/database/sample_loaders.py @@ -32,8 +32,14 @@ class EyesAnnotations(TransformerMixin, BaseEstimator): annotated_samples = [] for x in X: eyes = { - "leye": (find_attribute, (x, "leye_x"), find_attribute(x, "leye_y")), - "reye": (find_attribute(x, "reye_x"), find_attribute(x, "reye_y")), + "leye": ( + float(find_attribute(x, "leye_x")), + float(find_attribute(x, "leye_y")), + ), + "reye": ( + float(find_attribute(x, "reye_x")), + float(find_attribute(x, "reye_y")), + ), } sample = DelayedSample(x._load, parent=x, annotations=eyes) diff --git a/doc/implemented.rst b/doc/implemented.rst index e1f29a24a187427b61f265d738ab8fb0f304034c..0deac2602496a6ed7390588ea7b7666459ef43d3 100644 --- a/doc/implemented.rst +++ b/doc/implemented.rst @@ -20,7 +20,8 @@ Databases bob.bio.face.database.LFWBioDatabase bob.bio.face.database.MultipieBioDatabase bob.bio.face.database.FargoBioDatabase - bob.bio.face.database.meds.MEDSDatabase + bob.bio.face.database.MEDSDatabase + bob.bio.face.database.MorphDatabase Face Image Annotators diff --git a/setup.py b/setup.py index 4b978b1e1a46dab35c3a9572ed005a4b1c9dbe87..daf7cdb02e6053673d10f8343262a3103b686a8e 100644 --- a/setup.py +++ b/setup.py @@ -111,6 +111,7 @@ setup( "replaymobile-img-spoof = bob.bio.face.config.database.replaymobile:replaymobile_spoof", "fargo = bob.bio.face.config.database.fargo:database", "meds = bob.bio.face.config.database.meds:database", + "morph = bob.bio.face.config.database.morph:database", ], "bob.bio.annotator": [ "facedetect = bob.bio.face.config.annotator.facedetect:annotator", @@ -172,6 +173,7 @@ setup( "replaymobile-img-spoof = bob.bio.face.config.database.replaymobile_spoof", "fargo = bob.bio.face.config.database.fargo", "meds = bob.bio.face.config.database.meds", + "morph = bob.bio.face.config.database.morph", ], "bob.bio.cli": [ "display-face-annotations = bob.bio.face.script.display_face_annotations:display_face_annotations",