#!/usr/bin/env python2
# -*- coding: utf-8 -*-
# Used in ReplayMobilePadFile class
from bob.bio.video import FrameSelector
from bob.pad.base.database import PadDatabase
from bob.pad.face.database import VideoPadFile
from bob.pad.face.utils import number_of_frames
from bob.db.base.annotations import read_annotation_file
from bob.extension import rc
REPLAYMOBILE_FRAME_SHAPE = (3, 1280, 720)
[docs]class ReplayMobilePadFile(VideoPadFile):
"""
A high level implementation of the File class for the Replay-Mobile
database.
"""
def __init__(self, f):
"""
Parameters
----------
f : object
An instance of the File class defined in the low level db interface
of the Replay-Mobile database, in the bob.db.replaymobile.models.py
file.
"""
self.f = f
# this f is actually an instance of the File class that is defined in
# bob.db.replaymobile.models and the PadFile class here needs
# client_id, path, attack_type, file_id for initialization. We have to
# convert information here and provide them to PadFile. attack_type is
# a little tricky to get here. Based on the documentation of PadFile:
# In cased of a spoofed data, this parameter should indicate what kind
# of spoofed attack it is. The default None value is interpreted that
# the PadFile is a genuine or real sample.
if f.is_real():
attack_type = None
else:
attack_type = 'attack'
# attack_type is a string and I decided to make it like this for this
# particular database. You can do whatever you want for your own
# database.
super(ReplayMobilePadFile, self).__init__(
client_id=f.client_id,
path=f.path,
attack_type=attack_type,
file_id=f.id)
[docs] def load(self, directory=None, extension='.mov',
frame_selector=FrameSelector(selection_style='all')):
"""
Overridden version of the load method defined in the ``VideoPadFile``.
Parameters
----------
directory : str
String containing the path to the Replay-Mobile database.
extension : str
Extension of the video files in the Replay-Mobile database.
frame_selector : :any:`bob.bio.video.FrameSelector`
The frame selector to use.
Returns
-------
video_data : :any:`bob.bio.video.FrameContainer`
Video data stored in the FrameContainer, see
``bob.bio.video.utils.FrameContainer`` for further details.
"""
directory = directory or self.original_directory
video_data_array = self.f.load(
directory=directory, extension=extension)
return frame_selector(video_data_array)
@property
def annotations(self):
from bob.db.replaymobile.models import replaymobile_annotations
if self.annotation_directory is not None:
# return the external annotations
annotations = read_annotation_file(
self.make_path(self.annotation_directory,
self.annotation_extension),
self.annotation_type)
return annotations
# return original annotations
return replaymobile_annotations(self.f, self.original_directory)
@property
def frames(self):
from bob.db.replaymobile.models import replaymobile_frames
return replaymobile_frames(self.f, self.original_directory)
@property
def number_of_frames(self):
vfilename = self.make_path(
directory=self.original_directory,
extension='.mov')
return number_of_frames(vfilename)
@property
def frame_shape(self):
return REPLAYMOBILE_FRAME_SHAPE
class ReplayMobilePadDatabase(PadDatabase):
"""
A high level implementation of the Database class for the Replay-Mobile
database.
"""
def __init__(
self,
protocol='grandtest',
original_directory=rc['bob.db.replaymobile.directory'],
original_extension='.mov',
annotation_directory=None,
annotation_extension='.json',
annotation_type='json',
**kwargs):
"""
Parameters
----------
protocol : str or None
The name of the protocol that defines the default experimental
setup for this database. ``grandtest`` is the default protocol for
this database.
original_directory : str
The directory where the original data of the database are stored.
original_extension : str
The file name extension of the original data.
annotation_directory : str
If provided, the annotations will be read from this directory
instead of the default annotations that are provided.
annotation_extension : str
The extension of annotations when annotation_extension is provided.
**kwargs
The arguments of the :py:class:`bob.bio.base.database.BioDatabase`
base class constructor.
"""
from bob.db.replaymobile 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') # 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(ReplayMobilePadDatabase, self).__init__(
name='replay-mobile',
protocol=protocol,
original_directory=original_directory,
original_extension=original_extension,
annotation_directory=annotation_directory,
annotation_extension=annotation_extension,
annotation_type=annotation_type,
**kwargs)
@property
def original_directory(self):
return self.db.original_directory
@original_directory.setter
def original_directory(self, value):
self.db.original_directory = value
[docs] def objects(self,
groups=None,
protocol=None,
purposes=None,
model_ids=None,
**kwargs):
"""
This function returns lists of ReplayMobilePadFile objects, which
fulfill the given restrictions.
Parameters
----------
groups : 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 : 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 : 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
**kwargs
Returns
-------
files : [ReplayMobilePadFile]
A list of ReplayMobilePadFile 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.
files = self.db.objects(
protocol=protocol, groups=groups, cls=purposes, **kwargs)
files = [ReplayMobilePadFile(f) for f in files]
for f in files:
f.original_directory = self.original_directory
f.annotation_directory = self.annotation_directory
f.annotation_extension = self.annotation_extension
f.annotation_type = self.annotation_type
return files
[docs] def annotations(self, f):
"""
Return annotations for a given file object ``f``, which is an instance
of ``ReplayMobilePadFile`` defined in the HLDI of the Replay-Mobile DB.
The ``load()`` method of ``ReplayMobilePadFile`` 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.
If ``self.annotation_directory`` is not None, it will read the
annotations from there.
Parameters
----------
f : :any:`ReplayMobilePadFile`
An instance of :any:`ReplayMobilePadFile` 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 f.annotations
[docs] def frames(self, padfile):
"""Yields the frames of the padfile one by one.
Parameters
----------
padfile : :any:`ReplayMobilePadFile`
The high-level replay pad file
Yields
------
:any:`numpy.array`
A frame of the video. The size is (3, 1280, 720).
"""
return padfile.frames
[docs] def number_of_frames(self, padfile):
"""Returns the number of frames in a video file.
Parameters
----------
padfile : :any:`ReplayPadFile`
The high-level pad file
Returns
-------
int
The number of frames.
"""
return padfile.number_of_frames
@property
def frame_shape(self):
"""Returns the size of each frame in this database.
Returns
-------
(int, int, int)
The (#Channels, Height, Width) which is (3, 1280, 720).
"""
return REPLAYMOBILE_FRAME_SHAPE