diff --git a/bob/pad/face/config/casiafasd.py b/bob/pad/face/config/casiafasd.py
new file mode 100644
index 0000000000000000000000000000000000000000..0ee9b2575a3c1959e008bc3e163e8fafccba8200
--- /dev/null
+++ b/bob/pad/face/config/casiafasd.py
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+"""Config file for the CASIA FASD dataset.
+Please run ``bob config set bob.db.casia_fasd.directory /path/to/casia_fasd_files``
+in terminal to point to the original files of the dataset on your computer."""
+
+from bob.pad.face.database import CasiaFasdPadDatabase
+database = CasiaFasdPadDatabase()
diff --git a/bob/pad/face/config/extractor/optical_flow.py b/bob/pad/face/config/extractor/optical_flow.py
new file mode 100644
index 0000000000000000000000000000000000000000..895a4d9f0ef4ccc1b00369401fb05dc4e0fc36b1
--- /dev/null
+++ b/bob/pad/face/config/extractor/optical_flow.py
@@ -0,0 +1,4 @@
+from bob.bio.base.extractor import CallableExtractor
+from bob.pad.face.extractor import OpticalFlow
+
+extractor = CallableExtractor(OpticalFlow())
diff --git a/bob/pad/face/config/preprocessor/optical_flow.py b/bob/pad/face/config/preprocessor/optical_flow.py
new file mode 100644
index 0000000000000000000000000000000000000000..c7cad27feb43b0799fb1a60896df46bd91d65f9c
--- /dev/null
+++ b/bob/pad/face/config/preprocessor/optical_flow.py
@@ -0,0 +1,10 @@
+from bob.bio.base.preprocessor import CallablePreprocessor
+from bob.pad.face.extractor import OpticalFlow
+
+
+def _read_original_data(biofile, directory, extension):
+    return biofile.frames
+
+
+preprocessor = CallablePreprocessor(OpticalFlow(), accepts_annotations=False)
+preprocessor.read_original_data = _read_original_data
diff --git a/bob/pad/face/database/__init__.py b/bob/pad/face/database/__init__.py
index 753f5ef010ae763e4886a7213d05a2a327aeeabd..6f1dc8c5d58b7e91f70b58fcd9e4f1c1f970c1dd 100644
--- a/bob/pad/face/database/__init__.py
+++ b/bob/pad/face/database/__init__.py
@@ -8,6 +8,8 @@ from .batl import BatlPadDatabase
 from .celeb_a import CELEBAPadDatabase
 from .maskattack import MaskAttackPadDatabase
 from .casiasurf import CasiaSurfPadDatabase
+from .casiafasd import CasiaFasdPadDatabase
+
 
 # gets sphinx autodoc done right - don't remove it
 def __appropriate__(*args):
@@ -35,7 +37,8 @@ __appropriate__(
     BatlPadDatabase,
     CELEBAPadDatabase,
     MaskAttackPadDatabase,
-    CasiaSurfPadDatabase
+    CasiaSurfPadDatabase,
+    CasiaFasdPadDatabase,
 )
 
 __all__ = [_ for _ in dir() if not _.startswith('_')]
