Commit 7b83407b authored by Amir MOHAMMADI's avatar Amir MOHAMMADI

convert databases to use the new csv format from bob.pipelines

parent f83ac86a
Pipeline #49011 failed with stage
in 7 minutes and 12 seconds
......@@ -3,5 +3,5 @@ Please run ``bob config set bob.db.casia_fasd.directory /path/to/casia_fasd_file
in terminal to point to the original files of the dataset on your computer."""
from bob.pad.face.database import CasiaFasdPadDatabase
from bob.pad.base.pipelines.vanilla_pad import DatabaseConnector
database = DatabaseConnector(CasiaFasdPadDatabase())
database = CasiaFasdPadDatabase()
from bob.pad.face.database import CasiaSurfPadDatabase
from bob.pad.base.pipelines.vanilla_pad import DatabaseConnector
database = DatabaseConnector(CasiaSurfPadDatabase())
database = CasiaSurfPadDatabase()
from bob.pad.face.database import CasiaSurfPadDatabase
from bob.pad.base.pipelines.vanilla_pad import DatabaseConnector
database = DatabaseConnector(CasiaSurfPadDatabase())
database = CasiaSurfPadDatabase(stream_type="color")
"""`CELEBA`_ is a face makeup spoofing database adapted for face PAD experiments.
You can download the raw data of the `CELEBA`_ database by following
the link.
.. include:: links.rst
"""
from bob.pad.base.pipelines.vanilla_pad import DatabaseConnector
from bob.pad.face.database.celeb_a import CELEBAPadDatabase
database = DatabaseConnector(CELEBAPadDatabase())
from bob.pad.face.database import MaskAttackPadDatabase
from bob.pad.base.pipelines.vanilla_pad import DatabaseConnector
database = DatabaseConnector(MaskAttackPadDatabase())
database = MaskAttackPadDatabase()
"""`MIFS`_ is a face makeup spoofing database adapted for face PAD experiments.
Database assembled from a dataset consisting of 107 makeup-transformations taken
from random YouTube makeup video tutorials, adapted in this package for face-PAD
experiments. The public version of the database contains 107 such transformations
with each time two images of a subject before makeup, two images of the same
subject after makeup and two images of the target identity. For this package, a
subset of 104 makeup transformations is selected, the target identities images
discarded and the remaining images randomly distributed in three sets. More
information can be found in the reference [CDSR17]_.
You can download the raw data of the `MIFS`_ database by following
the link.
.. include:: links.rst
"""
from bob.pad.face.database import MIFSPadDatabase
from bob.pad.base.pipelines.vanilla_pad import DatabaseConnector
database = DatabaseConnector(MIFSPadDatabase())
......@@ -2,9 +2,7 @@ from .database import VideoPadFile
from .database import VideoPadSample # noqa: F401
from .casiafasd import CasiaFasdPadDatabase
from .casiasurf import CasiaSurfPadDatabase
from .celeb_a import CELEBAPadDatabase
from .maskattack import MaskAttackPadDatabase
from .mifs import MIFSPadDatabase
from .replay_attack import ReplayAttackPadDatabase
from .replay_mobile import ReplayMobilePadDatabase
......@@ -29,8 +27,6 @@ __appropriate__(
VideoPadFile,
ReplayAttackPadDatabase,
ReplayMobilePadDatabase,
MIFSPadDatabase,
CELEBAPadDatabase,
MaskAttackPadDatabase,
CasiaSurfPadDatabase,
CasiaFasdPadDatabase,
......
This diff is collapsed.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import logging
import os
import numpy as np
import bob.io.video
from bob.pad.face.database import VideoPadFile
from bob.pad.base.database import PadDatabase
from functools import partial
import bob.io.base
from bob.bio.video import VideoLikeContainer
from bob.extension import rc
from bob.extension.download import get_file
from bob.pad.base.database import FileListPadDatabase
from bob.pipelines import DelayedSample
from sklearn.preprocessing import FunctionTransformer
class CasiaSurfPadFile(VideoPadFile):
"""
A high level implementation of the File class for the CASIA-SURF database.
logger = logging.getLogger(__name__)
Note that this does not represent a file per se, but rather a sample
that may contain more than one file.
Attributes
----------
f : :py:class:`object`
An instance of the Sample class defined in the low level db interface
of the CASIA-SURF database, in the bob.db.casiasurf.models.py file.
def load_multi_stream(mods, paths):
retval = {}
for mod, path in zip(mods, paths):
data = bob.io.base.load(path)
fc = VideoLikeContainer(data, [0])
retval[mod] = fc
"""
if len(retval) == 1:
retval = retval[mods[0]]
return retval
def casia_surf_multistream_load(samples, original_directory, stream_type):
mod_to_attr = {}
mod_to_attr["color"] = "filename"
mod_to_attr["infrared"] = "ir_filename"
mod_to_attr["depth"] = "depth_filename"
def __init__(self, s, stream_type):
""" Init
Parameters
----------
s : :py:class:`object`
An instance of the Sample class defined in the low level db interface
of the CASIA-SURF database, in the bob.db.casiasurf.models.py file.
stream_type: str of list of str
The streams to be loaded.
"""
self.s = s
self.stream_type = stream_type
if not isinstance(s.attack_type, str):
attack_type = str(s.attack_type)
else:
attack_type = s.attack_type
if attack_type == '0':
attack_type = None
super(CasiaSurfPadFile, self).__init__(
client_id=s.id,
file_id=s.id,
attack_type=attack_type,
path=s.id)
def load(self, directory=rc['bob.db.casiasurf.directory'], extension='.jpg'):
"""Overloaded version of the load method defined in ``VideoPadFile``.
Parameters
----------
directory : :py:class:`str`
String containing the path to the CASIA-SURF database
extension : :py:class:`str`
Extension of the image files
frame_selector : :py:class:`bob.bio.video.FrameSelector`
The frame selector to use.
Returns
-------
dict:
image data for multiple streams stored in the dictionary.
The structure of the dictionary: ``data={"stream1_name" : numpy array, "stream2_name" : numpy array}``
Names of the streams are defined in ``self.stream_type``.
"""
return self.s.load(directory, extension, modality=self.stream_type)
class CasiaSurfPadDatabase(PadDatabase):
"""High level implementation of the Database class for the 3DMAD database.
Note that at the moment, this database only contains a training and validation set.
The protocol specifies the modality(ies) to load.
Attributes
mods = []
if isinstance(stream_type, str) and stream_type != "all":
mods = [stream_type]
elif isinstance(stream_type, str) and stream_type == "all":
mods = ["color", "infrared", "depth"]
else:
for m in stream_type:
mods.append(m)
def _load(sample):
paths = []
for mod in mods:
paths.append(
os.path.join(original_directory or "", getattr(sample, mod_to_attr[mod]))
)
data = partial(load_multi_stream, mods, paths)
return DelayedSample(data, parent=sample, annotations=None)
return [_load(s) for s in samples]
def CasiaSurfMultiStreamSample(original_directory, stream_type):
return FunctionTransformer(
casia_surf_multistream_load,
kw_args=dict(original_directory=original_directory, stream_type=stream_type),
)
def CasiaSurfPadDatabase(
stream_type="all",
**kwargs,
):
"""The CASIA SURF Face PAD database interface.
Parameters
----------
db : :py:class:`bob.db.casiasurf.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)
stream_type : str
A str or a list of str of the following choices: ``all``, ``color``, ``depth``, ``infrared``, by default ``all``
The returned sample either have their data as a VideoLikeContainer or
a dict of VideoLikeContainers depending on the chosen stream_type.
"""
def __init__(self, protocol='all', original_directory=rc['bob.db.casiasurf.directory'], original_extension='.jpg', **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.casiasurf import Database as LowLevelDatabase
self.db = LowLevelDatabase()
self.low_level_group_names = ('train', 'validation', 'test')
self.high_level_group_names = ('train', 'dev', 'eval')
super(CasiaSurfPadDatabase, self).__init__(
name='casiasurf',
protocol=protocol,
original_directory=original_directory,
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='all',
purposes=None,
model_ids=None,
**kwargs):
"""Returns a list of CasiaSurfPadFile 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 samples should be retrieved.
purposes : :py:class:`str`
The purposes for which Sample objects should be retrieved.
Usually it is either 'real' or 'attack'
model_ids
This parameter is not supported in PAD databases yet.
Returns
-------
samples : :py:class:`CasiaSurfPadFilePadFile`
A list of CasiaSurfPadFile objects.
"""
groups = self.convert_names_to_lowlevel(groups, self.low_level_group_names, self.high_level_group_names)
if groups is not None:
# for training
lowlevel_purposes = []
if 'train' in groups and 'real' in purposes:
lowlevel_purposes.append('real')
if 'train' in groups and 'attack' in purposes:
lowlevel_purposes.append('attack')
# for dev
if 'validation' in groups and 'real' in purposes:
lowlevel_purposes.append('real')
if 'validation' in groups and 'attack' in purposes:
lowlevel_purposes.append('attack')
# for eval
if 'test' in groups and 'real' in purposes:
lowlevel_purposes.append('real')
if 'test' in groups and 'attack' in purposes:
lowlevel_purposes.append('attack')
samples = self.db.objects(groups=groups, purposes=lowlevel_purposes, **kwargs)
samples = [CasiaSurfPadFile(s, stream_type=protocol) for s in samples]
return samples
def annotations(self, file):
"""No annotations are provided with this DB
"""
return None
name = "pad-face-casia-surf-252f86f2.tar.gz"
dataset_protocols_path = get_file(
name,
[f"http://www.idiap.ch/software/bob/data/bob/bob.pad.face/{name}"],
cache_subdir="protocols",
file_hash="252f86f2",
)
transformer = CasiaSurfMultiStreamSample(
original_directory=rc.get("bob.db.casiasurf.directory"),
stream_type=stream_type,
)
database = FileListPadDatabase(
dataset_protocols_path,
protocol="all",
transformer=transformer,
**kwargs,
)
database.annotation_type = None
database.fixed_positions = None
return database
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#==============================================================================
import bob.bio.video # Used in CELEBAPadFile class
import bob.io.base
import numpy as np
from bob.pad.base.database import PadFile # Used in ReplayPadFile class
from bob.pad.base.database import FileListPadDatabase
#==============================================================================
class CELEBAPadFile(PadFile):
"""
A high level implementation of the File class for the CELEBA database.
"""
def __init__(self, client_id, path, attack_type=None, file_id=None):
super(CELEBAPadFile, self).__init__(client_id, path, attack_type, file_id)
# ==========================================================================
def load(self):
"""
Overridden version of the load method defined in the ``PadFile``.
**Parameters:**
``directory`` : :py:class:`str`
String containing the path to the CELEBA database.
Default: None
``extension`` : :py:class:`str`
Extension of the video files in the CELEBA database.
Default: None
``frame_selector`` : :any:`bob.bio.video.FrameSelector`, optional
Specifying the frames to be selected.
**Returns:**
``video_data`` : FrameContainer
Video data stored in the FrameContainer, see ``bob.bio.video.utils.FrameContainer``
for further details.
"""
path = self.make_path(directory=directory, extension=extension) # path to the file
data = bob.io.base.load(path)
data = np.expand_dims(data, axis=0) # upgrade to 4D (video)
video_data = frame_selector(data) # video data
return video_data # video data
#==============================================================================
class CELEBAPadDatabase(FileListPadDatabase):
"""
A high level implementation of the Database class for the CELEBA database.
"""
def __init__(
self,
protocol='grandtest', # grandtest is the default protocol for this database
original_directory='[YOUR_CELEB_A_DATABASE_DIRECTORY]',
original_extension='.jpg',
**kwargs):
from pkg_resources import resource_filename
folder = resource_filename(__name__, '../lists/celeb_a/')
super(CELEBAPadDatabase, self).__init__(folder, 'celeb_a',
pad_file_class=CELEBAPadFile,
protocol = protocol,
original_directory=original_directory,
original_extension=original_extension)
#==========================================================================
def annotations(self, f):
"""
Return annotations for a given file object ``f``, which is an instance
of ``CELEBAPadFile``.
**Parameters:**
``f`` : :py:class:`object`
An instance of ``CELEBAPadFile`` 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.
"""
annotations = {} # dictionary to return
return annotations
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import os
import numpy as np
import bob.io.video
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.
"""
self.f = f
if f.is_real():
attack_type = None
else:
attack_type = 'mask'
super(MaskAttackPadFile, self).__init__(
client_id=f.client_id,
path=f.path,
attack_type=attack_type,
file_id=f.id)
class MaskAttackPadDatabase(PadDatabase):
"""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)
"""
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()
self.low_level_group_names = ('world', 'dev', 'test')
self.high_level_group_names = ('train', 'dev', 'eval')
super(MaskAttackPadDatabase, self).__init__(
name='maskattack',
protocol=protocol,
original_directory=original_directory,
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='classification',
purposes=None,
model_ids=None,
**kwargs):
"""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.
"""
groups = self.convert_names_to_lowlevel(groups, self.low_level_group_names, self.high_level_group_names)
if groups is not None:
# for training
lowlevel_purposes = []
if 'world' in groups and purposes == 'real':
lowlevel_purposes.append('trainReal')
if 'world' in groups and purposes == 'attack':
lowlevel_purposes.append('trainMask')
# for dev and eval
if ('dev' in groups or 'test' in groups) and purposes == 'real':
lowlevel_purposes.append('classifyReal')
if ('dev' in groups or 'test' in groups) and purposes == 'attack':
lowlevel_purposes.append('classifyMask')
files = self.db.objects(sets=groups, purposes=lowlevel_purposes, **kwargs)
files = [MaskAttackPadFile(f) for f in files]
# set the attributes
for f in files:
f.original_directory = self.original_directory
f.original_extension = self.original_extension
return files
def annotations(self, file):
"""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
import logging
from bob.extension import rc
from bob.extension.download import get_file
from bob.pad.base.database import FileListPadDatabase
from bob.pad.face.database import VideoPadSample
logger = logging.getLogger(__name__)
def MaskAttackPadDatabase(
protocol="classification",
selection_style=None,
max_number_of_frames=None,
step_size=None,
annotation_directory=None,
annotation_type=None,
fixed_positions=None,
**kwargs,
):
name = "pad-face-mask-attack-211bd751.tar.gz"
dataset_protocols_path = get_file(
name,
[f"http://www.idiap.ch/software/bob/data/bob/bob.pad.face/{name}"],
cache_subdir="protocols",
file_hash="211bd751",
)
transformer = VideoPadSample(
original_directory=rc.get("bob.db.maskattack.directory"),
annotation_directory=annotation_directory,
selection_style=selection_style,
max_number_of_frames=max_number_of_frames,
step_size=step_size,
)
database = FileListPadDatabase(
dataset_protocols_path,
protocol,
transformer=transformer,
**kwargs,
)
database.annotation_type = annotation_type
database.fixed_positions = fixed_positions
return database
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#!/usr/bin/env python
#==============================================================================
# Used in ReplayMobilePadFile class
import bob.io.base
import numpy as np
from bob.pad.face.database import VideoPadFile # Used in ReplayPadFile class
from bob.pad.base.database import FileListPadDatabase
#==============================================================================
class MIFSPadFile(VideoPadFile):
"""
A high level implementation of the File class for the MIFS database.
"""
def __init__(self, client_id, path, attack_type=None, file_id=None):
super(MIFSPadFile, self).__init__(client_id, path, attack_type,
file_id)
#==========================================================================
def load():
"""
Overridden version of the load method defined in the ``VideoPadFile``.
**Parameters:**