diff --git a/bob/bio/face/annotator/__init__.py b/bob/bio/face/annotator/__init__.py
index 83adf1d8d9d1ae3ab7d5572edeb72abc38e85553..ce553638a891bb84b554f9c323834e1931e060a1 100644
--- a/bob/bio/face/annotator/__init__.py
+++ b/bob/bio/face/annotator/__init__.py
@@ -1,8 +1,19 @@
-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('_')]
diff --git a/bob/bio/face/annotator/bobipfacedetect.py b/bob/bio/face/annotator/bobipfacedetect.py
index 46bd27cdce528f0fd0b8e6b06dba3d59997667b3..afae049212c06cb8314054bda5337f0e8978acf5 100644
--- a/bob/bio/face/annotator/bobipfacedetect.py
+++ b/bob/bio/face/annotator/bobipfacedetect.py
@@ -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
diff --git a/bob/bio/face/annotator/bobipflandmark.py b/bob/bio/face/annotator/bobipflandmark.py
index cd1552af8157aa0460a8f66d04c4d42d8412bfbc..3d099fa099809202318786b0835861c14ddbc4e1 100644
--- a/bob/bio/face/annotator/bobipflandmark.py
+++ b/bob/bio/face/annotator/bobipflandmark.py
@@ -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
diff --git a/bob/bio/face/config/annotator/__init__.py b/bob/bio/face/config/annotator/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/bob/bio/face/config/annotator/dlib.py b/bob/bio/face/config/annotator/dlib.py
new file mode 100644
index 0000000000000000000000000000000000000000..5475604c9bc580fe416efda6ddabbbca91989df2
--- /dev/null
+++ b/bob/bio/face/config/annotator/dlib.py
@@ -0,0 +1,3 @@
+from bob.bio.face.annotator import BobIpDlib
+
+annotator = BobIpDlib()
diff --git a/bob/bio/face/config/annotator/facedetect.py b/bob/bio/face/config/annotator/facedetect.py
new file mode 100644
index 0000000000000000000000000000000000000000..f39c8a118128dc44068482b4965bcc226d20016b
--- /dev/null
+++ b/bob/bio/face/config/annotator/facedetect.py
@@ -0,0 +1,3 @@
+from bob.bio.face.annotator import BobIpFacedetect
+
+annotator = BobIpFacedetect()
diff --git a/bob/bio/face/config/annotator/facedetect_eye_estimate.py b/bob/bio/face/config/annotator/facedetect_eye_estimate.py
new file mode 100644
index 0000000000000000000000000000000000000000..a42e19116a087a0fbec07d5b9e5b214b06b48b87
--- /dev/null
+++ b/bob/bio/face/config/annotator/facedetect_eye_estimate.py
@@ -0,0 +1,6 @@
+from bob.bio.base.annotator import FailSafe
+from bob.bio.face.annotator import BobIpFacedetect, BoundingBoxToEyes
+
+annotator = FailSafe(
+    [BobIpFacedetect(), BoundingBoxToEyes()],
+    required_keys=('reye', 'leye'))
diff --git a/bob/bio/face/config/annotator/flandmark.py b/bob/bio/face/config/annotator/flandmark.py
new file mode 100644
index 0000000000000000000000000000000000000000..e473b8d8506cf770f5134c8bb1001bbb7c588711
--- /dev/null
+++ b/bob/bio/face/config/annotator/flandmark.py
@@ -0,0 +1,6 @@
+from bob.bio.base.annotator import FailSafe
+from bob.bio.face.annotator import BobIpFacedetect, BobIpFlandmark
+
+annotator = FailSafe(
+    [BobIpFacedetect(), BobIpFlandmark()],
+    required_keys=('reye', 'leye'))
diff --git a/bob/bio/face/config/annotator/mtcnn.py b/bob/bio/face/config/annotator/mtcnn.py
new file mode 100644
index 0000000000000000000000000000000000000000..6dcfb2a5ea9bbaac33a3793dd8b0c6ffeb126b2b
--- /dev/null
+++ b/bob/bio/face/config/annotator/mtcnn.py
@@ -0,0 +1,3 @@
+from bob.bio.face.annotator import BobIpMTCNN
+
+annotator = BobIpMTCNN()
diff --git a/bob/bio/face/preprocessor/utils.py b/bob/bio/face/preprocessor/utils.py
index 01c350549d8774170d4f420b22f49daf6b31aca1..7be6bfe6ce5d9498d3a88a9b53a8f56aea210cae 100644
--- a/bob/bio/face/preprocessor/utils.py
+++ b/bob/bio/face/preprocessor/utils.py
@@ -1,4 +1,5 @@
 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
diff --git a/bob/bio/face/test/test_annotators.py b/bob/bio/face/test/test_annotators.py
index db4a8e665b4664310a6ef267627f3c6b179b358f..4f71886e0124738751270f132f9b042fb8a9af35 100644
--- a/bob/bio/face/test/test_annotators.py
+++ b/bob/bio/face/test/test_annotators.py
@@ -1,16 +1,48 @@
 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
diff --git a/conda/meta.yaml b/conda/meta.yaml
index 2a7b011ec064e6ad8882777779cf4e65de593ffa..4e408a42b6fbc9415bb1a6ddf1115348fefa3c52 100644
--- a/conda/meta.yaml
+++ b/conda/meta.yaml
@@ -45,10 +45,12 @@ requirements:
     - bob.ip.facedetect
     - bob.ip.flandmark
     - matplotlib {{ matplotlib }}
+    - six {{ six }}
   run:
     - python
     - setuptools
     - matplotlib
+    - six
 
 test:
   imports:
diff --git a/doc/annotators.rst b/doc/annotators.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b7cb0abf8051202fed2ee56924bb6df2863e5050
--- /dev/null
+++ b/doc/annotators.rst
@@ -0,0 +1,25 @@
+.. 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
diff --git a/doc/extra-intersphinx.txt b/doc/extra-intersphinx.txt
index 03938bdd20d5e43e2e1b18dc1d16365e57f5eb20..c82f95f8fd7a78b61d0116246d7a6f2ff9a69a65 100644
--- a/doc/extra-intersphinx.txt
+++ b/doc/extra-intersphinx.txt
@@ -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
diff --git a/doc/implemented.rst b/doc/implemented.rst
index c5f98bee1b8fa742ac5112fc1ae3b25727881189..c00192097f092b0fee8a7ba7fcd96be6e5108bcf 100644
--- a/doc/implemented.rst
+++ b/doc/implemented.rst
@@ -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
diff --git a/doc/index.rst b/doc/index.rst
index 1f0b9b5758a3c38a53a89c96760f0b611fd85b55..361114f346038cc84fba6ef2377f65e823ac6a9c 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -37,6 +37,7 @@ Users Guide
    baselines
    implementation
    references
+   annotators
 
 Reference Manual
 ================
diff --git a/requirements.txt b/requirements.txt
index 35383328ae4c7e7c459168579874a4471141693a..4dc31984ef4954f5d97cf1a33972148d2169222c 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -21,3 +21,4 @@ bob.learn.boosting
 bob.ip.facedetect
 bob.ip.flandmark
 matplotlib   # for plotting
+six
diff --git a/setup.py b/setup.py
index e0e5768d9cc0d6326553634cf47a3e230eea933d..05079868fb561109918f32b5b1b53a12f20e4a82 100644
--- a/setup.py
+++ b/setup.py
@@ -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