diff --git a/bob/pad/face/database/casiafasd.py b/bob/pad/face/database/casiafasd.py
new file mode 100644
index 0000000000000000000000000000000000000000..7f8e5ca3b999f1c027844911ad0d1e57764fa0df
--- /dev/null
+++ b/bob/pad/face/database/casiafasd.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+from bob.bio.video import FrameSelector
+from bob.extension import rc
+from bob.io.video import reader
+from bob.pad.base.database import PadDatabase
+from bob.pad.face.database import VideoPadFile
+from bob.db.base.utils import (
+    check_parameter_for_validity, check_parameters_for_validity)
+import numpy
+import os
+
+
+CASIA_FASD_FRAME_SHAPE = (3, 1280, 720)
+
+
+class CasiaFasdPadFile(VideoPadFile):
+    """
+    A high level implementation of the File class for the CASIA_FASD database.
+    """
+
+    def __init__(self, f, original_directory=None):
+        """
+        Parameters
+        ----------
+        f : object
+            An instance of the File class defined in the low level db interface
+            of the CasiaFasd database, in bob.db.casia_fasd.models
+        """
+
+        self.f = f
+        self.original_directory = original_directory
+
+        if f.is_real():
+            attack_type = None
+        else:
+            attack_type = 'attack/{}/{}'.format(f.get_type(), f.get_quality())
+
+        super(CasiaFasdPadFile, self).__init__(
+            client_id=str(f.get_clientid()),
+            path=f.filename,
+            attack_type=attack_type,
+            file_id=f.filename)
+
+    @property
+    def frames(self):
+        """Yields the frames of the biofile one by one.
+
+        Yields
+        ------
+        :any:`numpy.array`
+            A frame of the video. The size is :any:`CASIA_FASD_FRAME_SHAPE`.
+        """
+        vfilename = self.make_path(
+            directory=self.original_directory, extension='.avi')
+        for frame in reader(vfilename):
+            # pad frames to 1280 x 720 so they all have the same size
+            h, w = frame.shape[1:]
+            H, W = CASIA_FASD_FRAME_SHAPE[1:]
+            assert h <= H
+            assert w <= W
+            frame = numpy.pad(frame, ((0, 0), (0, H - h), (0, W - w)),
+                              mode='constant', constant_values=0)
+            yield frame
+
+    @property
+    def number_of_frames(self):
+        """Returns the number of frames in a video file.
+
+        Returns
+        -------
+        int
+            The number of frames.
+        """
+        vfilename = self.make_path(
+            directory=self.original_directory, extension='.avi')
+        return reader(vfilename).number_of_frames
+
+    @property
+    def frame_shape(self):
+        """Returns the size of each frame in this database.
+
+        Returns
+        -------
+        (int, int, int)
+            The (#Channels, Height, Width) which is
+            :any:`CASIA_FASD_FRAME_SHAPE`.
+        """
+        return CASIA_FASD_FRAME_SHAPE
+
+    @property
+    def annotations(self):
+        """Reads the annotations
+
+        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.
+        """
+        annots = self.f.bbx()
+        annotations = {}
+        for i, v in enumerate(annots):
+            topleft = (v[2], v[1])
+            bottomright = (v[2] + v[4], v[1] + v[3])
+            annotations[str(i)] = {'topleft': topleft,
+                                   'bottomright': bottomright}
+        return annotations
+
+    def load(self, directory=None, extension='.avi',
+             frame_selector=FrameSelector(selection_style='all')):
+        """Loads the video file and returns in a
+        :any:`bob.bio.video.FrameContainer`.
+
+        Parameters
+        ----------
+        directory : :obj:`str`, optional
+            The directory to load the data from.
+        extension : :obj:`str`, optional
+            The extension of the file to load.
+        frame_selector : :any:`bob.bio.video.FrameSelector`, optional
+            Which frames to select.
+
+        Returns
+        -------
+        :any:`bob.bio.video.FrameContainer`
+            The loaded frames inside a frame container.
+        """
+        directory = directory or self.original_directory
+        return frame_selector(self.make_path(directory, extension))
+
+
+class CasiaFasdPadDatabase(PadDatabase):
+    """
+    A high level implementation of the Database class for the CASIA_FASD
+    database. Please run ``bob config set bob.db.casia_fasd.directory
+    /path/to/casia_fasd_files`` in a terminal to point to the original files on
+    your computer. This interface is different from the one implemented in
+    ``bob.db.casia_fasd.Database``.
+    """
+
+    def __init__(
+            self,
+            # grandtest is the new modified protocol for this database
+            protocol='grandtest',
+            original_directory=rc['bob.db.casia_fasd.directory'],
+            **kwargs):
+        """
+        Parameters
+        ----------
+        protocol : str or None
+            The name of the protocol that defines the default experimental
+            setup for this database. Only grandtest is supported for now.
+
+        original_directory : str
+            The directory where the original data of the database are stored.
+
+        kwargs
+            The arguments of the :py:class:`bob.pad.base.database.PadDatabase`
+            base class constructor.
+        """
+        return super(CasiaFasdPadDatabase, self).__init__(
+            name='casiafasd',
+            protocol=protocol,
+            original_directory=original_directory,
+            original_extension='.avi',
+            training_depends_on_protocol=True,
+            **kwargs)
+
+    def objects(self,
+                groups=None,
+                protocol=None,
+                purposes=None,
+                model_ids=None,
+                **kwargs):
+        """
+        This function returns lists of CasiaFasdPadFile objects, which fulfill
+        the given restrictions.
+
+        Parameters
+        ----------
+        groups : :obj:`str` or [:obj:`str`]
+            The groups of which the clients should be returned.
+            Usually, groups are one or more elements of
+            ('train', 'dev', 'eval')
+
+        protocol : str
+            The protocol for which the clients should be retrieved.
+            Only 'grandtest' is supported for now. This protocol modifies the
+            'Overall Test' protocol and adds some ids to dev set.
+
+        purposes : :obj:`str` or [:obj:`str`]
+            The purposes for which File objects should be retrieved either
+            'real' or 'attack' or both.
+
+        model_ids
+            Ignored.
+
+        **kwargs
+            Ignored.
+
+        Returns
+        -------
+        files : [CasiaFasdPadFile]
+            A list of CasiaFasdPadFile objects.
+        """
+        groups = check_parameters_for_validity(
+            groups, 'groups', ('train', 'dev', 'eval'),
+            ('train', 'dev', 'eval'))
+        protocol = check_parameter_for_validity(
+            protocol, 'protocol', ('grandtest'), 'grandtest')
+        purposes = check_parameters_for_validity(
+            purposes, 'purposes', ('real', 'attack'), ('real', 'attack'))
+
+        qualities = ('low', 'normal', 'high')
+        types = ('warped', 'cut', 'video')
+        from bob.db.casia_fasd.models import File
+
+        files = []
+
+        db_mappings = {
+            'real_normal': '1',
+            'real_low': '2',
+            'real_high': 'HR_1',
+            'warped_normal': '3',
+            'warped_low': '4',
+            'warped_high': 'HR_2',
+            'cut_normal': '5',
+            'cut_low': '6',
+            'cut_high': 'HR_3',
+            'video_normal': '7',
+            'video_low': '8',
+            'video_high': 'HR_4'
+        }
+
+        # identitites 1-15 are for train, 16-20 are dev, and 21-50 for eval
+        grp_id_map = {
+            'train': list(range(1, 16)),
+            'dev': list(range(16, 21)),
+            'eval': list(range(21, 51)),
+        }
+        grp_map = {
+            'train': 'train',
+            'dev': 'train',
+            'eval': 'test',
+        }
+
+        for g in groups:
+            ids = grp_id_map[g]
+            for i in ids:
+                cur_id = i
+                if g == 'eval':
+                    cur_id = i - 20
+                    # the id within the group subset
+
+                # this group name (grp) is only train and test
+                grp = grp_map[g]
+
+                folder_name = grp + '_release'
+
+                for q in qualities:
+                    for c in purposes:
+                        # the class real doesn't have any different types, only
+                        # the attacks can be of different type
+                        if c == 'real':
+                            filename = os.path.join(folder_name, "%d" % cur_id,
+                                                    db_mappings['real_' + q])
+                            files.append(CasiaFasdPadFile(
+                                File(filename, c, grp),
+                                self.original_directory))
+                        else:
+                            for t in types:
+                                filename = os.path.join(
+                                    folder_name, "%d" % cur_id,
+                                    db_mappings[t + '_' + q])
+                                files.append(CasiaFasdPadFile(
+                                    File(filename, c, grp),
+                                    self.original_directory))
+        return files
+
+    def annotations(self, padfile):
+        return padfile.annotations
+
+    def frames(self, padfile):
+        return padfile.frames
+
+    def number_of_frames(self, padfile):
+        return padfile.number_of_frames
+
+    @property
+    def frame_shape(self):
+        return CASIA_FASD_FRAME_SHAPE
diff --git a/bob/pad/face/database/replay.py b/bob/pad/face/database/replay.py
index e144511e42f0586f568ee3b3ea192929f27012d5..56004ecffcd6cdc2fe40cdbd823ddb86ba15e558 100644
--- a/bob/pad/face/database/replay.py
+++ b/bob/pad/face/database/replay.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python
 # -*- coding: utf-8 -*-
 
 # Used in ReplayMobilePadFile class
