diff --git a/bob/pad/face/config/lbp_svm.py b/bob/pad/face/config/lbp_svm.py
index 3261e8ff815e23c2edd3609ce32d2a0b9f31a1af..ecaf7d031519998fe75a8c0d4fe3a9fd0c5e6979 100644
--- a/bob/pad/face/config/lbp_svm.py
+++ b/bob/pad/face/config/lbp_svm.py
@@ -20,35 +20,35 @@ this resource.
 #=======================================================================================
 # define preprocessor:
 
-from ..preprocessor import VideoFaceCrop
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50  # Minimal possible size of the face
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-COLOR_CHANNEL = 'gray'  # Convert image to gray-scale format
-
-preprocessor = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    color_channel=COLOR_CHANNEL)
+from ..preprocessor import FaceCropAlign
+
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+FACE_SIZE = 64 # The size of the resulting face
+RGB_OUTPUT_FLAG = False # Gray-scale output
+USE_FACE_ALIGNMENT = False # use annotations
+MAX_IMAGE_SIZE = None # no limiting here
+FACE_DETECTION_METHOD = None # use annotations
+MIN_FACE_SIZE = 50 # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                   rgb_output_flag = RGB_OUTPUT_FLAG,
+                                   use_face_alignment = USE_FACE_ALIGNMENT,
+                                   max_image_size = MAX_IMAGE_SIZE,
+                                   face_detection_method = FACE_DETECTION_METHOD,
+                                   min_face_size = MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+preprocessor = Wrapper(preprocessor = _image_preprocessor,
+                       frame_selector = _frame_selector)
 """
 In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
-The size of the face is normalized to ``cropped_image_size`` dimensions. The faces with the size
-below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
-[CAM12]_, which is defined by ``use_local_cropper_flag = True``.
+The size of the face is normalized to ``FACE_SIZE`` dimensions. The faces with the size
+below ``MIN_FACE_SIZE`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``FACE_DETECTION_METHOD = None``.
 """
 
 #=======================================================================================
diff --git a/bob/pad/face/config/lbp_svm_aggregated_db.py b/bob/pad/face/config/lbp_svm_aggregated_db.py
index 778364e8c7d69047cc4218cbec6136312e05161d..27313a4cc8f889bd997f9571034915f3d2846c8b 100644
--- a/bob/pad/face/config/lbp_svm_aggregated_db.py
+++ b/bob/pad/face/config/lbp_svm_aggregated_db.py
@@ -22,35 +22,35 @@ this resource.
 #=======================================================================================
 # define preprocessor:
 
-from ..preprocessor import VideoFaceCrop
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50  # Minimal possible size of the face
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-COLOR_CHANNEL = 'gray'  # Convert image to gray-scale format
-
-preprocessor = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    color_channel=COLOR_CHANNEL)
+from ..preprocessor import FaceCropAlign
+
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+FACE_SIZE = 64 # The size of the resulting face
+RGB_OUTPUT_FLAG = False # Gray-scale output
+USE_FACE_ALIGNMENT = False # use annotations
+MAX_IMAGE_SIZE = None # no limiting here
+FACE_DETECTION_METHOD = None # use annotations
+MIN_FACE_SIZE = 50 # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                   rgb_output_flag = RGB_OUTPUT_FLAG,
+                                   use_face_alignment = USE_FACE_ALIGNMENT,
+                                   max_image_size = MAX_IMAGE_SIZE,
+                                   face_detection_method = FACE_DETECTION_METHOD,
+                                   min_face_size = MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+preprocessor = Wrapper(preprocessor = _image_preprocessor,
+                       frame_selector = _frame_selector)
 """
 In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
-The size of the face is normalized to ``cropped_image_size`` dimensions. The faces with the size
-below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
-[CAM12]_, which is defined by ``use_local_cropper_flag = True``.
+The size of the face is normalized to ``FACE_SIZE`` dimensions. The faces with the size
+below ``MIN_FACE_SIZE`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``FACE_DETECTION_METHOD = None``.
 """
 
 #=======================================================================================
diff --git a/bob/pad/face/config/preprocessor/video_face_crop.py b/bob/pad/face/config/preprocessor/video_face_crop.py
index 08ed1448ed1240d7ce60ef81de560ad336a0ba5d..924ada95ba8eec4ccc4d1bb6dd5120d8d450e655 100644
--- a/bob/pad/face/config/preprocessor/video_face_crop.py
+++ b/bob/pad/face/config/preprocessor/video_face_crop.py
@@ -1,61 +1,44 @@
 #!/usr/bin/env python2
 # -*- coding: utf-8 -*-
 
-from bob.pad.face.preprocessor import VideoFaceCrop
+from ..preprocessor import FaceCropAlign
 
-#=======================================================================================
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+# =======================================================================================
 # Define instances here:
 
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-DETECT_FACES_FLAG = True  # find annotations locally replacing the database annotations
-FACE_DETECTION_METHOD = "dlib"
-
-rgb_face_detector_dlib = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    rgb_output_flag=RGB_OUTPUT_FLAG,
-    detect_faces_flag=DETECT_FACES_FLAG,
-    face_detection_method=FACE_DETECTION_METHOD)
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-DETECT_FACES_FLAG = True  # find annotations locally replacing the database annotations
-FACE_DETECTION_METHOD = "mtcnn"
-
-rgb_face_detector_mtcnn = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    rgb_output_flag=RGB_OUTPUT_FLAG,
-    detect_faces_flag=DETECT_FACES_FLAG,
-    face_detection_method=FACE_DETECTION_METHOD)
+
+FACE_SIZE = 64  # The size of the resulting face
+RGB_OUTPUT_FLAG = True  # RGB output
+USE_FACE_ALIGNMENT = False  #
+MAX_IMAGE_SIZE = None  # no limiting here
+FACE_DETECTION_METHOD = "dlib"  # use dlib face detection
+MIN_FACE_SIZE = 50  # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size=FACE_SIZE,
+                                    rgb_output_flag=RGB_OUTPUT_FLAG,
+                                    use_face_alignment=USE_FACE_ALIGNMENT,
+                                    max_image_size=MAX_IMAGE_SIZE,
+                                    face_detection_method=FACE_DETECTION_METHOD,
+                                    min_face_size=MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+rgb_face_detector_dlib = Wrapper(preprocessor = _image_preprocessor,
+                                 frame_selector = _frame_selector)
+
+# =======================================================================================
+FACE_DETECTION_METHOD = "mtcnn"  # use mtcnn face detection
+
+_image_preprocessor = FaceCropAlign(face_size=FACE_SIZE,
+                                    rgb_output_flag=RGB_OUTPUT_FLAG,
+                                    use_face_alignment=USE_FACE_ALIGNMENT,
+                                    max_image_size=MAX_IMAGE_SIZE,
+                                    face_detection_method=FACE_DETECTION_METHOD,
+                                    min_face_size=MIN_FACE_SIZE)
+
+rgb_face_detector_mtcnn = Wrapper(preprocessor = _image_preprocessor,
+                                  frame_selector = _frame_selector)
diff --git a/bob/pad/face/config/qm_lr.py b/bob/pad/face/config/qm_lr.py
index 19a5d4221f0156c01e32d78a09ed848468416ff3..f936d2a5ebfa2a409c70e60db3a2b91989255c5b 100644
--- a/bob/pad/face/config/qm_lr.py
+++ b/bob/pad/face/config/qm_lr.py
@@ -19,35 +19,35 @@ this resource.
 #=======================================================================================
 # define preprocessor:
 
-from ..preprocessor import VideoFaceCrop
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-
-preprocessor = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    rgb_output_flag=RGB_OUTPUT_FLAG)
+from ..preprocessor import FaceCropAlign
+
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+FACE_SIZE = 64 # The size of the resulting face
+RGB_OUTPUT_FLAG = True # RGB output
+USE_FACE_ALIGNMENT = False # use annotations
+MAX_IMAGE_SIZE = None # no limiting here
+FACE_DETECTION_METHOD = None # use annotations
+MIN_FACE_SIZE = 50 # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                   rgb_output_flag = RGB_OUTPUT_FLAG,
+                                   use_face_alignment = USE_FACE_ALIGNMENT,
+                                   max_image_size = MAX_IMAGE_SIZE,
+                                   face_detection_method = FACE_DETECTION_METHOD,
+                                   min_face_size = MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+preprocessor = Wrapper(preprocessor = _image_preprocessor,
+                       frame_selector = _frame_selector)
 """
 In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
-The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
-below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
-[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+The size of the face is normalized to ``FACE_SIZE`` dimensions. The faces of the size
+below ``MIN_FACE_SIZE`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``FACE_DETECTION_METHOD = None``. The preprocessed frame is the RGB
 facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
 """
 
diff --git a/bob/pad/face/config/qm_one_class_gmm.py b/bob/pad/face/config/qm_one_class_gmm.py
index 182c71bbbe8ef8783c81c9d42a2467e6371d5d0c..cce5c5a1d5e9f4d11a9ce97cfb3411728c7365eb 100644
--- a/bob/pad/face/config/qm_one_class_gmm.py
+++ b/bob/pad/face/config/qm_one_class_gmm.py
@@ -19,35 +19,35 @@ this resource.
 #=======================================================================================
 # define preprocessor:
 
