From bd592d5a23c4e205a2f35eeb1ebcfd35d5811e84 Mon Sep 17 00:00:00 2001 From: Tiago Freitas Pereira <tiagofrepereira@gmail.com> Date: Tue, 1 Dec 2020 20:14:37 +0100 Subject: [PATCH] [db] implementing MEDS database in the new interface --- bob/bio/face/database/__init__.py | 33 ++-- bob/bio/face/database/meds.py | 35 ++++ bob/bio/face/database/sample_loaders.py | 94 ++-------- bob/bio/face/test/test_databases.py | 239 ++++++++++++++++-------- 4 files changed, 233 insertions(+), 168 deletions(-) create mode 100644 bob/bio/face/database/meds.py diff --git a/bob/bio/face/database/__init__.py b/bob/bio/face/database/__init__.py index 57877158..83d143eb 100644 --- a/bob/bio/face/database/__init__.py +++ b/bob/bio/face/database/__init__.py @@ -12,13 +12,13 @@ from .multipie import MultipieBioDatabase from .ijbc import IJBCBioDatabase from .replaymobile import ReplayMobileBioDatabase from .fargo import FargoBioDatabase - +from .meds import MEDSDatabase # gets sphinx autodoc done right - don't remove it def __appropriate__(*args): - """Says object was actually declared here, and not in the import module. + """Says object was actually declared here, and not in the import module. Fixing sphinx warnings of not being able to find classes, when path is shortened. Parameters: @@ -28,20 +28,21 @@ def __appropriate__(*args): <https://github.com/sphinx-doc/sphinx/issues/3048>` """ - for obj in args: - obj.__module__ = __name__ + for obj in args: + obj.__module__ = __name__ + __appropriate__( - FaceBioFile, - MobioBioDatabase, - ReplayBioDatabase, - AtntBioDatabase, - GBUBioDatabase, - ARFaceBioDatabase, - LFWBioDatabase, - MultipieBioDatabase, - IJBCBioDatabase, - ReplayMobileBioDatabase, - FargoBioDatabase + FaceBioFile, + MobioBioDatabase, + ReplayBioDatabase, + AtntBioDatabase, + GBUBioDatabase, + ARFaceBioDatabase, + LFWBioDatabase, + MultipieBioDatabase, + IJBCBioDatabase, + ReplayMobileBioDatabase, + FargoBioDatabase, ) -__all__ = [_ for _ in dir() if not _.startswith('_')] +__all__ = [_ for _ in dir() if not _.startswith("_")] diff --git a/bob/bio/face/database/meds.py b/bob/bio/face/database/meds.py new file mode 100644 index 00000000..0eafb170 --- /dev/null +++ b/bob/bio/face/database/meds.py @@ -0,0 +1,35 @@ +#!/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 CSVDatasetDevEval, CSVToSampleLoader +from bob.extension import rc +import bob.io.base +from bob.bio.face.database.sample_loaders import EyesAnnotationsLoader + + +# TODO: POINT TO THE `.bob/meds`` +dataset_protocol_path = "/idiap/user/tpereira/gitlab/bob/bob.nightlies/meds" + + +class MEDSDatabase(CSVDatasetDevEval): + def __init__( + self, + protocol, + dataset_protocol_path=dataset_protocol_path, + csv_to_sample_loader=CSVToSampleLoader( + data_loader=bob.io.base.load, + metadata_loader=EyesAnnotationsLoader(), + dataset_original_directory=rc["bob.db.meds.directory"], + extension=".jpg", + ), + ): + + # TODO: IMPLEMENT THE DOWNLOAD MECHANISM + + super().__init__(dataset_protocol_path, protocol, csv_to_sample_loader) + diff --git a/bob/bio/face/database/sample_loaders.py b/bob/bio/face/database/sample_loaders.py index f19f86e2..c4016ef3 100644 --- a/bob/bio/face/database/sample_loaders.py +++ b/bob/bio/face/database/sample_loaders.py @@ -1,91 +1,27 @@ #!/usr/bin/env python # vim: set fileencoding=utf-8 : -""" Sample loader""" +""" Sample and Metatada loader""" -from bob.bio.base.database import CSVToSampleLoader -from bob.pipelines import Sample, DelayedSample, SampleSet -import functools -import os - - -class CSVToSampleLoaderEyesAnnotations(CSVToSampleLoader): +class EyesAnnotationsLoader: """ - Convert CSV files in the format below to either a list of - :any:`bob.pipelines.DelayedSample` or :any:`bob.pipelines.SampleSet` - Convert leye_x, leye_y, reye_x, reye_y attributes to `annotations = (leye, reye)` - """ - def convert_row_to_sample(self, row, header): - path = row[0] - subject = row[1] - kwargs = dict([[h, r] for h, r in zip(header[2:], row[2:])]) - - annotations = { - "leye": (kwargs["leye_x"], kwargs["leye_y"]), - "reye": (kwargs["reye_x"], kwargs["reye_y"]), + def __call__(self, row, header=None): + def find_attribute(attribute): + for i, a in enumerate(header): + if a == attribute: + return i + else: + ValueError(f"Attribute not found in the dataset: {a}") + + eyes = { + "leye": (row[find_attribute("leye_x")], row[find_attribute("leye_y")]), + "reye": (row[find_attribute("reye_x")], row[find_attribute("reye_y")]), } - kwargs.pop("leye_x") - kwargs.pop("leye_y") - kwargs.pop("reye_x") - kwargs.pop("reye_y") - - return DelayedSample( - functools.partial( - self.data_loader, - os.path.join(self.dataset_original_directory, path + self.extension), - ), - key=path, - subject=subject, - annotations=annotations, - **kwargs, - ) - - -""" -class CSVToSampleLoaderEyesAnnotations(CSVToSampleLoader): - def __call__(self, filename): - import ipdb - - ipdb.set_trace() - samples = super(CSVToSampleLoaderEyesAnnotations, self).__call__(filename) - - def generate_annotations(sample): - - Convert leye_x, leye_y, reye_x, reye_y attributes to - `annotations = (leye, reye)` - - - - check_keys = [ - a in (sample.__dict__.keys()) - for a in ["leye_x", "leye_y", "reye_x", "reye_y"] - ] - - if not check_keys: - raise ValueError( - "Sample needs to contain the following annotations: 'leye_x', 'leye_y', 'reye_x', 'reye_y'" - ) - - annotations = { - "leye": (sample.leye_x, sample.leye_y), - "reye": (sample.reye_x, sample.reye_y), - } - - # Changing the state of samples for efficiency - # We might have a gigantic amount of datasets - sample.__dict__.pop("leye_x") - sample.__dict__.pop("leye_y") - sample.__dict__.pop("reye_x") - sample.__dict__.pop("reye_y") - sample.annotations = annotations - - for sample in samples: - generate_annotations(sample) + annotation = {"annotations": eyes} - return samples -""" + return annotation diff --git a/bob/bio/face/test/test_databases.py b/bob/bio/face/test/test_databases.py index ee2c9651..1dba94ce 100644 --- a/bob/bio/face/test/test_databases.py +++ b/bob/bio/face/test/test_databases.py @@ -22,16 +22,23 @@ from nose.plugins.skip import SkipTest import bob.bio.base from bob.bio.base.test.utils import db_available -from bob.bio.base.test.test_database_implementations import check_database, check_database_zt +from bob.bio.base.test.test_database_implementations import ( + check_database, + check_database_zt, +) import bob.core + logger = bob.core.log.setup("bob.bio.face") -def _check_annotations(database, topleft=False, required=True, limit_files=None, framed=False): +def _check_annotations( + database, topleft=False, required=True, limit_files=None, framed=False +): database_legacy = database.database files = database_legacy.all_files() if limit_files is not None: import random + files = random.sample(files, limit_files) found_none = False @@ -45,118 +52,168 @@ def _check_annotations(database, topleft=False, required=True, limit_files=None, # take one of the frames annotations = annotations[list(annotations.keys())[0]] if topleft: - assert 'topleft' in annotations - assert 'bottomright' in annotations + assert "topleft" in annotations + assert "bottomright" in annotations else: - assert 'reye' in annotations - assert 'leye' in annotations + assert "reye" in annotations + assert "leye" in annotations else: found_none = True if found_none: logger.warn("Some annotations were None for {}".format(database_legacy.name)) -@db_available('arface') +@db_available("arface") def test_arface(): database = bob.bio.base.load_resource( - 'arface', 'database', preferred_package='bob.bio.face') + "arface", "database", preferred_package="bob.bio.face" + ) try: - check_database(database, groups=('dev', 'eval')) + check_database(database, groups=("dev", "eval")) except IOError as e: raise SkipTest( - "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) try: _check_annotations(database) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('atnt') +@db_available("atnt") def test_atnt(): database = bob.bio.base.load_resource( - 'atnt', 'database', preferred_package='bob.bio.face') + "atnt", "database", preferred_package="bob.bio.face" + ) try: check_database(database) except IOError as e: raise SkipTest( - "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) -@db_available('gbu') +@db_available("gbu") def test_gbu(): database = bob.bio.base.load_resource( - 'gbu', 'database', preferred_package='bob.bio.face') + "gbu", "database", preferred_package="bob.bio.face" + ) try: check_database(database, models_depend=True) - check_database(database, protocol='Bad', models_depend=True) - check_database(database, protocol='Ugly', models_depend=True) + check_database(database, protocol="Bad", models_depend=True) + check_database(database, protocol="Ugly", models_depend=True) except IOError as e: raise SkipTest( - "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) try: _check_annotations(database, limit_files=1000) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('lfw') +@db_available("lfw") def test_lfw(): database = bob.bio.base.load_resource( - 'lfw-restricted', 'database', preferred_package='bob.bio.face') + "lfw-restricted", "database", preferred_package="bob.bio.face" + ) try: check_database(database, training_depends=True, models_depend=True) - check_database(database, groups=('dev', 'eval'), - protocol='fold1', training_depends=True, models_depend=True) - check_database(bob.bio.base.load_resource('lfw-unrestricted', 'database', preferred_package='bob.bio.face'), - training_depends=True, models_depend=True) + check_database( + database, + groups=("dev", "eval"), + protocol="fold1", + training_depends=True, + models_depend=True, + ) + check_database( + bob.bio.base.load_resource( + "lfw-unrestricted", "database", preferred_package="bob.bio.face" + ), + training_depends=True, + models_depend=True, + ) except IOError as e: raise SkipTest( - "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) try: _check_annotations(database, limit_files=1000) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('mobio') +@db_available("mobio") def test_mobio(): database = bob.bio.base.load_resource( - 'mobio-image', 'database', preferred_package='bob.bio.face') + "mobio-image", "database", preferred_package="bob.bio.face" + ) try: check_database_zt(database, models_depend=True) - check_database_zt(database, protocol='female', models_depend=True) - check_database_zt(bob.bio.base.load_resource('mobio-male', 'database', preferred_package='bob.bio.face'), - models_depend=True) - check_database_zt(bob.bio.base.load_resource('mobio-female', 'database', preferred_package='bob.bio.face'), - models_depend=True) + check_database_zt(database, protocol="female", models_depend=True) + check_database_zt( + bob.bio.base.load_resource( + "mobio-male", "database", preferred_package="bob.bio.face" + ), + models_depend=True, + ) + check_database_zt( + bob.bio.base.load_resource( + "mobio-female", "database", preferred_package="bob.bio.face" + ), + models_depend=True, + ) except IOError as e: raise SkipTest( - "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) try: _check_annotations(database, limit_files=1000) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('multipie') +@db_available("multipie") def test_multipie(): database = bob.bio.base.load_resource( - 'multipie', 'database', preferred_package='bob.bio.face') + "multipie", "database", preferred_package="bob.bio.face" + ) try: check_database_zt(database, training_depends=True) - check_database_zt(bob.bio.base.load_resource('multipie-pose', 'database', preferred_package='bob.bio.face'), - training_depends=True) + check_database_zt( + bob.bio.base.load_resource( + "multipie-pose", "database", preferred_package="bob.bio.face" + ), + training_depends=True, + ) except IOError as e: raise SkipTest( - "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) except ValueError as e: raise SkipTest( - "The database could not queried; probably the protocol is missing inside the db.sql3 file. Here is the error: '%s'" % e) + "The database could not queried; probably the protocol is missing inside the db.sql3 file. Here is the error: '%s'" + % e + ) try: if database.database.annotation_directory is None: @@ -164,94 +221,130 @@ def test_multipie(): _check_annotations(database) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('replay') +@db_available("replay") def test_replay_licit(): database = bob.bio.base.load_resource( - 'replay-img-licit', 'database', preferred_package='bob.bio.face') + "replay-img-licit", "database", preferred_package="bob.bio.face" + ) try: - check_database(database, groups=('dev', 'eval')) + check_database(database, groups=("dev", "eval")) except IOError as e: raise SkipTest( - "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) try: _check_annotations(database, topleft=True) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('replay') +@db_available("replay") def test_replay_spoof(): database = bob.bio.base.load_resource( - 'replay-img-spoof', 'database', preferred_package='bob.bio.face') + "replay-img-spoof", "database", preferred_package="bob.bio.face" + ) try: - check_database(database, groups=('dev', 'eval')) + check_database(database, groups=("dev", "eval")) except IOError as e: raise SkipTest( - "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) try: _check_annotations(database, topleft=True) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('replaymobile') +@db_available("replaymobile") def test_replaymobile_licit(): database = bob.bio.base.load_resource( - 'replaymobile-img-licit', 'database', preferred_package='bob.bio.face') + "replaymobile-img-licit", "database", preferred_package="bob.bio.face" + ) try: - check_database(database, groups=('dev', 'eval')) + check_database(database, groups=("dev", "eval")) except IOError as e: raise SkipTest( - "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) try: _check_annotations(database, topleft=True, limit_files=20) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('replaymobile') +@db_available("replaymobile") def test_replaymobile_spoof(): database = bob.bio.base.load_resource( - 'replaymobile-img-spoof', 'database', preferred_package='bob.bio.face') + "replaymobile-img-spoof", "database", preferred_package="bob.bio.face" + ) try: - check_database(database, groups=('dev', 'eval')) + check_database(database, groups=("dev", "eval")) except IOError as e: raise SkipTest( - "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" % e) + "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'" + % e + ) try: _check_annotations(database, topleft=True, limit_files=20) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('ijbc') +@db_available("ijbc") def test_ijbc(): database = bob.bio.base.load_resource( - 'ijbc-11', 'database', preferred_package='bob.bio.face') + "ijbc-11", "database", preferred_package="bob.bio.face" + ) try: check_database(database, models_depend=True, training_depends=True) except IOError as e: - raise SkipTest( - "The database could not queried; Here is the error: '%s'" % e) + raise SkipTest("The database could not queried; Here is the error: '%s'" % e) try: _check_annotations(database, topleft=True, limit_files=1000) except IOError as e: raise SkipTest( - "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" % e) + "The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'" + % e + ) -@db_available('fargo') + +@db_available("fargo") def test_fargo(): database = bob.bio.base.load_resource( - 'fargo', 'database', preferred_package='bob.bio.face') + "fargo", "database", preferred_package="bob.bio.face" + ) try: check_database(database) except IOError as e: - raise SkipTest( - "The database could not queried; Here is the error: '%s'" % e) + raise SkipTest("The database could not queried; Here is the error: '%s'" % e) + + +def test_meds(): + from bob.bio.face.database import MEDSDatabase + + database = MEDSDatabase("verification_fold1") + + assert len(database.background_model_samples()) == 234 + + assert len(database.references()) == 223 // 2 + assert len(database.probes()) == 313 -- GitLab