diff --git a/bob/pad/face/extractor/OpticalFlow.py b/bob/pad/face/extractor/OpticalFlow.py
new file mode 100644
index 0000000000000000000000000000000000000000..a498c485371d85b847a0e8e6d2ddc970455ec0c7
--- /dev/null
+++ b/bob/pad/face/extractor/OpticalFlow.py
@@ -0,0 +1,126 @@
+from bob.bio.base import vstack_features
+from bob.bio.video import FrameContainer
+from bob.io.base import HDF5File
+from bob.ip.optflow.liu.cg import flow
+from collections import Iterator
+from functools import partial
+import logging
+
+logger = logging.getLogger(__name__)
+
+
+def _check_frame(frame):
+    if frame.dtype == "uint8":
+        return frame.astype("float64") / 255.0
+    return frame.astype("float64")
+
+
+class _Reader:
+    def __init__(self, i1, flow_method):
+        self.i1 = _check_frame(i1)
+        self.flow_method = flow_method
+
+    def __call__(self, i2):
+        i2 = _check_frame(i2)
+        flows = self.flow_method(self.i1, i2)[:2]
+        self.i1 = i2
+        return flows
+
+
+class OpticalFlow(object):
+    """An optical flow extractor
+    For more information see :any:`bob.ip.optflow.liu.cg.flow`.
+
+    Attributes
+    ----------
+    alpha : float
+        Regularization weight
+    inner : int
+        The number of inner fixed point iterations
+    iterations : int
+        The number of conjugate-gradient (CG) iterations
+    min_width : int
+        Width of the coarsest level
+    outer : int
+        The number of outer fixed point iterations
+    ratio : float
+        Downsample ratio
+    """
+
+    def __init__(
+        self,
+        alpha=0.02,
+        ratio=0.75,
+        min_width=30,
+        outer=20,
+        inner=1,
+        iterations=50,
+        **kwargs
+    ):
+        super().__init__(**kwargs)
+        self.alpha = alpha
+        self.ratio = ratio
+        self.min_width = min_width
+        self.outer = outer
+        self.inner = inner
+        self.iterations = iterations
+
+    def __call__(self, video):
+        """Computes optical flows on a video
+        Please note that the video should either be uint8 or float64 with values from 0
+        to 1.
+
+        Parameters
+        ----------
+        video : numpy.ndarray
+            The video. Can be a FrameContainer, generator, bob.io.video.reader, or a
+            numpy array.
+
+        Returns
+        -------
+        numpy.ndarray
+            The flows calculated for each pixel. The output shape will be
+            [number_of_frames - 1, 2, height, width].
+        """
+        if isinstance(video, FrameContainer):
+            video = video.as_array()
+        if not isinstance(video, Iterator):
+            video = iter(video)
+
+        i1 = next(video)
+        reader = _Reader(
+            i1,
+            partial(
+                flow,
+                alpha=self.alpha,
+                ratio=self.ratio,
+                min_width=self.min_width,
+                n_outer_fp_iterations=self.outer,
+                n_inner_fp_iterations=self.inner,
+                n_cg_iterations=self.iterations,
+            ),
+        )
+        flows = vstack_features(reader, video)
+        shape = list(flows.shape)
+        shape[0] = 2
+        shape.insert(0, -1)
+        return flows.reshape(shape)
+
+    def write_feature(self, feature, feature_file):
+        if not isinstance(feature_file, HDF5File):
+            feature_file = HDF5File(feature_file, "w")
+
+        feature_file.set("uv", feature)
+        feature_file.set_attribute("method", "liu.cg", "uv")
+        feature_file.set_attribute("alpha", self.alpha, "uv")
+        feature_file.set_attribute("ratio", self.ratio, "uv")
+        feature_file.set_attribute("min_width", self.min_width, "uv")
+        feature_file.set_attribute("n_outer_fp_iterations", self.outer, "uv")
+        feature_file.set_attribute("n_inner_fp_iterations", self.inner, "uv")
+        feature_file.set_attribute("n_iterations", self.iterations, "uv")
+
+    def read_feature(self, feature_file):
+        if not isinstance(feature_file, HDF5File):
+            feature_file = HDF5File(feature_file, "r")
+
+        return feature_file["uv"]
diff --git a/bob/pad/face/test/test_databases.py b/bob/pad/face/test/test_databases.py
index fb01fb324b8dcc21a505ff5f456513c4604ac3ab..7bb3cc8ea4f1a30d7d6fd55989cf8a470d1172fa 100644
--- a/bob/pad/face/test/test_databases.py
+++ b/bob/pad/face/test/test_databases.py
@@ -119,14 +119,17 @@ def test_maskattack():
         package_prefix='bob.pad.')
     try:
         # all real sequences: 2 sessions, 5 recordings for 17 individuals