-from ..preprocessor import VideoFaceCrop
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-
-preprocessor = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    rgb_output_flag=RGB_OUTPUT_FLAG)
+from ..preprocessor import FaceCropAlign
+
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+FACE_SIZE = 64 # The size of the resulting face
+RGB_OUTPUT_FLAG = True # RGB output
+USE_FACE_ALIGNMENT = False # use annotations
+MAX_IMAGE_SIZE = None # no limiting here
+FACE_DETECTION_METHOD = None # use annotations
+MIN_FACE_SIZE = 50 # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                   rgb_output_flag = RGB_OUTPUT_FLAG,
+                                   use_face_alignment = USE_FACE_ALIGNMENT,
+                                   max_image_size = MAX_IMAGE_SIZE,
+                                   face_detection_method = FACE_DETECTION_METHOD,
+                                   min_face_size = MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+preprocessor = Wrapper(preprocessor = _image_preprocessor,
+                       frame_selector = _frame_selector)
 """
 In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
-The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
-below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
-[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+The size of the face is normalized to ``FACE_SIZE`` dimensions. The faces of the size
+below ``MIN_FACE_SIZE`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``FACE_DETECTION_METHOD = None``. The preprocessed frame is the RGB
 facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
 """
 
diff --git a/bob/pad/face/config/qm_one_class_svm_aggregated_db.py b/bob/pad/face/config/qm_one_class_svm_aggregated_db.py
index 1216d66bf9af9cf324c0b8cc0c947eb342a78ecf..3f010944feea8d5ebeb0c0cd05345d70aad65efd 100644
--- a/bob/pad/face/config/qm_one_class_svm_aggregated_db.py
+++ b/bob/pad/face/config/qm_one_class_svm_aggregated_db.py
@@ -21,35 +21,35 @@ this resource.
 #=======================================================================================
 # define preprocessor:
 
-from ..preprocessor import VideoFaceCrop
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-
-preprocessor = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    rgb_output_flag=RGB_OUTPUT_FLAG)
+from ..preprocessor import FaceCropAlign
+
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+FACE_SIZE = 64 # The size of the resulting face
+RGB_OUTPUT_FLAG = True # RGB output
+USE_FACE_ALIGNMENT = False # use annotations
+MAX_IMAGE_SIZE = None # no limiting here
+FACE_DETECTION_METHOD = None # use annotations
+MIN_FACE_SIZE = 50 # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                   rgb_output_flag = RGB_OUTPUT_FLAG,
+                                   use_face_alignment = USE_FACE_ALIGNMENT,
+                                   max_image_size = MAX_IMAGE_SIZE,
+                                   face_detection_method = FACE_DETECTION_METHOD,
+                                   min_face_size = MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+preprocessor = Wrapper(preprocessor = _image_preprocessor,
+                       frame_selector = _frame_selector)
 """
 In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
-The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
-below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
-[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+The size of the face is normalized to ``FACE_SIZE`` dimensions. The faces of the size
+below ``MIN_FACE_SIZE`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``FACE_DETECTION_METHOD = None``. The preprocessed frame is the RGB
 facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
 """
 
diff --git a/bob/pad/face/config/qm_one_class_svm_cascade_aggregated_db.py b/bob/pad/face/config/qm_one_class_svm_cascade_aggregated_db.py
index 7fcc6122020478a7828f70e357e37cd5fa1e082f..f0f04b21dc343ac5bf958012b019120bfe029b61 100644
--- a/bob/pad/face/config/qm_one_class_svm_cascade_aggregated_db.py
+++ b/bob/pad/face/config/qm_one_class_svm_cascade_aggregated_db.py
@@ -21,35 +21,35 @@ this resource.
 #=======================================================================================
 # define preprocessor:
 
-from ..preprocessor import VideoFaceCrop
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-
-preprocessor = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    rgb_output_flag=RGB_OUTPUT_FLAG)
+from ..preprocessor import FaceCropAlign
+
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+FACE_SIZE = 64 # The size of the resulting face
+RGB_OUTPUT_FLAG = True # RGB output
+USE_FACE_ALIGNMENT = False # use annotations
+MAX_IMAGE_SIZE = None # no limiting here
+FACE_DETECTION_METHOD = None # use annotations
+MIN_FACE_SIZE = 50 # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                   rgb_output_flag = RGB_OUTPUT_FLAG,
+                                   use_face_alignment = USE_FACE_ALIGNMENT,
+                                   max_image_size = MAX_IMAGE_SIZE,
+                                   face_detection_method = FACE_DETECTION_METHOD,
+                                   min_face_size = MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+preprocessor = Wrapper(preprocessor = _image_preprocessor,
+                       frame_selector = _frame_selector)
 """
 In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
-The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
-below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
-[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+The size of the face is normalized to ``FACE_SIZE`` dimensions. The faces of the size
+below ``MIN_FACE_SIZE`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``FACE_DETECTION_METHOD = None``. The preprocessed frame is the RGB
 facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
 """
 
diff --git a/bob/pad/face/config/qm_svm.py b/bob/pad/face/config/qm_svm.py
index 961a413fdbbc294ac325b2d5a694af3689cfae48..8f9b8e2563d6bcc51d3a1f11a5dd58236480c6ad 100644
--- a/bob/pad/face/config/qm_svm.py
+++ b/bob/pad/face/config/qm_svm.py
@@ -19,35 +19,35 @@ this resource.
 #=======================================================================================
 # define preprocessor:
 
-from ..preprocessor import VideoFaceCrop
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-
-preprocessor = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    rgb_output_flag=RGB_OUTPUT_FLAG)
+from ..preprocessor import FaceCropAlign
+
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+FACE_SIZE = 64 # The size of the resulting face
+RGB_OUTPUT_FLAG = True # RGB output
+USE_FACE_ALIGNMENT = False # use annotations
+MAX_IMAGE_SIZE = None # no limiting here
+FACE_DETECTION_METHOD = None # use annotations
+MIN_FACE_SIZE = 50 # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                   rgb_output_flag = RGB_OUTPUT_FLAG,
+                                   use_face_alignment = USE_FACE_ALIGNMENT,
+                                   max_image_size = MAX_IMAGE_SIZE,
+                                   face_detection_method = FACE_DETECTION_METHOD,
+                                   min_face_size = MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+preprocessor = Wrapper(preprocessor = _image_preprocessor,
+                       frame_selector = _frame_selector)
 """
 In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
-The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
-below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
-[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+The size of the face is normalized to ``FACE_SIZE`` dimensions. The faces of the size
+below ``MIN_FACE_SIZE`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``FACE_DETECTION_METHOD = None``. The preprocessed frame is the RGB
 facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
 """
 
diff --git a/bob/pad/face/config/qm_svm_aggregated_db.py b/bob/pad/face/config/qm_svm_aggregated_db.py
index 481c50b85b7ec42eaf5a1e4f59999d48bd38f605..8fafbbd5f277116557f4ec22517acb9832e6751b 100644
--- a/bob/pad/face/config/qm_svm_aggregated_db.py
+++ b/bob/pad/face/config/qm_svm_aggregated_db.py
@@ -21,35 +21,35 @@ this resource.
 #=======================================================================================
 # define preprocessor:
 
-from ..preprocessor import VideoFaceCrop
-
-CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-FIXED_POSITIONS = None
-MASK_SIGMA = None  # The sigma for random values areas outside image
-MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-MASK_SEED = None  # The seed for generating random values during extrapolation
-CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-MIN_FACE_SIZE = 50
-USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-
-preprocessor = VideoFaceCrop(
-    cropped_image_size=CROPPED_IMAGE_SIZE,
-    cropped_positions=CROPPED_POSITIONS,
-    fixed_positions=FIXED_POSITIONS,
-    mask_sigma=MASK_SIGMA,
-    mask_neighbors=MASK_NEIGHBORS,
-    mask_seed=None,
-    check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-    min_face_size=MIN_FACE_SIZE,
-    use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-    rgb_output_flag=RGB_OUTPUT_FLAG)
+from ..preprocessor import FaceCropAlign
+
+from bob.bio.video.preprocessor import Wrapper
+
+from bob.bio.video.utils import FrameSelector
+
+FACE_SIZE = 64 # The size of the resulting face
+RGB_OUTPUT_FLAG = True # RGB output
+USE_FACE_ALIGNMENT = False # use annotations
+MAX_IMAGE_SIZE = None # no limiting here
+FACE_DETECTION_METHOD = None # use annotations
+MIN_FACE_SIZE = 50 # skip small faces
+
+_image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                   rgb_output_flag = RGB_OUTPUT_FLAG,
+                                   use_face_alignment = USE_FACE_ALIGNMENT,
+                                   max_image_size = MAX_IMAGE_SIZE,
+                                   face_detection_method = FACE_DETECTION_METHOD,
+                                   min_face_size = MIN_FACE_SIZE)
+
+_frame_selector = FrameSelector(selection_style = "all")
+
+preprocessor = Wrapper(preprocessor = _image_preprocessor,
+                       frame_selector = _frame_selector)
 """
 In the preprocessing stage the face is cropped in each frame of the input video given facial annotations.
-The size of the face is normalized to ``cropped_image_size`` dimensions. The faces of the size
-below ``min_face_size`` threshold are discarded. The preprocessor is similar to the one introduced in
-[CAM12]_, which is defined by ``use_local_cropper_flag = True``. The preprocessed frame is the RGB
+The size of the face is normalized to ``FACE_SIZE`` dimensions. The faces of the size
+below ``MIN_FACE_SIZE`` threshold are discarded. The preprocessor is similar to the one introduced in
+[CAM12]_, which is defined by ``FACE_DETECTION_METHOD = None``. The preprocessed frame is the RGB
 facial image, which is defined by ``RGB_OUTPUT_FLAG = True``.
 """
 
diff --git a/bob/pad/face/database/aggregated_db.py b/bob/pad/face/database/aggregated_db.py
index cc584490fcdd20d16f2caaa6c1c89122b8c8a67c..6a30de5e72864cbc6d00590e3f927eb286ae4187 100644
--- a/bob/pad/face/database/aggregated_db.py
+++ b/bob/pad/face/database/aggregated_db.py
@@ -187,7 +187,8 @@ class AggregatedDbPadFile(VideoPadFile):
         return file_path
 
     # =========================================================================
