Commit 1e8e19f2 authored by Amir MOHAMMADI's avatar Amir MOHAMMADI
Browse files

Add more documentation and write tests

parent 12e27e31
Pipeline #17550 failed with stage
in 62 minutes and 32 seconds
from bob.ip.facedetect import bounding_box_from_annotation
from .Base import Base
import bob.ip.facedetect
def bounding_box_to_annotations(bbx):
"""Converts :any:`bob.ip.facedetect.BoundingBox` to dictionary annotations.
Parameters
----------
bbx : :any:`bob.ip.facedetect.BoundingBox`
The given bounding box.
Returns
-------
dict
A dictionary with topleft and bottomright keys.
"""
landmarks = {
'topleft': bbx.topleft,
'bottomright': bbx.bottomright,
......@@ -17,7 +28,7 @@ def min_face_size_validator(annotations, min_face_size=(32, 32)):
----------
annotations : dict
The annotations in dictionary format.
min_face_size : (int, int), optional
min_face_size : (:obj:`int`, :obj:`int`), optional
The minimal size of a face.
Returns
......@@ -25,12 +36,21 @@ def min_face_size_validator(annotations, min_face_size=(32, 32)):
bool
True, if the face is large enough.
"""
bbx = bounding_box_from_annotation(source='direct', **annotations)
bbx = bob.ip.facedetect.bounding_box_from_annotations(
source='direct', **annotations)
if bbx.size < min_face_size:
return False
return True
# These imports should be here to avoid circular dependencies
from .Base import Base
from .bobipfacedetect import BobIpFacedetect, BoundingBoxToEyes
from .bobipflandmark import BobIpFlandmark
from .bobipdlib import BobIpDlib
from .bobipmtcnn import BobIpMTCNN
# gets sphinx autodoc done right - don't remove it
def __appropriate__(*args):
"""Says object was actually declared here, and not in the import module.
......@@ -52,6 +72,11 @@ def __appropriate__(*args):
__appropriate__(
Base,
BobIpFacedetect,
BoundingBoxToEyes,
BobIpFlandmark,
BobIpDlib,
BobIpMTCNN,
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
......@@ -42,7 +42,8 @@ class BobIpFacedetect(Base):
The annotations in a dictionary. The keys are topleft, bottomright,
quality, leye, reye.
"""
image = rgb_to_gray(image)
if image.ndim == 3:
image = rgb_to_gray(image)
bounding_box, quality = detect_single_face(
image, self.cascade, self.sampler, self.detection_overlap)
landmarks = bounding_box_to_annotations(bounding_box)
......@@ -53,6 +54,17 @@ class BobIpFacedetect(Base):
class BoundingBoxToEyes(Base):
"""Converts bounding box annotations to eye locations. The bounding box's
annotations is expected to have come from :any:`BobIpFacedetect`.
Example usage:
.. doctest::
>>> from bob.bio.base.annotator import FailSafe
>>> from bob.bio.face.annotator import (
... BobIpFacedetect, BoundingBoxToEyes)
>>> annotator = FailSafe(
... [BobIpFacedetect(), BoundingBoxToEyes()],
... required_keys=('reye', 'leye'))
"""
def annotate(self, image, annotations, **kwargs):
......@@ -73,7 +85,5 @@ class BoundingBoxToEyes(Base):
The annotations with reye and leye locations added.
"""
bbx = bounding_box_from_annotation(source='direct', **annotations)
# make a copy of the annotations
annotations = dict(annotations)
annotations.update(expected_eye_positions(bbx))
return annotations
......@@ -5,7 +5,19 @@ from bob.ip.flandmark import Flandmark
class BobIpFlandmark(Base):
"""Annotator using bob.ip.flandmark.
This annotator needs the topleft and bottomright annotations provided."""
This annotator needs the topleft and bottomright annotations provided.
Example usage:
.. doctest::
>>> from bob.bio.base.annotator import FailSafe
>>> from bob.bio.face.annotator import (
... BobIpFacedetect, BobIpFlandmark)
>>> annotator = FailSafe(
... [BobIpFacedetect(), BobIpFlandmark()],
... required_keys=('reye', 'leye'))
"""
def __init__(self, **kwargs):
super(BobIpFlandmark, self).__init__(**kwargs)
......@@ -28,7 +40,8 @@ class BobIpFlandmark(Base):
dict
Annotations with reye and leye keys or None if it fails.
"""
image = rgb_to_gray(image)
if image.ndim == 3:
image = rgb_to_gray(image)
top, left = annotations['topleft']
top, left = int(max(top, 0)), int(max(left, 0))
height = annotations['bottomright'][0] - top
......
from bob.bio.face.annotator import BobIpDlib
annotator = BobIpDlib()
from bob.bio.face.annotator import BobIpFacedetect
annotator = BobIpFacedetect()
from bob.bio.base.annotator import FailSafe
from bob.bio.face.annotator import BobIpFacedetect, BoundingBoxToEyes
annotator = FailSafe(
[BobIpFacedetect(), BoundingBoxToEyes()],
required_keys=('reye', 'leye'))
from bob.bio.base.annotator import FailSafe
from bob.bio.face.annotator import BobIpFacedetect, BobIpFlandmark
annotator = FailSafe(
[BobIpFacedetect(), BobIpFlandmark()],
required_keys=('reye', 'leye'))
from bob.bio.face.annotator import BobIpMTCNN
annotator = BobIpMTCNN()
import bob.bio.base
import six
def load_cropper(face_cropper):
......@@ -6,7 +7,7 @@ def load_cropper(face_cropper):
from .FaceDetect import FaceDetect
if face_cropper is None:
cropper = None
elif isinstance(face_cropper, str):
elif isinstance(face_cropper, six.string_types):
cropper = bob.bio.base.load_resource(face_cropper, 'preprocessor')
elif isinstance(face_cropper, (FaceCrop, FaceDetect)):
cropper = face_cropper
......@@ -21,7 +22,7 @@ def load_cropper_only(face_cropper):
from .FaceCrop import FaceCrop
if face_cropper is None:
cropper = None
elif isinstance(face_cropper, str):
elif isinstance(face_cropper, six.string_types):
cropper = bob.bio.base.load_resource(face_cropper, 'preprocessor')
elif isinstance(face_cropper, FaceCrop):
cropper = face_cropper
......
import bob.io.base
import bob.io.base.test_utils
import bob.io.image
import bob.ip.facedetect
from bob.bio.face.annotator import (
BobIpFacedetect, BoundingBoxToEyes, BobIpFlandmark)
from bob.bio.base.annotator import FailSafe
import numpy
face_image = bob.io.base.load(bob.io.base.test_utils.datafile(
'testimage.jpg', 'bob.ip.facedetect'))
def test_bob_ip_facedetect():
from bob.bio.face.annotator.bobipfacedetect import BobIpFacedetect
annot = BobIpFacedetect()(face_image)
def _assert_bob_ip_facedetect(annot):
assert annot['topleft'] == (110, 82), annot
assert annot['bottomright'] == (334, 268), annot
assert numpy.allclose(annot['quality'], 39.209601948013685), annot
def test_bob_ip_facedetect():
from bob.bio.face.annotator.bobipfacedetect import BobIpFacedetect
annot = BobIpFacedetect()(face_image)
_assert_bob_ip_facedetect(annot)
def test_bob_ip_facedetect_eyes():
annotator = FailSafe(
[BobIpFacedetect(), BoundingBoxToEyes()],
required_keys=('reye', 'leye'),
)
annot = annotator(face_image)
_assert_bob_ip_facedetect(annot)
assert [int(x) for x in annot['reye']] == [175, 128], annot
assert [int(x) for x in annot['leye']] == [175, 221], annot
def test_bob_ip_flandmark():
annotator = FailSafe(
[BobIpFacedetect(), BobIpFlandmark()],
required_keys=('reye', 'leye'),
)
annot = annotator(face_image)
_assert_bob_ip_facedetect(annot)
assert [int(x) for x in annot['reye']] == [183, 127], annot
assert [int(x) for x in annot['leye']] == [174, 223], annot
......@@ -45,10 +45,12 @@ requirements:
- bob.ip.facedetect
- bob.ip.flandmark
- matplotlib {{ matplotlib }}
- six {{ six }}
run:
- python
- setuptools
- matplotlib
- six
test:
imports:
......
.. vim: set fileencoding=utf-8 :
.. _bob.bio.face.annotators:
=================
Face Annotators
=================
This packages provides several face annotators (using RGB images) that you can
use to annotate biometric databases. See :ref:`bob.bio.base.annotations` for
a guide on the general usage of this feature.
.. warning::
The annotators are named after the package that provides this annotator.
Their respective |project| packages need to be installed if you want to use
them.
See :doc:`implemented` for a list of available annotators. Here is an example
on how to use :any:`bob.bio.face.annotator.BobIpFlandmark` to annotate the ATNT
database:
.. code-block:: sh
$ bob bio annotate -vvv -d atnt -a flandmark -o /tmp/annotations
......@@ -4,7 +4,6 @@ bob.bio.base
bob.io.base
bob.ip.gabor
bob.ip.base
bob.bio.speaker
bob.bio.gmm
bob.bio.video
bob.bio.csu
......@@ -14,4 +13,4 @@ bob.ip.facedetect
bob.ip.flandmark
bob.learn.linear
gridtk
bob.db.youtube
\ No newline at end of file
bob.db.youtube
......@@ -27,6 +27,19 @@ Databases
bob.bio.face.database.FRGCBioDatabase
bob.bio.face.database.SCFaceBioDatabase
Face Image Annotators
~~~~~~~~~~~~~~~~~~~~~
.. autosummary::
bob.bio.face.annotator.Base
bob.bio.face.annotator.BobIpFacedetect
bob.bio.face.annotator.BoundingBoxToEyes
bob.bio.face.annotator.BobIpFlandmark
bob.bio.face.annotator.BobIpDlib
bob.bio.face.annotator.BobIpMTCNN
Image Preprocessors
~~~~~~~~~~~~~~~~~~~
......@@ -41,7 +54,6 @@ Image Preprocessors
bob.bio.face.preprocessor.INormLBP
Image Feature Extractors
~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -59,10 +71,16 @@ Face Recognition Algorithms
bob.bio.face.algorithm.GaborJet
bob.bio.face.algorithm.Histogram
Databases
---------
.. automodule:: bob.bio.face.database
Annotators
----------
.. automodule:: bob.bio.face.annotator
Preprocessors
-------------
......@@ -78,4 +96,5 @@ Algorithms
.. automodule:: bob.bio.face.algorithm
.. include:: links.rst
......@@ -37,6 +37,7 @@ Users Guide
baselines
implementation
references
annotators
Reference Manual
================
......
......@@ -21,3 +21,4 @@ bob.learn.boosting
bob.ip.facedetect
bob.ip.flandmark
matplotlib # for plotting
six
......@@ -134,6 +134,14 @@ setup(
'replaymobile-img-spoof = bob.bio.face.config.database.replaymobile:replaymobile_spoof',
],
'bob.bio.annotator': [
'facedetect = bob.bio.face.config.annotator.facedetect:annotator',
'facedetect-eye-estimate = bob.bio.face.config.annotator.facedetect_eye_estimate:annotator',
'flandmark = bob.bio.face.config.annotator.flandmark:annotator',
'dlib = bob.bio.face.config.annotator.dlib:annotator',
'mtcnn = bob.bio.face.config.annotator.mtcnn:annotator',
],
'bob.bio.preprocessor': [
'base = bob.bio.face.config.preprocessor.base:preprocessor', # simple color conversion
'face-crop-eyes = bob.bio.face.config.preprocessor.face_crop_eyes:preprocessor', # face crop
......
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