-        assert len(maskattack.objects(groups=['train', 'dev', 'eval'], purposes='real')) == 170
+        assert len(maskattack.objects(
+            groups=['train', 'dev', 'eval'], purposes='real')) == 170
         # all attacks: 1 session, 5 recordings for 17 individuals
-        assert len(maskattack.objects(groups=['train', 'dev', 'eval'], purposes='attack')) == 85
-        
+        assert len(maskattack.objects(
+            groups=['train', 'dev', 'eval'], purposes='attack')) == 85
+
         # training real: 7 subjects, 2 sessions, 5 recordings
         assert len(maskattack.objects(groups=['train'], purposes='real')) == 70
         # training real: 7 subjects, 1 session, 5 recordings
-        assert len(maskattack.objects(groups=['train'], purposes='attack')) == 35
+        assert len(maskattack.objects(
+            groups=['train'], purposes='attack')) == 35
 
         # dev and test contains the same number of sequences:
         # real: 5 subjects, 2 sessions, 5 recordings
@@ -134,7 +137,8 @@ def test_maskattack():
         assert len(maskattack.objects(groups=['dev'], purposes='real')) == 50
         assert len(maskattack.objects(groups=['eval'], purposes='real')) == 50
         assert len(maskattack.objects(groups=['dev'], purposes='attack')) == 25