-    def load(self, directory=None, extension='.mov'):
+    def load(self, directory=None, extension='.mov',
+             frame_selector=FrameSelector(selection_style='all')):
         """
         Overridden version of the load method defined in the ``VideoPadFile``.
 
@@ -252,9 +253,6 @@ class AggregatedDbPadFile(VideoPadFile):
 
         if isinstance(db_pad_file, bob.bio.video.database.mobio.MobioBioFile):
 
-            frame_selector = FrameSelector(
-                selection_style='all')  # select all frames of the file
-
             video_data = db_pad_file.load(
                 directory=directory,
                 extension='.mp4',
@@ -263,7 +261,9 @@ class AggregatedDbPadFile(VideoPadFile):
         else:
 
             video_data = db_pad_file.load(
-                directory=directory, extension=extension)
+                directory=directory, 
+                extension=extension,
+                frame_selector=frame_selector)
 
         return video_data  # video data
 
diff --git a/bob/pad/face/preprocessor/FaceCropAlign.py b/bob/pad/face/preprocessor/FaceCropAlign.py
new file mode 100644
index 0000000000000000000000000000000000000000..acbd819b8b6bf650b082511ef7fa1e7ad4fc98f3
--- /dev/null
+++ b/bob/pad/face/preprocessor/FaceCropAlign.py
@@ -0,0 +1,474 @@
+#!/usr/bin/env python2
+# -*- coding: utf-8 -*-
+"""
+Created on Tue May 30 14:11:16 2017
+
+@author: Olegs Nikisins
+"""
+
+# ==============================================================================
+# Import what is needed here:
+
+from bob.bio.base.preprocessor import Preprocessor
+
+import numpy as np
+
+import bob.ip.color
+
+import bob.ip.base
+
+import importlib
+
+
+# ==============================================================================
+def get_eye_pos(lm):
+    """
+    This function returns the locations of left and right eyes
+
+    **Parameters:**
+
+    ``lm`` : :py:class:`numpy.ndarray`
+        A numpy array containing the coordinates of facial landmarks, (68X2)
+
+    **Returns:**
+
+    ``right_eye``
+        A tuple containing the location of right eye,
+
+    ``left_eye``
+        A tuple containing the location of left eye
+
+    """
+
+    # Mean position of eye corners as eye centers , casted to int()
+
+    left_eye_t = (lm[36, :] + lm[39, :]) / 2.0
+    right_eye_t = (lm[42, :] + lm[45, :]) / 2.0
+
+    right_eye = (int(left_eye_t[1]), int(left_eye_t[0]))
+    left_eye = (int(right_eye_t[1]), int(right_eye_t[0]))
+
+    return right_eye, left_eye
+
+
+# ==============================================================================
+def detect_face_landmarks_in_image(image, method="dlib"):
+    """
+    This function detects a face in the input image. Two oprions for face detector , but landmark detector is always the same
+
+    **Parameters:**
+
+    ``image`` : 3D :py:class:`numpy.ndarray`
+        A color image to detect the face in.
+
+    ``method`` : :py:class:`str`
+        A package to be used for face detection. Options supported by this
+        package: "dlib" (dlib is a dependency of this package). If  bob.ip.mtcnn
+        is installed in your system you can use it as-well (bob.ip.mtcnn is NOT
+        a dependency of this package).
+
+    **Returns:**
+
+    ``annotations`` : :py:class:`dict`
+        A dictionary containing annotations of the face bounding box, eye locations and facial landmarks.
+        Dictionary must be as follows ``{'topleft': (row, col), 'bottomright': (row, col), 'left_eye': (row, col), 'right_eye': (row, col), 'landmarks': [(col1,row1), (col2,row2), ...]}``.
+        If no annotations found an empty dictionary is returned.
+        Where (rowK,colK) is the location of Kth facial landmark (K=0,...,67).
+    """
+
+    ### Face detector
+
+    try:
+        face_detection_module = importlib.import_module("bob.ip." + method)
+
+    except ImportError:
+
+        print("No module named bob.ip." + method +
+              " trying to use default method!")
+
+        try:
+            face_detection_module = importlib.import_module("bob.ip.dlib")
+            method = "dlib"
+        except ImportError:
+            raise ImportError("No module named bob.ip.dlib")
+
+    if not hasattr(face_detection_module, 'FaceDetector'):
+        raise AttributeError(
+            "bob.ip." + method + " module has no attribute FaceDetector!")
+
+    #### Landmark detector
+
+    try:
+        landmark_detection_module = importlib.import_module(
+            "bob.ip.facelandmarks")
+    except ImportError:
+        raise ImportError("No module named bob.ip.facelandmarks!!")
+
+    if not hasattr(landmark_detection_module,
+                   'detect_landmarks_on_boundingbox'):
+        raise AttributeError(
+            "bob.ip.facelandmarksmodule has no attribute detect_landmarks_on_boundingbox!"
+        )
+
+    face_detector = face_detection_module.FaceDetector()
+
+    data = face_detector.detect_single_face(image)
+
+    annotations = {}
+
+    if (data is not None) and (not all([x is None for x in data])):
+
+        bounding_box = data[0]
+
+        bounding_box_scaled = bounding_box.scale(0.95, True)  # is ok for dlib
+
+        lm = landmark_detection_module.detect_landmarks_on_boundingbox(
+            image, bounding_box_scaled)
+
+        if lm is not None:
+
+            lm = np.array(lm)
+
+            lm = np.vstack((lm[:, 1], lm[:, 0])).T
+
+            #print("LM",lm)
+
+            right_eye, left_eye = get_eye_pos(lm)
+
+            points = []
+
+            for i in range(lm.shape[0]):
+
+                points.append((int(lm[i, 0]), int(lm[i, 1])))
+
+            annotations['topleft'] = bounding_box.topleft
+
+            annotations['bottomright'] = bounding_box.bottomright
+
+            annotations['landmarks'] = points
+
+            annotations['left_eye'] = left_eye
+
+            annotations['right_eye'] = right_eye
+
+    return annotations
+
+
+# ==========================================================================
+def normalize_image_size_in_grayscale(image, annotations,
+                                      face_size, use_face_alignment):
+    """
+    This function crops the face in the input Gray-scale image given annotations
+    defining the face bounding box, and eye positions.
+    The size of the face is also normalized to the pre-defined dimensions.
+
+    Two normalization options are available, which are controlled by
+    ``use_face_alignment`` flag, see below.
+
+    **Parameters:**
+
+    ``image`` : 2D :py:class:`numpy.ndarray`
+        Gray-scale input image.
+
+    ``annotations`` : :py:class:`dict`
+        A dictionary containing annotations of the face bounding box,
+        eye locations and facial landmarks.
+        Dictionary must be as follows: ``{'topleft': (row, col), 'bottomright': (row, col),
+        'left_eye': (row, col), 'right_eye': (row, col)}``.
+
+    ``face_size`` : :py:class:`int`
+        The size of the face after normalization.
+
+    ``use_face_alignment`` : :py:class:`bool`
+        If ``False``, the re-sizing from this publication is used:
+        "On the Effectiveness of Local Binary Patterns in Face Anti-spoofing"
+        If ``True`` the facial image is both re-sized and aligned using
+        positions of the eyes, which are given in the annotations.
+
+    **Returns:**
+
+    ``normbbx`` : 2D :py:class:`numpy.ndarray`
+        An image of the cropped face of the size (face_size, face_size).
+    """
+
+    if use_face_alignment:
+
+        face_eyes_norm = bob.ip.base.FaceEyesNorm(
+            eyes_distance=((face_size + 1) / 2.),
+            crop_size=(face_size, face_size),
+            eyes_center=(face_size / 4., (face_size - 0.5) / 2.))
+
+        right_eye, left_eye = annotations['right_eye'], annotations['left_eye']
+
+        normalized_image = face_eyes_norm( image, right_eye = right_eye, left_eye = left_eye )
+
+        normbbx=normalized_image.astype('uint8')
+
+    else:
+
+        cutframe = image[annotations['topleft'][0]:annotations['bottomright'][
+            0], annotations['topleft'][1]:annotations['bottomright'][1]]
+
+        tempbbx = np.ndarray((face_size, face_size), 'float64')
+        normbbx = np.ndarray((face_size, face_size), 'uint8')
+        bob.ip.base.scale(cutframe, tempbbx)  # normalization
+        tempbbx_ = tempbbx + 0.5
+        tempbbx_ = np.floor(tempbbx_)
+        normbbx = np.cast['uint8'](tempbbx_)
+
+    return normbbx
+
+
+# ==========================================================================
+def normalize_image_size(image, annotations, face_size,
+                         rgb_output_flag, use_face_alignment):
+    """
+    This function crops the face in the input image given annotations defining
+    the face bounding box. The size of the face is also normalized to the
+    pre-defined dimensions. For RGB inputs it is possible to return both
+    color and gray-scale outputs. This option is controlled by ``rgb_output_flag``.
+
+    Two normalization options are available, which are controlled by
+    ``use_face_alignment`` flag, see below.
+
+    **Parameters:**
+
+    ``image`` : 2D or 3D :py:class:`numpy.ndarray`
+        Input image (RGB or gray-scale).
+
+    ``annotations`` : :py:class:`dict`
+        A dictionary containing annotations of the face bounding box,
+        eye locations and facial landmarks.
+        Dictionary must be as follows: ``{'topleft': (row, col), 'bottomright': (row, col),
+        'left_eye': (row, col), 'right_eye': (row, col)}``.
+
+    ``face_size`` : :py:class:`int`
+        The size of the face after normalization.
+
+    ``rgb_output_flag`` : :py:class:`bool`
+        Return RGB cropped face if ``True``, otherwise a gray-scale image is
+        returned. Default: ``False``.
+
+    ``use_face_alignment`` : :py:class:`bool`
+        If ``False``, the facial image re-sizing from this publication is used:
+        "On the Effectiveness of Local Binary Patterns in Face Anti-spoofing"
+        If ``True`` the facial image is both re-sized, and aligned, using
+        positions of the eyes, which are given in the annotations.
+
+    **Returns:**
+
+    ``face`` : 2D or 3D :py:class:`numpy.ndarray`
+        An image of the cropped face of the size (face_size, face_size),
+        RGB 3D or gray-scale 2D.
+    """
+
+    if len(image.shape) == 3:
+
+        if not (rgb_output_flag):
+
+            image = bob.ip.color.rgb_to_gray(image)
+
+    if len(image.shape) == 2:
+
+        image = [image]  # make gray-scale image an iterable
+
+    result = []
+
+    for image_channel in image:  # for all color channels in the input image
+
+        cropped_face = normalize_image_size_in_grayscale(
+            image_channel, annotations, face_size, use_face_alignment)
+
+        result.append(cropped_face)
+
+    face = np.stack(result, axis=0)
+
+    face = np.squeeze(face)  # squeeze 1-st dimension for gray-scale images
+
+    return face
+
+
+# ==========================================================================
+class FaceCropAlign(Preprocessor):
+    """
+    This function is designed to crop / size-normalize / align face
+    in the input image.
+
+    The size of the output face is ``3 x face_size x face_size`` pixels, if
+    ``rgb_output_flag = True``, or ``face_size x face_size`` if
+    ``rgb_output_flag = False``.
+
+    The face can also be aligned using positions of the eyes, only when
+    ``use_face_alignment = True`` and ``face_detection_method is not None``.
+
+    Both input annotations, and automatically determined are supported.
+
+    If ``face_detection_method is not None``, the annotations returned by
+    face detector will be used in the cropping.
+    Currently supported face detectors are listed in
+    ``supported_face_detection_method`` argument of this class.
+
+    If ``face_detection_method is None`` (Default), the input annotations are
+    used for cropping.
+
+    A few quality checks are supported in this function.
+    The quality checks are controlled by these arguments:
+    ``max_image_size``, ``min_face_size``. More details below.
+    Note: ``max_image_size`` is only supported when
+    ``face_detection_method is not None``.
+
+    **Parameters:**
+
+    ``face_size`` : :py:class:`int`
+        The size of the face after normalization.
+
+    ``rgb_output_flag`` : :py:class:`bool`
+        Return RGB cropped face if ``True``, otherwise a gray-scale image is
+        returned.
+
+    ``use_face_alignment`` : :py:class:`bool`
+        If set to ``True`` the face will be aligned aligned,
+        using the facial landmarks detected locally.
+        Works only when ``face_detection_method is not None``.
+
+    ``max_image_size`` : :py:class:`int`
+        The maximum size of the image to be processed.
+        ``max_image_size`` is only supported when
+        ``face_detection_method is not None``.
+        Default: ``None``.
+
+    ``face_detection_method`` : :py:class:`str`
+        A package to be used for face detection and landmark detection.
+        Options supported by this class:
+        "dlib" and "mtcnn", which are listed in
+        ``self.supported_face_detection_method`` argument.
+        Default: ``None``.
+
+    ``min_face_size`` : :py:class:`int`
+        The minimal size of the face in pixels to be processed.
+        Default: None.
+    """
+
+    # ==========================================================================
+    def __init__(self, face_size,
+                 rgb_output_flag,
+                 use_face_alignment,
+                 max_image_size=None,
+                 face_detection_method=None,
+                 min_face_size=None):
+
+        Preprocessor.__init__(self, face_size=face_size,
+                              rgb_output_flag=rgb_output_flag,
+                              use_face_alignment=use_face_alignment,
+                              max_image_size=max_image_size,
+                              face_detection_method=face_detection_method,
+                              min_face_size=min_face_size)
+
+        self.face_size = face_size
+        self.rgb_output_flag = rgb_output_flag
+        self.use_face_alignment = use_face_alignment
+
+        self.max_image_size = max_image_size
+        self.face_detection_method = face_detection_method
+        self.min_face_size = min_face_size
+
+        self.supported_face_detection_method = ["dlib", "mtcnn"]
+
+        if self.face_detection_method is not None:
+
+            if self.face_detection_method not in self.supported_face_detection_method:
+
+                raise ValueError('The {0} face detection method is not supported by this class. '
+                    'Currently supported face detectors are: bob.ip.{1}, bob.ip.{2}'.
+                    format(face_detection_method, self.supported_face_detection_method[0], self.supported_face_detection_method[1]))
+
+    # ==========================================================================
+    def __call__(self, image, annotations=None):
+        """
+        This function is designed to crop / size-normalize / align face
+        in the input image.
+
+        The size of the output face is ``3 x face_size x face_size`` pixels, if
+        ``rgb_output_flag = True``, or ``face_size x face_size`` if
+        ``rgb_output_flag = False``.
+
+        The face can also be aligned using positions of the eyes, only when
+        ``use_face_alignment = True`` and ``face_detection_method is not None``.
+
+        Both input annotations, and automatically determined are supported.
+
+        If ``face_detection_method is not None``, the annotations returned by
+        face detector will be used in the cropping.
+        Currently supported face detectors are listed in
+        ``supported_face_detection_method`` argument of this class.
+
+        If ``face_detection_method is None`` (Default), the input annotations are
+        used for cropping.
+
+        A few quality checks are supported in this function.
+        The quality checks are controlled by these arguments:
+        ``max_image_size``, ``min_face_size``. More details below.
+        Note: ``max_image_size`` is only supported when
+        ``face_detection_method is not None``.
+
+        **Parameters:**
+
+        ``image`` : 2D or 3D :py:class:`numpy.ndarray`
+            Input image (RGB or gray-scale) or None.
+
+        ``annotations`` : :py:class:`dict` or None
+            A dictionary containing annotations of the face bounding box.
+            Dictionary must be as follows:
+            ``{'topleft': (row, col), 'bottomright': (row, col)}``
+            Default: None .
+
+        **Returns:**
+
+        ``norm_face_image`` : 2D or 3D :py:class:`numpy.ndarray` or None
+            An image of the cropped / aligned face, of the size:
+            (self.face_size, self.face_size), RGB 3D or gray-scale 2D.
+        """
+
+        if self.face_detection_method is not None:
+
+            if self.max_image_size is not None: # max_image_size = 1920, for example
+
+                if np.max(image.shape) > self.max_image_size: # quality check
+
+                    return None
+
+            try:
+
+                annotations = detect_face_landmarks_in_image(image=image,
+                    method=self.face_detection_method)
+
+            except:
+
+                return None
+
+            if not annotations:  # if empty dictionary is returned
+
+                return None
+
+        if annotations is None:  # annotations are missing for this image
+
+            return None
+
+        if self.min_face_size is not None: # quality check
+
+            # size of the face
+            original_face_size = np.min(
+                np.array(annotations['bottomright']) -
+                np.array(annotations['topleft']))
+
+            if original_face_size < self.min_face_size:  # check if face size is above the threshold
+
+                return None
+
+        norm_face_image = normalize_image_size(image=image,
+                                               annotations=annotations,
+                                               face_size=self.face_size,
+                                               rgb_output_flag=self.rgb_output_flag,
+                                               use_face_alignment=self.use_face_alignment)
+
+        return norm_face_image
diff --git a/bob/pad/face/preprocessor/ImageFaceCrop.py b/bob/pad/face/preprocessor/ImageFaceCrop.py
deleted file mode 100644
index 2b3fefb7c706a911643ee842ddba88ecbb3a81a2..0000000000000000000000000000000000000000
--- a/bob/pad/face/preprocessor/ImageFaceCrop.py
+++ /dev/null
@@ -1,177 +0,0 @@
-#!/usr/bin/env python2
-# -*- coding: utf-8 -*-
-"""
-Created on Tue May 30 14:11:16 2017
-
-@author: Olegs Nikisins
-"""
-
-#==============================================================================
-# Import what is needed here:
-
-from bob.bio.base.preprocessor import Preprocessor
-
-import numpy as np
-
-import bob.ip.color
-
-import bob.ip.base
-
-#==============================================================================
-# Main body:
-
-
-class ImageFaceCrop(Preprocessor):
-    """
-    This class crops the face in the input image given annotations defining
-    the face bounding box. The size of the face is also normalized to the
-    pre-defined dimensions. For RGB inputs it is possible to return both
-    color and gray-scale outputs. This option is controlled by ``rgb_output_flag``.
-
-    The algorithm is identical to the following paper:
-    "On the Effectiveness of Local Binary Patterns in Face Anti-spoofing"
-
-    **Parameters:**
-
-    ``face_size`` : :py:class:`int`
-        The size of the face after normalization.
-
-    ``rgb_output_flag`` : :py:class:`bool`
-        Return RGB cropped face if ``True``, otherwise a gray-scale image is
-        returned. Default: ``False``.
-    """
-
-    #==========================================================================
-    def __init__(self, face_size, rgb_output_flag=False):
-
-        Preprocessor.__init__(
-            self, face_size=face_size, rgb_output_flag=rgb_output_flag)
-
-        self.face_size = face_size
-        self.rgb_output_flag = rgb_output_flag
-
-    #==========================================================================
-    def normalize_image_size_in_grayscale(self, image, annotations, face_size):
-        """
-        This function crops the face in the input Gray-scale image given annotations
-        defining the face bounding box. The size of the face is also normalized to the
-        pre-defined dimensions.
-
-        The algorithm is identical to the following paper:
-        "On the Effectiveness of Local Binary Patterns in Face Anti-spoofing"
-
-        **Parameters:**
-
-        ``image`` : 2D :py:class:`numpy.ndarray`
-            Gray-scale input image.
-
-        ``annotations`` : :py:class:`dict`
-            A dictionary containing annotations of the face bounding box.
-            Dictionary must be as follows ``{'topleft': (row, col), 'bottomright': (row, col)}``
-
-        ``face_size`` : :py:class:`int`
-            The size of the face after normalization.
-
-        **Returns:**
-
-        ``normbbx`` : 2D :py:class:`numpy.ndarray`
-            An image of the cropped face of the size (self.face_size, self.face_size).
-        """
-
-        cutframe = image[annotations['topleft'][0]:annotations['bottomright'][
-            0], annotations['topleft'][1]:annotations['bottomright'][1]]
-
-        tempbbx = np.ndarray((face_size, face_size), 'float64')
-        normbbx = np.ndarray((face_size, face_size), 'uint8')
-        bob.ip.base.scale(cutframe, tempbbx)  # normalization
-        tempbbx_ = tempbbx + 0.5
-        tempbbx_ = np.floor(tempbbx_)
-        normbbx = np.cast['uint8'](tempbbx_)
-
-        return normbbx
-
-    #==========================================================================
-    def normalize_image_size(self, image, annotations, face_size,
-                             rgb_output_flag):
-        """
-        This function crops the face in the input image given annotations defining
-        the face bounding box. The size of the face is also normalized to the
-        pre-defined dimensions. For RGB inputs it is possible to return both
-        color and gray-scale outputs. This option is controlled by ``rgb_output_flag``.
-
-        The algorithm is identical to the following paper:
-        "On the Effectiveness of Local Binary Patterns in Face Anti-spoofing"
-
-        **Parameters:**
-
-        ``image`` : 2D or 3D :py:class:`numpy.ndarray`
-            Input image (RGB or gray-scale).
-
-        ``annotations`` : :py:class:`dict`
-            A dictionary containing annotations of the face bounding box.
-            Dictionary must be as follows ``{'topleft': (row, col), 'bottomright': (row, col)}``
-
-        ``face_size`` : :py:class:`int`
-            The size of the face after normalization.
-
-        ``rgb_output_flag`` : :py:class:`bool`
-            Return RGB cropped face if ``True``, otherwise a gray-scale image is
-            returned. Default: ``False``.
-
-        **Returns:**
-
-        ``face`` : 2D or 3D :py:class:`numpy.ndarray`
-            An image of the cropped face of the size (self.face_size, self.face_size),
-            rgb 3D or gray-scale 2D.
-        """
-
-        if len(image.shape) == 3:
-
-            if not (rgb_output_flag):
-
-                image = bob.ip.color.rgb_to_gray(image)
-
-        if len(image.shape) == 2:
-
-            image = [image]  # make gray-scale image an iterable
-
-        result = []
-
-        for image_channel in image:  # for all color channels in the input image
-
-            cropped_face = self.normalize_image_size_in_grayscale(
-                image_channel, annotations, face_size)
-
-            result.append(cropped_face)
-
-        face = np.stack(result, axis=0)
-
-        face = np.squeeze(face)  # squeeze 1-st dimension for gray-scale images
-
-        return face
-
-    #==========================================================================
-    def __call__(self, image, annotations):
-        """
-        Call the ``normalize_image_size()`` method of this class.
-
-        **Parameters:**
-
-        ``image`` : 2D or 3D :py:class:`numpy.ndarray`
-            Input image (RGB or gray-scale).
-
-        ``annotations`` : :py:class:`dict`
-            A dictionary containing annotations of the face bounding box.
-            Dictionary must be as follows ``{'topleft': (row, col), 'bottomright': (row, col)}``
-
-        **Returns:**
-
-        ``norm_face_image`` : 2D or 3D :py:class:`numpy.ndarray`
-            An image of the cropped face of the size (self.face_size, self.face_size),
-            rgb 3D or gray-scale 2D.
-        """
-
-        norm_face_image = self.normalize_image_size(
-            image, annotations, self.face_size, self.rgb_output_flag)
-
-        return norm_face_image
diff --git a/bob/pad/face/preprocessor/VideoFaceCrop.py b/bob/pad/face/preprocessor/VideoFaceCrop.py
deleted file mode 100644
index b5433657427f8a7b91e59b5e84aa6055cdb8e057..0000000000000000000000000000000000000000
--- a/bob/pad/face/preprocessor/VideoFaceCrop.py
+++ /dev/null
@@ -1,363 +0,0 @@
-#!/usr/bin/env python2
-# -*- coding: utf-8 -*-
-"""
-Created on Fri May 12 14:14:23 2017
-
-@author: Olegs Nikisins
-"""
-#==============================================================================
-# Import what is needed here:
-
-from bob.bio.base.preprocessor import Preprocessor
-
-from bob.bio.face.preprocessor import FaceCrop
-
-import bob.bio.video
-
-import numpy as np
-
-from bob.pad.face.preprocessor.ImageFaceCrop import ImageFaceCrop
-
-from ..utils.face_detection_utils import detect_faces_in_video
-
-#==============================================================================
-# Main body:
-
-
-class VideoFaceCrop(Preprocessor, object):
-    """
-    This class is designed to crop faces in each frame of the input video given
-    annotations defining the position of the face.
-
-    **Parameters:**
-
-    ``cropped_image_size`` : (int, int)
-        The size of the resulting cropped images.
-
-    ``cropped_positions`` : :py:class:`dict`
-        The coordinates in the cropped image, where the annotated points should be put to.
-        This parameter is a dictionary with usually two elements, e.g., ``{'reye':(RIGHT_EYE_Y, RIGHT_EYE_X) , 'leye':(LEFT_EYE_Y, LEFT_EYE_X)}``.
-        However, also other parameters, such as ``{'topleft' : ..., 'bottomright' : ...}`` are supported, as long as the ``annotations`` in the `__call__` function are present.
-
-    ``fixed_positions`` : :py:class:`dict`
-        Or None.
-        If specified, ignore the annotations from the database and use these fixed positions throughout.
-
-    ``mask_sigma`` : :py:class:`float`
-        Or None
-        Fill the area outside of image boundaries with random pixels from the border, by adding noise to the pixel values.
-        To disable extrapolation, set this value to ``None``.
-        To disable adding random noise, set it to a negative value or 0.
-
-    ``mask_neighbors`` : :py:class:`int`
-        The number of neighbors used during mask extrapolation.
-        See :py:func:`bob.ip.base.extrapolate_mask` for details.
-
-    ``mask_seed`` : :py:class:`int`
-        Or None.
-        The random seed to apply for mask extrapolation.
-
-        .. warning::
-          When run in parallel, the same random seed will be applied to all parallel processes.
-          Hence, results of parallel execution will differ from the results in serial execution.
-
-    ``check_face_size_flag`` : :py:class:`bool`
-        If True, only return the frames containing faces of the size above the
-        specified threshold ``min_face_size``. Default: False.
-
-    ``min_face_size`` : :py:class:`int`
-        The minimal size of the face in pixels. Only valid when ``check_face_size_flag``
-        is set to True. Default: 50.
-
-    ``use_local_cropper_flag`` : :py:class:`bool`
-        If True, use the local ImageFaceCrop class to crop faces in the frames.
-        Otherwise, the FaceCrop preprocessor from bob.bio.face is used.
-        Default: False.
-
-    ``rgb_output_flag`` : :py:class:`bool`
-        Return RGB cropped face if ``True``, otherwise a gray-scale image is
-        returned. This flag is only valid when ``use_local_cropper_flag = True``.
-        Default: ``False``.
-
-    ``detect_faces_flag`` : :py:class:`bool`
-        If set to ``True`` the facial annotations will be generated using
-        face detection. Otherwise, annotations of the database are used for
-        cropping.
-        Default: ``False``.
-
-    ``face_detection_method`` : :py:class:`str`
-        A package to be used for face detection. Options supported by this
-        package: "dlib" (dlib is a dependency of this package). If  bob.ip.mtcnn
-        is installed in your system you can use it as-well (bob.ip.mtcnn is NOT
-        a dependency of this package).
-
-    ``kwargs``
-        Remaining keyword parameters passed to the Base constructor, such as ``color_channel`` or ``dtype``.
-    """
-
-    #==========================================================================
-    def __init__(self,
-                 cropped_image_size,
-                 cropped_positions,
-                 fixed_positions=None,
-                 mask_sigma=None,
-                 mask_neighbors=5,
-                 mask_seed=None,
-                 check_face_size_flag=False,
-                 min_face_size=50,
-                 use_local_cropper_flag=False,
-                 rgb_output_flag=False,
-                 detect_faces_flag=False,
-                 face_detection_method="dlib",
-                 **kwargs):
-
-        super(VideoFaceCrop, self).__init__(
-            cropped_image_size=cropped_image_size,
-            cropped_positions=cropped_positions,
-            fixed_positions=fixed_positions,
-            mask_sigma=mask_sigma,
-            mask_neighbors=mask_neighbors,
-            mask_seed=mask_seed,
-            check_face_size_flag=check_face_size_flag,
-            min_face_size=min_face_size,
-            use_local_cropper_flag=use_local_cropper_flag,
-            rgb_output_flag=rgb_output_flag,
-            detect_faces_flag=detect_faces_flag,
-            face_detection_method=face_detection_method,
-            **kwargs)
-
-        self.cropped_image_size = cropped_image_size
-        self.cropped_positions = cropped_positions
-        self.fixed_positions = fixed_positions
-        self.mask_sigma = mask_sigma
-        self.mask_neighbors = mask_neighbors
-        self.mask_seed = mask_seed
-        self.check_face_size_flag = check_face_size_flag
-        self.min_face_size = min_face_size
-        self.use_local_cropper_flag = use_local_cropper_flag
-        self.rgb_output_flag = rgb_output_flag
-        self.detect_faces_flag = detect_faces_flag
-        self.face_detection_method = face_detection_method
-
-        # Save also the data stored in the kwargs:
-        for (k, v) in kwargs.items():
-            setattr(self, k, v)
-
-        if self.use_local_cropper_flag:
-
-            preprocessor = ImageFaceCrop(
-                face_size=self.cropped_image_size[0],
-                rgb_output_flag=self.rgb_output_flag)
-
-        else:
-
-            preprocessor = FaceCrop(
-                cropped_image_size=self.cropped_image_size,
-                cropped_positions=self.cropped_positions,
-                fixed_positions=self.fixed_positions,
-                mask_sigma=self.mask_sigma,
-                mask_neighbors=self.mask_neighbors,
-                mask_seed=self.mask_seed,
-                **kwargs)
-
-        self.video_preprocessor = bob.bio.video.preprocessor.Wrapper(
-            preprocessor)
-
-    #==========================================================================
-    def check_face_size(self, frame_container, annotations, min_face_size):
-        """
-        Return the FrameContainer containing the frames with faces of the
-        size overcoming the specified threshold.
-
-        **Parameters:**
-
-        ``frame_container`` : FrameContainer
-            Video data stored in the FrameContainer, see ``bob.bio.video.utils.FrameContainer``
-            for further details.
-
-        ``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.
-
-        ``min_face_size`` : :py:class:`int`
-            The minimal size of the face in pixels.
-
-        **Returns:**
-
-        ``cleaned_frame_container`` : FrameContainer
-            FrameContainer containing the frames with faces of the size
-            overcoming the specified threshold.
-        """
-
-        cleaned_frame_container = bob.bio.video.FrameContainer(
-        )  # initialize the FrameContainer
-
-        selected_frame_idx = 0
-
-        for idx in range(0,
-                         np.min([len(annotations),
-                                 len(frame_container)])):  # idx - frame index
-
-            frame_annotations = annotations[str(
-                idx)]  # annotations for particular frame
-
-            # size of current face
-            face_size = np.min(
-                np.array(frame_annotations['bottomright']) -
-                np.array(frame_annotations['topleft']))
-
-            if face_size >= min_face_size:  # check if face size is above the threshold
-
-                selected_frame = frame_container[idx][1]  # get current frame
-
-                cleaned_frame_container.add(
-                    selected_frame_idx,
-                    selected_frame)  # add current frame to FrameContainer
-
-                selected_frame_idx = selected_frame_idx + 1
-
-        return cleaned_frame_container
-
-    #==========================================================================
-    def select_annotated_frames(self, frames, annotations):
-        """
-        Select only annotated frames in the input FrameContainer ``frames``.
-
-        **Parameters:**
-
-        ``frames`` : FrameContainer
-            Video data stored in the FrameContainer, see ``bob.bio.video.utils.FrameContainer``
-            for further details.
-
-        ``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.
-
-        **Returns:**
-
-        ``cleaned_frame_container`` : FrameContainer
-            FrameContainer containing the annotated frames only.
-
-        ``cleaned_annotations`` : :py:class:`dict`
-            A dictionary containing the annotations for each frame in the output 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.
-        """
-
-        annotated_frames = np.sort([
-            np.int(item) for item in annotations.keys()
-        ])  # annotated frame numbers
-
-        available_frames = range(
-            0, len(frames))  # frame numbers in the input video
-
-        valid_frames = list(
-            set(annotated_frames).intersection(
-                available_frames))  # valid and annotated frames
-
-        cleaned_frame_container = bob.bio.video.FrameContainer(
-        )  # initialize the FrameContainer
-
-        cleaned_annotations = {}
-
-        for idx, valid_frame_num in enumerate(valid_frames):
-            ## valid_frame_num - is the number of the original frame having annotations
-
-            cleaned_annotations[str(idx)] = annotations[str(
-                valid_frame_num)]  # correct the frame numbers
-
-            selected_frame = frames[valid_frame_num][1]  # get current frame
-
-            cleaned_frame_container.add(
-                idx, selected_frame)  # add current frame to FrameContainer
-
-        return cleaned_frame_container, cleaned_annotations
-
-    #==========================================================================
-    def __call__(self, frames, annotations):
-        """
-        Crop the face in the input video frames given annotations for each frame.
-
-        **Parameters:**
-
-        ``frames`` : FrameContainer
-            Video data stored in the FrameContainer, see ``bob.bio.video.utils.FrameContainer``
-            for further details.
-
-        ``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.
-
-        **Returns:**
-
-        ``preprocessed_video`` : FrameContainer
-            Cropped faces stored in the FrameContainer.
-        """
-
-        if self.detect_faces_flag:
-
-            annotations = detect_faces_in_video(frames,
-                                                self.face_detection_method)
-
-        if len(frames) != len(annotations):  # if some annotations are missing
-
-            ## Select only annotated frames:
-            frames, annotations = self.select_annotated_frames(
-                frames, annotations)
-
-        preprocessed_video = self.video_preprocessor(
-            frames=frames, annotations=annotations)
-
-        if self.check_face_size_flag:
-
-            preprocessed_video = self.check_face_size(
-                preprocessed_video, annotations, self.min_face_size)
-
-        return preprocessed_video
-
-    #==========================================================================
-    def write_data(self, frames, file_name):
-        """
-        Writes the given data (that has been generated using the __call__ function of this class) to file.
-        This method overwrites the write_data() method of the Preprocessor class.
-
-        **Parameters:**
-
-        ``frames`` :
-            data returned by the __call__ method of the class.
-
-        ``file_name`` : :py:class:`str`
-            name of the file.
-        """
-
-        if frames:  # save file if FrameContainer is not empty, otherwise do nothing.
-
-            self.video_preprocessor.write_data(frames, file_name)
-
-    #==========================================================================
-    def read_data(self, file_name):
-        """
-        Reads the preprocessed data from file.
-        This method overwrites the read_data() method of the Preprocessor class.
-
-        **Parameters:**
-
-        ``file_name`` : :py:class:`str`
-            name of the file.
-
-        **Returns:**
-
-        ``frames`` : :py:class:`bob.bio.video.FrameContainer`
-            Frames stored in the frame container.
-        """
-
-        frames = self.video_preprocessor.read_data(file_name)
-
-        return frames
diff --git a/bob/pad/face/preprocessor/__init__.py b/bob/pad/face/preprocessor/__init__.py
index d2b91b800873183e0a4df1d230eaf46773e372d5..5f43d3e2fcdacb09d1feed125c727d2c0a9f7234 100644
--- a/bob/pad/face/preprocessor/__init__.py
+++ b/bob/pad/face/preprocessor/__init__.py
@@ -1,5 +1,4 @@
-from .VideoFaceCrop import VideoFaceCrop
-from .ImageFaceCrop import ImageFaceCrop
+from .FaceCropAlign import FaceCropAlign
 from .FrameDifference import FrameDifference
 from .VideoSparseCoding import VideoSparseCoding
 
@@ -23,8 +22,7 @@ def __appropriate__(*args):
 
 
 __appropriate__(
-    VideoFaceCrop,
-    ImageFaceCrop,
+    FaceCropAlign,
     FrameDifference,
     VideoSparseCoding,
 )
diff --git a/bob/pad/face/test/test.py b/bob/pad/face/test/test.py
index 5693bb7fa89f2f775de938ee60d79d78fadf93f7..d6afe44fe18c17b3aaf306e19bec9fd9766fd8de 100644
--- a/bob/pad/face/test/test.py
+++ b/bob/pad/face/test/test.py
@@ -18,9 +18,7 @@ from bob.ip.color import rgb_to_gray
 
 from ..extractor import LBPHistogram
 
-from ..preprocessor import ImageFaceCrop
-
-from ..preprocessor import VideoFaceCrop
+from ..preprocessor import FaceCropAlign
 
 from ..preprocessor import FrameDifference
 
@@ -30,16 +28,18 @@ from ..extractor import LBPHistogram
 
 from ..extractor import ImageQualityMeasure
 
-from ..utils import face_detection_utils
-
 import random
 
+from ..preprocessor.FaceCropAlign import detect_face_landmarks_in_image
+
+from bob.bio.video.preprocessor import Wrapper
+
 
 def test_detect_face_landmarks_in_image_mtcnn():
 
     img = load(datafile('testimage.jpg', 'bob.bio.face.test'))
     assert len(img) == 3
-    annotations = face_detection_utils.detect_face_landmarks_in_image(
+    annotations = detect_face_landmarks_in_image(
         img, method='mtcnn')
     assert len(annotations['landmarks']) == 68
     assert len(annotations['left_eye']) == 2
@@ -50,25 +50,11 @@ def test_detect_face_landmarks_in_image_mtcnn():
     #assert len(annotations['left_eye']) == (176, 220)
 
 
-def test_detect_face_landmarks_in_video_mtcnn():
-
-    img = load(datafile('testimage.jpg', 'bob.bio.face.test'))
-    assert len(img) == 3
-    frame_container = bob.bio.video.FrameContainer()
-    frame_container.add(1, img)
-    frame_container.add(2, img)
-
-    annotations = face_detection_utils.detect_face_landmarks_in_video(
-        frame_container, method='mtcnn')
-    assert len(annotations) == 2
-    assert len(annotations['1']['landmarks']) == 68
-
-
 def test_detect_face_landmarks_in_image_dlib():
 
     img = load(datafile('testimage.jpg', 'bob.bio.face.test'))
     assert len(img) == 3
-    annotations = face_detection_utils.detect_face_landmarks_in_image(
+    annotations = detect_face_landmarks_in_image(
         img, method='dlib')
     assert len(annotations['landmarks']) == 68
     assert len(annotations['left_eye']) == 2
@@ -79,20 +65,6 @@ def test_detect_face_landmarks_in_image_dlib():
     #assert len(annotations['left_eye']) == (176, 220)
 
 
-def test_detect_face_landmarks_in_video_dlib():
-
-    img = load(datafile('testimage.jpg', 'bob.bio.face.test'))
-    assert len(img) == 3
-    frame_container = bob.bio.video.FrameContainer()
-    frame_container.add(1, img)
-    frame_container.add(2, img)
-
-    annotations = face_detection_utils.detect_face_landmarks_in_video(
-        frame_container, method='dlib')
-    assert len(annotations) == 2
-    assert len(annotations['1']['landmarks']) == 68
-
-
 #==============================================================================
 def test_lbp_histogram():
     lbp = LBPHistogram()
@@ -104,21 +76,21 @@ def test_lbp_histogram():
 
 
 #==============================================================================
-def test_image_face_crop():
+def test_face_crop_align():
     """
