diff --git a/bob/pad/face/utils/__init__.py b/bob/pad/face/utils/__init__.py
index 1b0b03c6e033c25748fdf0be22d1fc91d143c789..4274408459b2d3c87d8eb51a54c47817510b813a 100644
--- a/bob/pad/face/utils/__init__.py
+++ b/bob/pad/face/utils/__init__.py
@@ -1,6 +1,7 @@
 from .load_utils import (
     frames, number_of_frames, yield_frames, yield_faces, scale_face, blocks,
-    bbx_cropper, min_face_size_normalizer, the_giant_video_loader)
+    bbx_cropper, min_face_size_normalizer, color_augmentation,
+    the_giant_video_loader)
 
 # gets sphinx autodoc done right - don't remove it
 __all__ = [_ for _ in dir() if not _.startswith('_')]
diff --git a/bob/pad/face/utils/load_utils.py b/bob/pad/face/utils/load_utils.py
index 30566afc2f68440c4d2bd0e886d4da673c2a7a3b..ef939297295298bd4269e47b8d463dfaeecea595 100644
--- a/bob/pad/face/utils/load_utils.py
+++ b/bob/pad/face/utils/load_utils.py
@@ -2,6 +2,7 @@ from bob.bio.face.annotator import min_face_size_validator
 from bob.bio.video.annotator import normalize_annotations
 from bob.io.video import reader
 from bob.ip.base import scale, block, block_output_shape
+from bob.ip.color import rgb_to_yuv, rgb_to_hsv
 from bob.ip.facedetect import bounding_box_from_annotation
 from functools import partial
 import numpy
@@ -192,16 +193,73 @@ def blocks(data, block_size, block_overlap=(0, 0)):
     return output
 
 
+def color_augmentation(image, channels=('rgb',)):
+    """Converts an RGB image to different color channels.
+
+    Parameters
+    ----------
+    image : numpy.array
+        The image in RGB Bob format.
+    channels : tuple, optional
+        List of channels to convert the image to. It can be any of ``rgb``,
+        ``yuv``, ``hsv``.
+
+    Returns
+    -------
+    numpy.array
+        The image that contains several channels:
+        ``(3*len(channels), height, width)``.
+    """
+    final_image = []
+
+    if 'rgb' in channels:
+        final_image.append(image)
+
+    if 'yuv' in channels:
+        final_image.append(rgb_to_yuv(image))
+
+    if 'hsv' in channels:
+        final_image.append(rgb_to_hsv(image))
+
+    return numpy.concatenate(final_image, axis=0)
+
+
+def _random_sample(A, size):
+    return A[numpy.random.choice(A.shape[0], size, replace=False), ...]
+
+
 def the_giant_video_loader(paddb, padfile,
                            region='whole', scaling_factor=None, cropper=None,
-                           normalizer=None):
-    generator = None
+                           normalizer=None, patches=False,
+                           block_size=(96, 96), block_overlap=(0, 0),
+                           random_patches_per_frame=None, augment=None,
+                           multiple_bonafide_patches=1):
     if region == 'whole':
         generator = yield_frames(paddb, padfile)
     elif region == 'crop':
         generator = yield_faces(
             paddb, padfile, cropper=cropper, normalizer=normalizer)
+    else:
+        raise ValueError("Invalid region value: `{}'".format(region))
+
     if scaling_factor is not None:
         generator = (scale(frame, scaling_factor)
                      for frame in generator)
+    if patches:
+        if random_patches_per_frame is None:
+            generator = (
+                patch for frame in generator
+                for patch in blocks(frame, block_size, block_overlap))
+        else:
+            if padfile.attack_type is None:
+                random_patches_per_frame *= multiple_bonafide_patches
+            generator = (
+                patch for frame in generator
+                for patch in _random_sample(
+                    blocks(frame, block_size, block_overlap),
+                    random_patches_per_frame))
+
+    if augment is not None:
+        generator = (augment(frame) for frame in generator)
+
     return generator