-        assert len(maskattack.objects(groups=['eval'], purposes='attack')) == 25
+        assert len(maskattack.objects(
+            groups=['eval'], purposes='attack')) == 25
 
     except IOError as e:
         raise SkipTest(
@@ -142,6 +146,8 @@ def test_maskattack():
             % e)
 
 # Test the Aggregated database, which doesn't have a package
+
+
 def test_aggregated_db():
     aggregated_db = bob.bio.base.load_resource(
         'aggregated-db',
@@ -210,147 +216,61 @@ def test_casiasurf():
         preferred_package='bob.pad.face',
         package_prefix='bob.pad.')
     try:
-        assert len(casiasurf.objects(groups=['train'], purposes='real')) == 8942 
+        assert len(casiasurf.objects(groups=['train'], purposes='real')) == 8942
         assert len(casiasurf.objects(groups=['train'], purposes='attack')) == 20324
         assert len(casiasurf.objects(groups=('dev',), purposes=('real',))) == 2994
         assert len(casiasurf.objects(groups=('dev',), purposes=('attack',))) == 6614
         assert len(casiasurf.objects(groups=('dev',), purposes=('real','attack'))) == 9608
         assert len(casiasurf.objects(groups=('eval',), purposes=('attack',))) == 57710
-    
+
     except IOError as e:
         raise SkipTest(
             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'"
             % e)
 