-    Test ImageFaceCrop preprocessor, which is designed to crop faces in the images.
+    Test FaceCropAlign preprocessor, which is designed to crop faces in the images.
     """
 
     image = load(datafile('test_image.png', 'bob.pad.face.test'))
     annotations = {'topleft': (95, 155), 'bottomright': (215, 265)}
 
-    preprocessor = ImageFaceCrop(face_size=64, rgb_output_flag=False)
+    preprocessor = FaceCropAlign(face_size=64, rgb_output_flag=False, use_face_alignment=False)
     face = preprocessor(image, annotations)
 
     assert face.shape == (64, 64)
     assert np.sum(face) == 429158
 
-    preprocessor = ImageFaceCrop(face_size=64, rgb_output_flag=True)
+    preprocessor = FaceCropAlign(face_size=64, rgb_output_flag=True, use_face_alignment=False)
     face = preprocessor(image, annotations)
 
     assert face.shape == (3, 64, 64)
@@ -172,35 +144,28 @@ def convert_image_to_video_data(image, annotations, n_frames):
 #==============================================================================
 def test_video_face_crop():
     """
-    Test VideoFaceCrop preprocessor, which is designed to crop faces in the video.
+    Test FaceCropAlign preprocessor with Wrapper, which is designed to crop faces in the video.
     """
 
+    FACE_SIZE = 64 # The size of the resulting face
+    RGB_OUTPUT_FLAG = False # Gray-scale output
+    USE_FACE_ALIGNMENT = False # use annotations
+    MAX_IMAGE_SIZE = None # no limiting here
+    FACE_DETECTION_METHOD = None # use annotations
+    MIN_FACE_SIZE = 50 # skip small faces
+
+    image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                       rgb_output_flag = RGB_OUTPUT_FLAG,
+                                       use_face_alignment = USE_FACE_ALIGNMENT,
+                                       max_image_size = MAX_IMAGE_SIZE,
+                                       face_detection_method = FACE_DETECTION_METHOD,
+                                       min_face_size = MIN_FACE_SIZE)
+
+    preprocessor = Wrapper(image_preprocessor)
+
     image = load(datafile('test_image.png', 'bob.pad.face.test'))
     annotations = {'topleft': (95, 155), 'bottomright': (215, 265)}
 
-    CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-    CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-    FIXED_POSITIONS = None
-    MASK_SIGMA = None  # The sigma for random values areas outside image
-    MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-    MASK_SEED = None  # The seed for generating random values during extrapolation
-    CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-    MIN_FACE_SIZE = 50  # Minimal possible size of the face
-    USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-    COLOR_CHANNEL = 'gray'  # Convert image to gray-scale format
-
-    preprocessor = VideoFaceCrop(
-        cropped_image_size=CROPPED_IMAGE_SIZE,
-        cropped_positions=CROPPED_POSITIONS,
-        fixed_positions=FIXED_POSITIONS,
-        mask_sigma=MASK_SIGMA,
-        mask_neighbors=MASK_NEIGHBORS,
-        mask_seed=MASK_SEED,
-        check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-        min_face_size=MIN_FACE_SIZE,
-        use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-        color_channel=COLOR_CHANNEL)
-
     video, annotations = convert_image_to_video_data(image, annotations, 20)
 
     faces = preprocessor(frames=video, annotations=annotations)
@@ -212,34 +177,23 @@ def test_video_face_crop():
     assert np.sum(faces[-1][1]) == 429158
 
     #==========================================================================
-    # test another configuration of the  VideoFaceCrop preprocessor:
-
-    CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-    CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-    FIXED_POSITIONS = None
-    MASK_SIGMA = None  # The sigma for random values areas outside image
-    MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-    MASK_SEED = None  # The seed for generating random values during extrapolation
-    CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-    MIN_FACE_SIZE = 50
-    USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-    RGB_OUTPUT_FLAG = True  # Return RGB cropped face using local cropper
-    DETECT_FACES_FLAG = True  # find annotations locally replacing the database annotations
-    FACE_DETECTION_METHOD = "dlib"
-
-    preprocessor = VideoFaceCrop(
-        cropped_image_size=CROPPED_IMAGE_SIZE,
-        cropped_positions=CROPPED_POSITIONS,
-        fixed_positions=FIXED_POSITIONS,
-        mask_sigma=MASK_SIGMA,
-        mask_neighbors=MASK_NEIGHBORS,
-        mask_seed=None,
-        check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-        min_face_size=MIN_FACE_SIZE,
-        use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-        rgb_output_flag=RGB_OUTPUT_FLAG,
-        detect_faces_flag=DETECT_FACES_FLAG,
-        face_detection_method=FACE_DETECTION_METHOD)
+    # test another configuration of the preprocessor:
+
+    FACE_SIZE = 64 # The size of the resulting face
+    RGB_OUTPUT_FLAG = True # Gray-scale output
+    USE_FACE_ALIGNMENT = False # use annotations
+    MAX_IMAGE_SIZE = None # no limiting here
+    FACE_DETECTION_METHOD = "dlib" # use annotations
+    MIN_FACE_SIZE = 50 # skip small faces
+
+    image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                       rgb_output_flag = RGB_OUTPUT_FLAG,
+                                       use_face_alignment = USE_FACE_ALIGNMENT,
+                                       max_image_size = MAX_IMAGE_SIZE,
+                                       face_detection_method = FACE_DETECTION_METHOD,
+                                       min_face_size = MIN_FACE_SIZE)
+
+    preprocessor = Wrapper(image_preprocessor)
 
     video, _ = convert_image_to_video_data(image, annotations, 3)
 
@@ -310,34 +264,29 @@ def test_video_lbp_histogram():
     Test LBPHistogram with Wrapper extractor.
     """
 
