diff --git a/bob/pad/face/__init__.py b/bob/pad/face/__init__.py index 1d16bcbc879c7c6054b3c555e01c7e710eae801e..cc278fa2d1cfe68f247d655d7161ba0b569e117f 100644 --- a/bob/pad/face/__init__.py +++ b/bob/pad/face/__init__.py @@ -11,3 +11,4 @@ def get_config(): # gets sphinx autodoc done right - don't remove it __all__ = [_ for _ in dir() if not _.startswith('_')] + diff --git a/bob/pad/face/config/__init__.py b/bob/pad/face/config/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/bob/pad/face/config/database/__init__.py b/bob/pad/face/config/database/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/bob/pad/face/config/database/replay.py b/bob/pad/face/config/database/replay.py new file mode 100644 index 0000000000000000000000000000000000000000..f1cbd70cb6725aa1ff17a172456eecd24d6c8f70 --- /dev/null +++ b/bob/pad/face/config/database/replay.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +from bob.pad.face.database import ReplayPadDatabase + + +# Directory where the data files are stored. +# This directory is given in the .bob_bio_databases.txt file located in your home directory +original_directory = "[YOUR_REPLAY_ATTACK_DIRECTORY]" +original_extension = ".mov" # extension of the data files + + +database = ReplayPadDatabase( + protocol='grandtest', + original_directory=original_directory, + original_extension=original_extension, + training_depends_on_protocol=True, +) diff --git a/bob/pad/face/database/replay.py b/bob/pad/face/database/replay.py index 7e4e0ccfca3fe1b1edfc8e2633b6d23967fcb85a..00b288547d558c2a4a7df3572d17e5ab7d5a2431 100644 --- a/bob/pad/face/database/replay.py +++ b/bob/pad/face/database/replay.py @@ -10,12 +10,14 @@ High level implementation for the REPLAY-ATTACK database #============================================================================== -from bob.pad.base.database import PadDatabase - import bob.bio.video # Used in ReplayPadFile class from bob.pad.base.database import PadFile # Used in ReplayPadFile class +from bob.pad.base.database import PadDatabase + +from bob.db.replay import Database as LowLevelDatabase + #============================================================================== class ReplayPadFile(PadFile): @@ -25,7 +27,6 @@ class ReplayPadFile(PadFile): def __init__(self, f): """ - **Parameters:** ``f`` : :py:class:`object` @@ -80,59 +81,101 @@ class ReplayPadFile(PadFile): bbx_data = self.f.bbx(directory=directory) # numpy array containing the face bounding box data for each video frame, returned data format described in the f.bbx() method of the low level interface return_dictionary = {} - return_dictionary["video"] = video_data - return_dictionary["bbx"] = bbx_data + return_dictionary["data"] = video_data + return_dictionary["annotations"] = bbx_data return return_dictionary # dictionary containing the face bounding box annotations and video data #============================================================================== +class ReplayPadDatabase(PadDatabase): + """ + A high level implementation of the Database class for the REPLAY-ATTACK database. + """ + def __init__( + self, + all_files_options={}, + check_original_files_for_existence=False, + original_directory=None, + original_extension=None, + # here I have said grandtest because this is the name of the default + # protocol for this database + protocol='grandtest', + **kwargs): + """ + **Parameters:** + ``all_files_options`` : :py:class:`dict` + Dictionary of options passed to the second-level database query when retrieving all data. + ``check_original_files_for_existence`` : :py:class:`bool` + Enables to test for the original data files when querying the database. + ``original_directory`` : :py:class:`str` + The directory where the original data of the database are stored. + ``original_extension`` : :py:class:`str` + The file name extension of the original data. + ``protocol`` : :py:class:`str` or ``None`` + The name of the protocol that defines the default experimental setup for this database. + ``kwargs`` + The arguments of the :py:class:`bob.bio.base.database.BioDatabase` base class constructor. + """ + self.db = LowLevelDatabase() -class ReplayPadDatabase(PadDatabase): + # Since the high level API expects different group names than what the low + # level API offers, you need to convert them when necessary + self.low_level_group_names = ('train', 'devel', 'test') # group names in the low-level database interface + self.high_level_group_names = ('train', 'dev', 'eval') # names are expected to be like that in objects() function + + # Always use super to call parent class methods. + super(ReplayPadDatabase, self).__init__( + 'replay', + all_files_options, + check_original_files_for_existence, + original_directory, + original_extension, + protocol, + **kwargs) + + def objects(self, groups=None, protocol=None, purposes=None, model_ids=None, **kwargs): + """ + This function returns lists of ReplayPadFile objects, which fulfill the given restrictions. + + Keyword parameters: + + ``groups`` : :py:class:`str` + OR a list of strings. + The groups of which the clients should be returned. + Usually, groups are one or more elements of ('train', 'dev', 'eval') - def __init__( - self, - all_files_options={}, - check_original_files_for_existence=False, - original_directory=None, - original_extension=None, - # here I have said grandtest because this is the name of the default - # protocol for this database - protocol='grandtest', - **kwargs): - - from bob.db.replay import Database as LowLevelDatabase - self.__db = LowLevelDatabase() - - # Since the high level API expects different group names than what the low - # level API offers, you need to convert them when necessary - self.low_level_group_names = ('train', 'devel', 'test') - self.high_level_group_names = ('train', 'dev', 'eval') - - # Always use super to call parent class methods. - super(ReplayPadDatabase, self).__init__( - 'replay', - all_files_options, - check_original_files_for_existence, - original_directory, - original_extension, - protocol, - **kwargs) - - def objects(self, groups=None, protocol=None, purposes=None, model_ids=None, **kwargs): - # Convert group names to low-level group names here. - groups = self.convert_names_to_lowlevel( - groups, self.low_level_group_names, self.high_level_group_names) - # Since this database was designed for PAD experiments, nothing special - # needs to be done here. - files = self.__db.objects(protocol=protocol, groups=groups, cls=purposes, **kwargs) - files = [ReplayPadFile(f) for f in files] - return files + ``protocol`` : :py:class:`str` + The protocol for which the clients should be retrieved. + The protocol is dependent on your database. + If you do not have protocols defined, just ignore this field. + + ``purposes`` : :py:class:`str` + OR a list of strings. + The purposes for which File objects should be retrieved. + Usually it is either 'real' or 'attack'. + + ``model_ids`` + This parameter is not supported in PAD databases yet + """ + # Convert group names to low-level group names here. + groups = self.convert_names_to_lowlevel(groups, self.low_level_group_names, self.high_level_group_names) + # Since this database was designed for PAD experiments, nothing special + # needs to be done here. + files = self.db.objects(protocol=protocol, groups=groups, cls=purposes, **kwargs) + files = [ReplayPadFile(f) for f in files] + return files + + def annotations(self, file): + """ + Do nothing. In this particular implementation the annotations are returned in the *File class above. + """ + return None diff --git a/setup.py b/setup.py index 7dc09b29749731b7e17836b1c766f522ff6e3662..3ccff59989c4aa43e4f921a72c89f461513a1b32 100644 --- a/setup.py +++ b/setup.py @@ -88,10 +88,15 @@ setup( # the version of bob. entry_points = { - # scripts should be declared using this entry: - 'console_scripts' : [ - 'version.py = bob.pad.face.script.version:main', - ], + # scripts should be declared using this entry: + 'console_scripts' : [ + 'version.py = bob.pad.face.script.version:main', + ], + + 'bob.pad.database': [ + 'replay = bob.pad.face.config.database.replay:database', + ], + }, # Classifiers are important if you plan to distribute this package through