-# # Test the BATL database
-# @db_available('batl-db')
-# def test_aggregated_db():
-#     batl_db = bob.bio.base.load_resource(
-#         'batl-db',
-#         'database',
-#         preferred_package='bob.pad.face',
-#         package_prefix='bob.pad.')
-#     try:
-
-#         assert len(
-#             batl_db.objects(groups=['train', 'dev', 'eval'])) == 1679
-#         assert len(batl_db.objects(groups=['train', 'dev'])) == 1122
-#         assert len(batl_db.objects(groups=['train'])) == 565
-
-#         assert len(batl_db.objects(groups='train')) == 565
-#         assert len(batl_db.objects(groups='dev')) == 557
-#         assert len(batl_db.objects(groups='eval')) == 557
-
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'], protocol='grandtest')) == 1679
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest',
-#                 purposes='real')) == 347
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest',
-#                 purposes='attack')) == 1332
-#         #tests for join_train_dev protocols
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest-color-50-join_train_dev')) == 1679
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev'], protocol='grandtest-color-50-join_train_dev')) == 1679
-#         assert len(
-#             batl_db.objects(groups='eval',
-#                                   protocol='grandtest-color-50-join_train_dev')) == 557
-#         # test for LOO_fakehead
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest-color-50-LOO_fakehead')) == 1149
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_fakehead')) == 1017
-#         assert len(
-#             batl_db.objects(groups='eval',
-#                                   protocol='grandtest-color-50-LOO_fakehead')) == 132
-
-#         # test for LOO_flexiblemask
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest-color-50-LOO_flexiblemask')) == 1132
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_flexiblemask')) == 880
-#         assert len(
-#             batl_db.objects(groups='eval',
-#                                   protocol='grandtest-color-50-LOO_flexiblemask')) == 252
-
-#         # test for LOO_glasses
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest-color-50-LOO_glasses')) == 1206
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_glasses')) == 1069
-#         assert len(
-#             batl_db.objects(groups='eval',
-#                                   protocol='grandtest-color-50-LOO_glasses')) == 137
-
-#         # test for LOO_papermask
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest-color-50-LOO_papermask')) == 1308
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_papermask')) == 1122
-#         assert len(
-#             batl_db.objects(groups='eval',
-#                                   protocol='grandtest-color-50-LOO_papermask')) == 186
-
-#         # test for LOO_prints
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest-color-50-LOO_prints')) == 1169
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_prints')) == 988
-#         assert len(
-#             batl_db.objects(groups='eval',
-#                                   protocol='grandtest-color-50-LOO_prints')) == 181
-
-#         # test for LOO_replay
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest-color-50-LOO_replay')) == 1049
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_replay')) == 854
-#         assert len(
-#             batl_db.objects(groups='eval',
-#                                   protocol='grandtest-color-50-LOO_replay')) == 195
-
-#         # test for LOO_rigidmask
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev', 'eval'],
-#                 protocol='grandtest-color-50-LOO_rigidmask')) == 1198
-#         assert len(
-#             batl_db.objects(
-#                 groups=['train', 'dev'], protocol='grandtest-color-50-LOO_rigidmask')) == 1034
-#         assert len(
-#             batl_db.objects(groups='eval',
-#                                   protocol='grandtest-color-50-LOO_rigidmask')) == 164
-
-
-#     except IOError as e:
-#         raise SkipTest(
-#             "The database could not be queried; probably the db.sql3 file is missing. Here is the error: '%s'"
-#             % e)
+
+@db_available('casia_fasd')
+def test_casia_fasd():
+    casia_fasd = bob.bio.base.load_resource(
+        'casiafasd',
+        'database',
+        preferred_package='bob.pad.face',
+        package_prefix='bob.pad.')
+
+    assert len(casia_fasd.objects()) == 600
+    assert len(casia_fasd.objects(purposes='real')) == 150
+    assert len(casia_fasd.objects(purposes='attack')) == 450
+    assert len(casia_fasd.objects(groups=('train', 'dev'))) == 240
+    assert len(casia_fasd.objects(groups='train')) == 180
+    assert len(casia_fasd.objects(groups='dev')) == 60
+    assert len(casia_fasd.objects(groups='eval')) == 360
+
+    # test annotations since they are shipped with bob.db.casia_fasd
+    f = [f for f in casia_fasd.objects() if f.path == 'train_release/1/2'][0]
+    assert len(f.annotations) == 132
+    assert f.annotations['0'] == \
+        {'topleft': (102, 214), 'bottomright': (242, 354)}
+
+
+@db_available('casia_fasd')
+def test_casia_fasd_frames():
+    casia_fasd = bob.bio.base.load_resource(
+        'casiafasd',
+        'database',
+        preferred_package='bob.pad.face',
+        package_prefix='bob.pad.')
+
+    # test frame loading if the db original files are available
+    try:
+        files = casia_fasd.objects()[:12]
+        for f in files:
+            for frame in f.frames:
+                assert frame.shape == (3, 1280, 720)
+                break
+    except (IOError, RuntimeError)as e:
+        raise SkipTest(
+            "The database original files are missing. To run this test run "
+            "``bob config set bob.db.casia_fasd.directory "
+            "/path/to/casia_fasd_files`` in a terminal to point to the "
+            "original files on your computer. . Here is the error: '%s'"
+            % e)
diff --git a/conda/meta.yaml b/conda/meta.yaml
index 5b5670f0b04ffdadd2442b22cbde302e174664a2..8e7159051cf6321952be6e7c087d96586e6d9bd6 100644
--- a/conda/meta.yaml
+++ b/conda/meta.yaml
@@ -47,6 +47,7 @@ requirements:
     - {{ pin_compatible('numpy') }}
     - {{ pin_compatible('scikit-learn') }}
     - {{ pin_compatible('scikit-image') }}
+    - {{ pin_compatible('opencv') }}
 
 test:
   imports:
@@ -67,6 +68,7 @@ test:
     - bob.db.replay
     - bob.db.replaymobile
     - bob.db.msu_mfsd_mod
+    - bob.db.casia_fasd
     - bob.db.mobio
     - bob.db.maskattack
     - bob.db.casiasurf
diff --git a/doc/installation.rst b/doc/installation.rst
index d1ee42e19a17150ca53d961c20b3e49b9e4bae36..19849aa9263e622d0e0afca1757c57f360f6843e 100644
--- a/doc/installation.rst
+++ b/doc/installation.rst
@@ -1,47 +1,13 @@
 
-
 .. _bob.pad.face.installation:
 
-==============
- Installation
-==============
-
-The installation of this package is divided in 2-parts. Installation of the
-package and its software dependencies and the installation of databases.
-
-
-Package Installation
---------------------
-
-To install this package, first follow our `installation`_ instructions. Then,
-using the buildout command provided by the distribution, bootstrap this package
-using buildout:
-
-
-.. code-block:: sh
-
-  $ buildout
-
-
-Sphinx Documentation Building
------------------------------
-
-Once the package is installed, you may re-build this documentation locally by
-running:
-
-.. code-block:: sh
+======================
+ Setting up Databases
+======================
 