+    from ..preprocessor import FaceCropAlign
+
+    from bob.bio.video.preprocessor import Wrapper
+
+    FACE_SIZE = 64 # The size of the resulting face
+    RGB_OUTPUT_FLAG = False # Gray-scale output
+    USE_FACE_ALIGNMENT = False # use annotations
+    MAX_IMAGE_SIZE = None # no limiting here
+    FACE_DETECTION_METHOD = None # use annotations
+    MIN_FACE_SIZE = 50 # skip small faces
+
+    image_preprocessor = FaceCropAlign(face_size = FACE_SIZE,
+                                       rgb_output_flag = RGB_OUTPUT_FLAG,
+                                       use_face_alignment = USE_FACE_ALIGNMENT,
+                                       max_image_size = MAX_IMAGE_SIZE,
+                                       face_detection_method = FACE_DETECTION_METHOD,
+                                       min_face_size = MIN_FACE_SIZE)
+
+    preprocessor = Wrapper(image_preprocessor)
+
     image = load(datafile('test_image.png', 'bob.pad.face.test'))
     annotations = {'topleft': (95, 155), 'bottomright': (215, 265)}
 
-    CROPPED_IMAGE_SIZE = (64, 64)  # The size of the resulting face
-    CROPPED_POSITIONS = {'topleft': (0, 0), 'bottomright': CROPPED_IMAGE_SIZE}
-    FIXED_POSITIONS = None
-    MASK_SIGMA = None  # The sigma for random values areas outside image
-    MASK_NEIGHBORS = 5  # The number of neighbors to consider while extrapolating
-    MASK_SEED = None  # The seed for generating random values during extrapolation
-    CHECK_FACE_SIZE_FLAG = True  # Check the size of the face
-    MIN_FACE_SIZE = 50  # Minimal possible size of the face
-    USE_LOCAL_CROPPER_FLAG = True  # Use the local face cropping class (identical to Ivana's paper)
-    RGB_OUTPUT_FLAG = False  # The output is gray-scale
-    COLOR_CHANNEL = 'gray'  # Convert image to gray-scale format
-
-    preprocessor = VideoFaceCrop(
-        cropped_image_size=CROPPED_IMAGE_SIZE,
-        cropped_positions=CROPPED_POSITIONS,
-        fixed_positions=FIXED_POSITIONS,
-        mask_sigma=MASK_SIGMA,
-        mask_neighbors=MASK_NEIGHBORS,
-        mask_seed=MASK_SEED,
-        check_face_size_flag=CHECK_FACE_SIZE_FLAG,
-        min_face_size=MIN_FACE_SIZE,
-        use_local_cropper_flag=USE_LOCAL_CROPPER_FLAG,
-        rgb_output_flag=RGB_OUTPUT_FLAG,
-        color_channel=COLOR_CHANNEL)
-
     video, annotations = convert_image_to_video_data(image, annotations, 20)
 
     faces = preprocessor(frames=video, annotations=annotations)
