diff --git a/bob/pad/face/database/__init__.py b/bob/pad/face/database/__init__.py index c326c7ded5d3d45c290f290a5dede0c012ff5420..217442075022a4dbcaed66cdd292c9dfff6d223d 100644 --- a/bob/pad/face/database/__init__.py +++ b/bob/pad/face/database/__init__.py @@ -6,6 +6,7 @@ from .aggregated_db import AggregatedDbPadDatabase from .mifs import MIFSPadDatabase from .batl import BatlPadDatabase from .celeb_a import CELEBAPadDatabase +from .maskattack import MaskAttackPadDatabase # gets sphinx autodoc done right - don't remove it def __appropriate__(*args): @@ -31,7 +32,8 @@ __appropriate__( AggregatedDbPadDatabase, MIFSPadDatabase, BatlPadDatabase, - CELEBAPadDatabase + CELEBAPadDatabase, + MaskAttackPadDatabase ) __all__ = [_ for _ in dir() if not _.startswith('_')] diff --git a/bob/pad/face/database/maskattack.py b/bob/pad/face/database/maskattack.py index 56c2b2a50b0452ad846ad5b07918f693baea0493..64bc5bcc98c7f4f2c656f2650079fc67112d41f4 100644 --- a/bob/pad/face/database/maskattack.py +++ b/bob/pad/face/database/maskattack.py @@ -5,23 +5,31 @@ import os import numpy as np import bob.io.video from bob.bio.video import FrameSelector, FrameContainer -from bob.pad.face.database import VideoPadFile # Used in MsuMfsdPadFile class +from bob.pad.face.database import VideoPadFile from bob.pad.base.database import PadDatabase class MaskAttackPadFile(VideoPadFile): """ A high level implementation of the File class for the 3DMAD database. + + Attributes + ---------- + f : :py:class:`object` + An instance of the File class defined in the low level db interface + of the 3DMAD database, in the bob.db.maskattack.models.py file. + """ def __init__(self, f): + """Init function + + Parameters + ---------- + f : :py:class:`object` + An instance of the File class defined in the low level db interface + of the 3DMAD database, in the bob.db.maskattack.models.py file. + """ - **Parameters:** - - ``f`` : :py:class:`object` - An instance of the File class defined in the low level db interface - of the 3DMAD database, in the bob.db.maskattack.models.py file. - """ - self.f = f if f.is_real(): attack_type = None @@ -34,80 +42,64 @@ class MaskAttackPadFile(VideoPadFile): attack_type=attack_type, file_id=f.id) - #========================================================================== def load(self, directory=None, extension='.avi', frame_selector=FrameSelector(selection_style='all')): - """ - Overridden version of the load method defined in the ``VideoPadFile``. - - **Parameters:** - - ``directory`` : :py:class:`str` - String containing the path to the MSU MFSD database. - Default: None - - ``extension`` : :py:class:`str` - Extension of the video files in the MSU MFSD database. - Note: ``extension`` value is not used in the code of this method. - Default: None - - ``frame_selector`` : ``FrameSelector`` + """Overridden version of the load method defined in ``VideoPadFile``. + + Parameters + ---------- + directory : :py:class:`str` + String containing the path to the 3DMAD database + (generated sequences from original data). + extension : :py:class:`str` + Extension of the video files + frame_selector : :py:class:`bob.bio.video.FrameSelector` The frame selector to use. - **Returns:** - - ``video_data`` : FrameContainer - Video data stored in the FrameContainer, see ``bob.bio.video.utils.FrameContainer`` - for further details. + Returns + ------- + video_data : :py:class:`bob.bio.video.utils.FrameContainer` + video data stored in a FrameContainer + """ vfilename = self.make_path(directory, extension) video = bob.io.video.reader(vfilename) video_data_array = video.load() - return frame_selector(video_data_array) -#============================================================================== class MaskAttackPadDatabase(PadDatabase): - """ - A high level implementation of the Database class for the 3DMAD database. - """ - - def __init__( - self, - protocol=None, - original_directory=None, - original_extension='.avi', - **kwargs): - """ - **Parameters:** + """High level implementation of the Database class for the 3DMAD database. + + Attributes + ---------- + db : :py:class:`bob.db.maskattack.Database` + the low-level database interface + low_level_group_names : list of :py:obj:`str` + the group names in the low-level interface (world, dev, test) + high_level_group_names : list of :py:obj:`str` + the group names in the high-level interface (train, dev, eval) - ``protocol`` : :py:class:`str` or ``None`` - The name of the protocol that defines the default experimental setup for this 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. + """ - ``kwargs`` - The arguments of the :py:class:`bob.bio.base.database.BioDatabase` base class constructor. + def __init__(self, protocol='classification', original_directory=None, original_extension='.avi', **kwargs): + """Init function + + Parameters + ---------- + protocol : :py:class:`str` + The name of the protocol that defines the default experimental setup for this 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. + """ - from bob.db.maskattack 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 = ( - 'world', 'dev', - '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 + self.low_level_group_names = ('world', 'dev', 'test') + self.high_level_group_names = ('train', 'dev', 'eval') - # Always use super to call parent class methods. super(MaskAttackPadDatabase, self).__init__( name='maskattack', protocol=protocol, @@ -115,60 +107,45 @@ class MaskAttackPadDatabase(PadDatabase): original_extension=original_extension, **kwargs) + @property def original_directory(self): return self.db.original_directory + @original_directory.setter def original_directory(self, value): self.db.original_directory = value - #========================================================================== def objects(self, groups=None, - protocol=None, + protocol='classification', purposes=None, model_ids=None, **kwargs): - """ - This function returns lists of MaskAttackPadFile 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') - - ``protocol`` : :py:class:`str` - The protocol for which the clients should be retrieved. - Note: this argument is not used in the code, because ``objects`` method of the - low-level BD interface of the MSU MFSD doesn't have ``protocol`` argument. - - ``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. - - **Returns:** - - ``files`` : [MsuMfsdPadFile] - A list of MsuMfsdPadFile objects. + """Returns a list of MaskAttackPadFile objects, which fulfill the given restrictions. + + Parameters + ---------- + groups : list of :py:class:`str` + The groups of which the clients should be returned. + Usually, groups are one or more elements of ('train', 'dev', 'eval') + protocol : :py:class:`str` + The protocol for which the clients should be retrieved. + purposes : :py:class:`str` + 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. + + Returns + ------- + files : :py:class:`MaskAttackPadFile` + A list of MaskAttackPadFile objects. """ - # 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. + groups = self.convert_names_to_lowlevel(groups, self.low_level_group_names, self.high_level_group_names) - #print("Objects method called with groups = {}, protocol = {}, purposes = {}, model_ids = {}".format(groups, protocol, purposes, model_ids)) - #print("Kwargs -> {}".format(**kwargs)) - #print("Translated groups = {}".frima) - if groups is not None: # for training @@ -189,48 +166,20 @@ class MaskAttackPadDatabase(PadDatabase): return files - #========================================================================== + def annotations(self, file): - """ - Return annotations for a given file object ``f``, which is an instance - of ``MsuMfsdPadFile`` defined in the HLDI of the MSU MFSD DB. - The ``load()`` method of ``MsuMfsdPadFile`` class (see above) - returns a video, therefore this method returns bounding-box annotations - for each video frame. The annotations are returned as dictionary of dictionaries. - - **Parameters:** - - ``f`` : :py:class:`object` - An instance of ``MsuMfsdPadFile`` defined above. - - **Returns:** - - ``annotations`` : :py:class:`dict` - A dictionary containing the annotations for each frame in the video. - Dictionary structure: ``annotations = {'1': frame1_dict, '2': frame1_dict, ...}``. - Where ``frameN_dict = {'topleft': (row, col), 'bottomright': (row, col)}`` - is the dictionary defining the coordinates of the face bounding box in frame N. + """Return annotations for a given file object. + + Parameters + ---------- + f : :py:class:`MaskAttackPadFile` + An instance of ``MaskAttackPadFile`` defined above. + + Returns + ------- + annotations : :py:class:`dict` + A dictionary containing the annotations for each frame in the video. + Dictionary structure: ``annotations = {'1': frame1_dict, '2': frame1_dict, ...}``. """ return None - #annots = f.f.bbx( - # directory=self.original_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 - - #annotations = {} # dictionary to return - - #for frame_annots in annots: - - # topleft = (np.int(frame_annots[2]), np.int(frame_annots[1])) - # bottomright = (np.int(frame_annots[2] + frame_annots[4]), - # np.int(frame_annots[1] + frame_annots[3])) - - # annotations[str(np.int(frame_annots[0]))] = { - # 'topleft': topleft, - # 'bottomright': bottomright - # } - - #return annotations - - #def model_with_ids_protocol(groups=None, protocol=None): - # pass