-  $ sphinx-build doc html
-
-The resulting HTML documentation will be output inside the directory `html`.
-
-
-Setting up Databases
---------------------
-
-In order to run face PAD algorithms using this package, you'll need to
-make sure to download the raw files corresponding to the databases you'd like
-to process. The raw files are not distributed with Bob_ software as biometric
+In order to run face PAD algorithms using this package, you'll need to make
+sure to download the raw files corresponding to the databases you'd like to
+process. The raw files are **not** distributed with Bob_ software as biometric
 data is, to most countries, considered sensible data that cannot be obtained
 without explicit licensing from a data controller. You must visit the websites
 below, sign the license agreements and then download the data before trying out
@@ -52,7 +18,7 @@ to run the baselines.
    If you're at the Idiap Research Institute in Switzlerand, the datasets in
    the baselines mentioned in this guide are already downloaded and
    pre-installed on our shared file system. You don't need to re-download
-   databases or create a ``~/.bob_bio_databases.txt`` file.
+   databases.
 
 
 The current system readily supports the following freely available datasets:
@@ -67,30 +33,11 @@ are installed. Then, follow the instructions in
 :ref:`bob.pad.base.installation` to let this framework know where databases are
 located on your system.
 
+.. note::
 
-Development
------------
-
-If you're developing this package, you may automatically clone all necessary
-Bob_ repositories on your local package installation. This allows you to build
-against an environment which contains all of our dependencies_, but no
-previously installed Bob_ packages. To do so, use the buildout recipe in
-``develop.cfg`` just after bootstraping:
-
-.. code-block:: sh
-
-  $ buildout -c develop.cfg
-
-Database SQL support files
-==========================
-
-If you installed all packages from scratch like above, you'll need to download
-the SQL support files of some of the database front-ends available in this
-package. This operation can be easily done like this:
-
-.. code-block:: sh
-
-  $ bob_dbmanage.py all download
+    Some databases may need to be configured using a newer method explained in
+    :ref:`bob.extension.rc`. Refer to the documentation of the database for
+    further information.
 
 
 .. include:: links.rst
diff --git a/setup.py b/setup.py
index a1824b9f3e5dbc42f4e06a3b8e1b356b331a6e49..6b62d22ea726838d2b6741208894258203402179 100644
--- a/setup.py
+++ b/setup.py
@@ -66,6 +66,7 @@ setup(
             'replay-attack = bob.pad.face.config.replay_attack:database',
             'replay-mobile = bob.pad.face.config.replay_mobile:database',
             'msu-mfsd = bob.pad.face.config.msu_mfsd:database',
+            'casiafasd = bob.pad.face.config.casiafasd:database',
             'aggregated-db = bob.pad.face.config.aggregated_db:database',
             'mifs = bob.pad.face.config.mifs:database',
             'batl-db = bob.pad.face.config.database.batl.batl_db:database',
@@ -85,6 +86,7 @@ setup(
             'replay-attack = bob.pad.face.config.replay_attack',
             'replay-mobile = bob.pad.face.config.replay_mobile',
             'msu-mfsd = bob.pad.face.config.msu_mfsd',
+            'casiafasd = bob.pad.face.config.casiafasd',
             'aggregated-db = bob.pad.face.config.aggregated_db',
             'mifs = bob.pad.face.config.mifs',
             'batl-db = bob.pad.face.config.database.batl.batl_db',
diff --git a/test-requirements.txt b/test-requirements.txt
index a2ec5b9057eaa8e301cd821942792508b416f054..fae37ea3fb6ed9f6464be836218e5eb9547cc4d6 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -2,6 +2,7 @@ nose
 bob.db.replay
 bob.db.replaymobile
 bob.db.msu_mfsd_mod
+bob.db.casia_fasd
 bob.db.mobio
 bob.db.maskattack
 bob.db.casiasurf