diff --git a/bob/pad/face/utils/__init__.py b/bob/pad/face/utils/__init__.py
index 4444a68057622b8ebef09f5f12fd586aeca7fb82..fe90985c44f031beee8771dcc8ec134836f5907b 100644
--- a/bob/pad/face/utils/__init__.py
+++ b/bob/pad/face/utils/__init__.py
@@ -1,6 +1,3 @@
-from .face_detection_utils import (detect_face_in_image, detect_faces_in_video,
-                                   detect_face_landmarks_in_image,
-                                   detect_face_landmarks_in_video, get_eye_pos)
 from .load_utils import (frames, number_of_frames, yield_frames,
                          normalize_detections, yield_faces, scale_face, blocks)
 
diff --git a/bob/pad/face/utils/face_detection_utils.py b/bob/pad/face/utils/face_detection_utils.py
deleted file mode 100644
index 034ca9abe1d3d56f880c173f78f7043bc8238c67..0000000000000000000000000000000000000000
--- a/bob/pad/face/utils/face_detection_utils.py
+++ /dev/null
@@ -1,274 +0,0 @@
-#!/usr/bin/env python
-# vim: set fileencoding=utf-8 :
-"""
-This file contains face detection utils.
-"""
-#==============================================================================
-# Import here:
-
-import importlib
-import numpy as np
-
-
-#==============================================================================
-def get_eye_pos(lm):
-    """
-    This function returns the locations of left and right eyes
-
-    **Parameters:**
-
-    ``lm`` : :py:class:`numpy.ndarray`
-        A numpy array containing the coordinates of facial landmarks, (68X2)
-
-    **Returns:**
-
-    ``right_eye``
-        A tuple containing the location of right eye,
-
-    ``left_eye``
-        A tuple containing the location of left eye
-
-    """
-
-    # Mean position of eye corners as eye centers , casted to int()
-
-    left_eye_t = (lm[36, :] + lm[39, :]) / 2.0
-    right_eye_t = (lm[42, :] + lm[45, :]) / 2.0
-
-    right_eye = (int(left_eye_t[1]), int(left_eye_t[0]))
-    left_eye = (int(right_eye_t[1]), int(right_eye_t[0]))
-
-    return right_eye, left_eye
-
-
-#==============================================================================
-def detect_face_in_image(image, method="dlib"):
-    """
-    This function detects a face in the input image.
-
-    **Parameters:**
-
-    ``image`` : 3D :py:class:`numpy.ndarray`
-        A color image to detect the face in.
-
-    ``method`` : :py:class:`str`
-        A package to be used for face detection. Options supported by this
-        package: "dlib" (dlib is a dependency of this package). If  bob.ip.mtcnn
-        is installed in your system you can use it as-well (bob.ip.mtcnn is NOT
-        a dependency of this package).
-
-    **Returns:**
-
-    ``annotations`` : :py:class:`dict`
-        A dictionary containing annotations of the face bounding box.
-        Dictionary must be as follows ``{'topleft': (row, col), 'bottomright': (row, col)}``.
-        If no annotations found an empty dictionary is returned.
-    """
-
-    try:
-        face_detection_module = importlib.import_module("bob.ip." + method)
-    except ImportError:
-        raise ImportError("No module named bob.ip." + method)
-
-    if not hasattr(face_detection_module, 'FaceDetector'):
-        raise AttributeError(
-            "bob.ip." + method + " module has no attribute FaceDetector")
-
-    data = face_detection_module.FaceDetector().detect_single_face(image)
-
-    annotations = {}
-
-    if (data is not None) and (not all([x is None for x in data])):
-
-        bounding_box = data[0]
-
-        annotations['topleft'] = bounding_box.topleft
-
-        annotations['bottomright'] = bounding_box.bottomright
-
-    return annotations
-
-
-#==============================================================================
-def detect_faces_in_video(frame_container, method="dlib"):
-    """
-    This function detects a face in each farme of the input video.
-
-    **Parameters:**
-
-    ``frame_container`` : FrameContainer
-        FrameContainer containing the frames data.
-
-    ``method`` : :py:class:`str`
-        A package to be used for face detection. Options supported by this
-        package: "dlib" (dlib is a dependency of this package). If  bob.ip.mtcnn
-        is installed in your system you can use it as-well (bob.ip.mtcnn is NOT
-        a dependency of this package).
-
-    **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.
-        If no annotations found an empty dictionary is returned.
-    """
-
-    annotations = {}
-
-    for idx, frame in enumerate(frame_container):
-
-        image = frame[1]
-
-        frame_annotations = detect_face_in_image(image, method)
-
-        if frame_annotations:
-
-            annotations[str(idx)] = frame_annotations
-
-    return annotations
-
-
-#==============================================================================
-def detect_face_landmarks_in_image(image, method="dlib"):
-    """
-    This function detects a face in the input image. Two oprions for face detector , but landmark detector is always the same
-
-    **Parameters:**
-
-    ``image`` : 3D :py:class:`numpy.ndarray`
-        A color image to detect the face in.
-
-    ``method`` : :py:class:`str`
-        A package to be used for face detection. Options supported by this
-        package: "dlib" (dlib is a dependency of this package). If  bob.ip.mtcnn
-        is installed in your system you can use it as-well (bob.ip.mtcnn is NOT
-        a dependency of this package).
-
-    **Returns:**
-
-    ``annotations`` : :py:class:`dict`
-        A dictionary containing annotations of the face bounding box, eye locations and facial landmarks.
-        Dictionary must be as follows ``{'topleft': (row, col), 'bottomright': (row, col), 'left_eye': (row, col), 'right_eye': (row, col), 'landmarks': [(col1,row1), (col2,row2), ...]}``.
-        If no annotations found an empty dictionary is returned.
-        Where (rowK,colK) is the location of Kth facial landmark (K=0,...,67).
-    """
-
-    ### Face detector
-
-    try:
-        face_detection_module = importlib.import_module("bob.ip." + method)
-
-    except ImportError:
-
-        print("No module named bob.ip." + method +
-              " trying to use default method!")
-
-        try:
-            face_detection_module = importlib.import_module("bob.ip.dlib")
-            method = "dlib"
-        except ImportError:
-            raise ImportError("No module named bob.ip.dlib")
-
-    if not hasattr(face_detection_module, 'FaceDetector'):
-        raise AttributeError(
-            "bob.ip." + method + " module has no attribute FaceDetector!")
-
-    #### Landmark detector
-
-    try:
-        landmark_detection_module = importlib.import_module(
-            "bob.ip.facelandmarks")
-    except ImportError:
-        raise ImportError("No module named bob.ip.facelandmarks!!")
-
-    if not hasattr(landmark_detection_module,
-                   'detect_landmarks_on_boundingbox'):
-        raise AttributeError(
-            "bob.ip.facelandmarksmodule has no attribute detect_landmarks_on_boundingbox!"
-        )
-
-    face_detector = face_detection_module.FaceDetector()
-
-    data = face_detector.detect_single_face(image)
-
-    annotations = {}
-
-    if (data is not None) and (not all([x is None for x in data])):
-
-        bounding_box = data[0]
-
-        bounding_box_scaled = bounding_box.scale(0.95, True)  # is ok for dlib
-
-        lm = landmark_detection_module.detect_landmarks_on_boundingbox(
-            image, bounding_box_scaled)
-
-        if lm is not None:
-
-            lm = np.array(lm)
-
-            lm = np.vstack((lm[:, 1], lm[:, 0])).T
-
-            #print("LM",lm)
-
-            right_eye, left_eye = get_eye_pos(lm)
-
-            points = []
-
-            for i in range(lm.shape[0]):
-
-                points.append((int(lm[i, 0]), int(lm[i, 1])))
-
-            annotations['topleft'] = bounding_box.topleft
-
-            annotations['bottomright'] = bounding_box.bottomright
-
-            annotations['landmarks'] = points
-
-            annotations['left_eye'] = left_eye
-
-            annotations['right_eye'] = right_eye
-
-    return annotations
-
-
-#==============================================================================
-def detect_face_landmarks_in_video(frame_container, method="dlib"):
-    """
-    This function detects a face and face landmarks  in each farme of the input video.
-
-    **Parameters:**
-
-    ``frame_container`` : FrameContainer
-        FrameContainer containing the frames data.
-
-    ``method`` : :py:class:`str`
-        A package to be used for face detection. Options supported by this
-        package: "dlib" (dlib is a dependency of this package) and "mtcnn".
-        If its found it will be used else defaults to "dlib"
-
-    **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), 'left_eye': (row, col), 'right_eye': (row, col), 'landmarks': [(col1,row1), (col2,row2), ...]}``
-        is the dictionary defining the coordinates of the face bounding box in frame N.
-        Where (colK,rowK) is the location of Kth facial landmark (K=0,...,67).
-        If no annotations found an empty dictionary is returned.
-    """
-
-    annotations = {}
-
-    for idx, frame in enumerate(frame_container):
-
-        image = frame[1]
-
-        frame_annotations = detect_face_landmarks_in_image(image, method)
-
-        if frame_annotations:
-
-            annotations[str(idx)] = frame_annotations
-
-    return annotations
diff --git a/doc/api.rst b/doc/api.rst
index 8a763821a21241a62193fe21a0d2a2db457bc402..e085abd029c89a2c9a42f2fe0096009d5b015e66 100644
--- a/doc/api.rst
+++ b/doc/api.rst
@@ -72,12 +72,7 @@ Utilities
 
 .. autosummary::
    bob.pad.face.utils.blocks
-   bob.pad.face.utils.detect_face_in_image
-   bob.pad.face.utils.detect_face_landmarks_in_image
-   bob.pad.face.utils.detect_face_landmarks_in_video
-   bob.pad.face.utils.detect_faces_in_video
    bob.pad.face.utils.frames
-   bob.pad.face.utils.get_eye_pos
    bob.pad.face.utils.normalize_detections
    bob.pad.face.utils.number_of_frames
    bob.pad.face.utils.scale_face