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

Add a failsafevideo wrapper

parent 2d2ebde7
from collections import OrderedDict
from bob.bio.face.annotator import Base, min_face_size_validator
from .. import utils
import logging
logger = logging.getLogger(__name__)
class FailSafeVideo(Base):
"""A fail-safe video annotator.
It tries several annotators in order and tries the next one if the previous
one fails. However, the difference between this annotator and
:any:`bob.bio.base.annotator.FailSafe` is that this one tries to use
annotations from older frames (if valid) before trying the next annotator.
Attributes
----------
annotators : list
A list of annotators to try
max_age : int
The maximum number of frames that an annotation is valid for next frames.
This value should be positive. If you want to set max_age to infinite,
then you can use the :any:`bob.bio.video.annotator.Wrapper` instead.
required_keys : list
A list of keys that should be available in annotations to stop trying
different annotators.
validator : callable
A function that takes the annotations and validates it.
"""
def __init__(self, annotators, required_keys, max_age=20,
validator=min_face_size_validator, **kwargs):
super(FailSafeVideo, self).__init__(**kwargs)
assert max_age > 0, "max_age: `{}' cannot be less than 1".format(max_age)
self.annotators = list(annotators)
self.required_keys = list(required_keys)
self.max_age = max_age
self.validator = validator
def annotate(self, frames, **kwargs):
if isinstance(frames, utils.FrameContainer):
frames = frames.as_array()
annotations = OrderedDict()
current = {}
age = 0
for i, frame in enumerate(frames):
for annotator in self.annotators:
annot = annotator.annotate(frame, **kwargs)
if annot and self.validator(annot):
current = annot
age = 0
break
elif age < self.max_age:
age += 1
break
else: # no detections and age is larger than maximum allowed
current = {}
if current is not annot:
logger.debug("Annotator `%s' failed.", annotator)
annotations[str(i)] = current
return annotations
......@@ -2,72 +2,11 @@ from collections import OrderedDict
from bob.bio.face.annotator import Base
from bob.ip.facedetect import bounding_box_from_annotation
from bob.bio.base import load_resource
from bob.bio.face.annotator import min_face_size_validator
from .. import utils
def normalize_annotations(annotations, validator, max_age=-1):
"""Normalizes the annotations of one video sequence. It fills the
annotations for frames from previous ones if the annotation for the current
frame is not valid.
Parameters
----------
annotations : dict
A dict of dict where the keys to the first dict are frame indices as
strings (starting from 0). The inside dicts contain annotations for
that frame.
validator : callable
Takes a dict (annotations) and returns True if the annotations are
valid. This can be check based on minimal face size for example.
max_age : :obj:`int`, optional
An integer indicating for a how many frames a detected face is valid if
no detection occurs after such frame. A value of -1 == forever
Yields
------
str
The index of frame.
dict
The corrected annotations of the frame.
"""
# the annotations for the current frame
current = {}
age = 0
for k, annot in annotations.items():
if annot and validator(annot):
current = annot
age = 0
elif max_age < 0 or age < max_age:
age += 1
else: # no detections and age is larger than maximum allowed
current = {}
yield k, current
def min_face_size_validator(annotations, min_face_size=32):
"""Validates annotations based on face's minimal size.
Parameters
----------
annotations : dict
The annotations in dictionary format.
min_face_size : int, optional
The minimal size of a face.
Returns
-------
bool
True, if the face is large enough.
"""
bbx = bounding_box_from_annotation(source='direct', **annotations)
if bbx.size < 32:
return False
return True
class Wrapper(Base):
"""Annotates video files.
This annotator does not support annotating only select frames of a video.
......@@ -98,7 +37,7 @@ class Wrapper(Base):
self.max_age = max_age
# load annotator configuration
if isinstance(annotator, basestring):
if isinstance(annotator, str):
self.annotator = load_resource(annotator, "annotator")
def annotate(self, frames, **kwargs):
......
from .Wrapper import Wrapper, normalize_annotations, min_face_size_validator
from .Wrapper import Wrapper
from .FailSafeVideo import FailSafeVideo
def normalize_annotations(annotations, validator, max_age=-1):
"""Normalizes the annotations of one video sequence. It fills the
annotations for frames from previous ones if the annotation for the current
frame is not valid.
Parameters
----------
annotations : dict
A dict of dict where the keys to the first dict are frame indices as
strings (starting from 0). The inside dicts contain annotations for
that frame.
validator : callable
Takes a dict (annotations) and returns True if the annotations are
valid. This can be check based on minimal face size for example.
max_age : :obj:`int`, optional
An integer indicating for a how many frames a detected face is valid if
no detection occurs after such frame. A value of -1 == forever
Yields
------
str
The index of frame.
dict
The corrected annotations of the frame.
"""
# the annotations for the current frame
current = {}
age = 0
for k, annot in annotations.items():
if annot and validator(annot):
current = annot
age = 0
elif max_age < 0 or age < max_age:
age += 1
else: # no detections and age is larger than maximum allowed
current = {}
yield k, current
# gets sphinx autodoc done right - don't remove it
def __appropriate__(*args):
"""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
----------
*args
An iterable of objects to modify
Resolves `Sphinx referencing issues
<https://github.com/sphinx-doc/sphinx/issues/3048>`
"""
for obj in args:
obj.__module__ = __name__
__appropriate__(
Wrapper,
FailSafeVideo,
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment