Commit f90a96e0 authored by Tiago de Freitas Pereira's avatar Tiago de Freitas Pereira

Merge branch 'video-support' into 'master'

Video support

See merge request !46
parents 8cace2f8 2bbdceaa
Pipeline #53766 failed with stages
in 58 minutes and 45 seconds
from .utils import select_frames, VideoAsArray, VideoLikeContainer
from .utils import (
select_frames,
VideoAsArray,
VideoLikeContainer,
video_wrap_skpipeline,
)
from . import annotator
from . import transformer
......@@ -31,8 +36,7 @@ def __appropriate__(*args):
__appropriate__(
VideoAsArray,
VideoLikeContainer,
VideoAsArray, VideoLikeContainer,
)
# gets sphinx autodoc done right - don't remove it
__all__ = [_ for _ in dir() if not _.startswith("_")]
from bob.bio.base.pipelines.vanilla_biometrics.legacy import DatabaseConnector
from bob.bio.video.database import YoutubeBioDatabase
database = DatabaseConnector(
YoutubeBioDatabase(
protocol="fold1",
models_depend_on_protocol=True,
training_depends_on_protocol=True,
all_files_options={"subworld": "fivefolds"},
extractor_training_options={"subworld": "fivefolds"},
projector_training_options={"subworld": "fivefolds"},
enroller_training_options={"subworld": "fivefolds"},
)
from bob.bio.video.database import YoutubeDatabase
from functools import partial
from bob.bio.video.utils import select_frames
# Defining frame selection bit
# If you want to customize this, please, create a new config file and do
# bob bio pipelines vanilla-biometrics `my-new-config-file.py` `baseline`......
selection_style = "first"
max_number_of_frames = None
step_size = None
frame_selector = partial(
select_frames,
max_number_of_frames=max_number_of_frames,
selection_style=selection_style,
step_size=step_size,
)
database = YoutubeDatabase(protocol="fold0", frame_selector=frame_selector)
from bob.bio.video.transformer import VideoWrapper
from bob.bio.video.utils import video_wrap_skpipeline
from bob.pipelines import wrap
# Fetaching the pipeline from the chain-loading
pipeline = locals().get("pipeline")
pipeline.transformer = video_wrap_skpipeline(pipeline.transformer)
from .youtube import YoutubeDatabase
from .database import VideoBioFile
from .youtube import YoutubeBioDatabase
# gets sphinx autodoc done right - don't remove it
......@@ -18,8 +18,5 @@ def __appropriate__(*args):
obj.__module__ = __name__
__appropriate__(
VideoBioFile,
YoutubeBioDatabase,
)
__all__ = [_ for _ in dir() if not _.startswith('_')]
__appropriate__(YoutubeDatabase, VideoBioFile)
__all__ = [_ for _ in dir() if not _.startswith("_")]
This diff is collapsed.
from nose.plugins.skip import SkipTest
import bob.bio.base
from bob.bio.base.test.utils import db_available
from bob.bio.base.test.test_database_implementations import check_database_zt
from bob.bio.face.test.test_databases import _check_annotations
import pkg_resources
@db_available("youtube")
def test_youtube():
database = bob.bio.base.load_resource(
"youtube", "database", preferred_package="bob.bio.video"
)
try:
check_database_zt(database, training_depends=True, models_depend=True)
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
)
try:
if database.database.original_directory is None:
raise SkipTest("The annotations cannot be queried as original_directory is None")
_check_annotations(database, limit_files=1000, topleft=True, framed=True)
except IOError as e:
raise SkipTest(
"The annotations could not be queried; probably the annotation files are missing. Here is the error: '%s'"
% e
)
def test_new_youtube():
from bob.bio.video.database import YoutubeDatabase
for protocol in [f"fold{i}" for i in range(10)]:
@db_available("youtube")
def test_youtube_load_method():
database = bob.bio.base.load_resource(
"youtube", "database", preferred_package="bob.bio.video"
)
database.database.original_directory = pkg_resources.resource_filename(
"bob.bio.video", "test/data"
)
youtube_db_sample = [
sample
for sample_set in database.references(group="dev")
for sample in sample_set
if sample.key == "Aaron_Eckhart/0"
][0]
database = YoutubeDatabase("fold0")
references = database.references()
probes = database.probes()
frame_container = youtube_db_sample.data
assert len(references) == 500
assert len(probes) == 500
assert len(frame_container) == 2
......@@ -5,10 +5,42 @@ import h5py
import numpy as np
from bob.bio.base import selected_indices
from bob.io.video import reader
from .transformer import VideoWrapper
from bob.pipelines import wrap
logger = logging.getLogger(__name__)
def video_wrap_skpipeline(sk_pipeline):
"""
This function takes a `sklearn.Pipeline` and wraps each estimator inside of it with
:any:`bob.bio.video.transformer.VideoWrapper`
"""
for i, name, estimator in sk_pipeline._iter():
# 1. Unwrap the estimator
# If the estimator is `Sample` wrapped takes `estimator.estimator`.
transformer = (
estimator.estimator if hasattr(estimator, "estimator") else estimator
)
# 2. do a video wrap
transformer = VideoWrapper(transformer)
# 3. Sample wrap again
transformer = wrap(
["sample"],
transformer,
fit_extra_arguments=estimator.fit_extra_arguments,
transform_extra_arguments=estimator.transform_extra_arguments,
)
sk_pipeline.steps[i] = (name, transformer)
return sk_pipeline
def select_frames(
count, max_number_of_frames=None, selection_style=None, step_size=None
):
......@@ -252,7 +284,7 @@ class VideoLikeContainer:
# weak closing of the hdf5 file so we don't load all the data into
# memory https://docs.h5py.org/en/stable/high/file.html#closing-files
f = h5py.File(file, mode="r")
loaded = {"data": f["data"], "indices": f["indices"]}
loaded = {"data": f["data"], "indices": list(f["indices"])}
except OSError:
with open(file, "rb") as f:
loaded = pickle.load(f)
......
.. _bob.bio.video.faq:
================================
Frequently Asked Questions (FAQ)
================================
How to change the way frames are selected in my experiment?
-----------------------------------------------------------
The default frame selector in this package :any:`bob.bio.video.select_frames` allows you to select the
way frames are select `first`, `spread`, `step`, and `all` the the maximum number of frames can be used in this select.
The examples below shows some examples on how to use this selector.
Select the first frame only from every video
............................................
.. code-block:: python
>>> from bob.bio.video import select_frames
>>> from functools import partial
>>> frame_selector = partial(select_frames, selection_style="first", max_number_of_frames=1)
>>> frame_indices = [] # Some arbitrary list holding the frame indices
>>> selected_frames = frame_selector(frame_indices)
Select all frames
.................
.. code-block:: python
>>> from bob.bio.video import select_frames
>>> from functools import partial
>>> frame_selector = partial(select_frames, selection_style="all", max_number_of_frames=None)
>>> frame_indices = [] # Some arbitrary list holding the frame indices
>>> selected_frames = frame_selector(frame_indices)
Select all frames, but with an upper-bound of 100 frames
........................................................
.. code-block:: python
>>> from bob.bio.video import select_frames
>>> from functools import partial
>>> frame_selector = partial(select_frames, selection_style="all", max_number_of_frames=100)
>>> frame_indices = [] # Some arbitrary list holding the frame indices
>>> selected_frames = frame_selector(frame_indices)
Select 10 frames equally spread from the whole video
....................................................
.. code-block:: python
>>> from bob.bio.video import select_frames
>>> from functools import partial
>>> frame_selector = partial(select_frames, selection_style="spread", max_number_of_frames=10)
>>> frame_indices = [] # Some arbitrary list holding the frame indices
>>> selected_frames = frame_selector(frame_indices)
Now that I have customized my frame selector, so what?
......................................................
Once this frame selector is set, you can customize your experiment to use it.
The example below shows how to customize it for the YouTube Video Faces dataset (using one of the examples above)
.. code-block:: python
>>> from bob.bio.video.database import YoutubeDatabase
>>> from functools import partial
>>> from bob.bio.video.utils import select_frames
>>> frame_selector = partial(select_frames, selection_style="spread", max_number_of_frames=10)
>>> database = YoutubeDatabase(protocol="fold0", frame_selector=frame_selector)
Once this is saved into a python file (e.g. `my-dataset.py`), the vanilla-biometrics pipeline (:doc:`vanilla_biometrics_intro`) can be triggered as::
$ bob bio pipelines vanilla-biometrics my-dataset.py [BASELINE] video-wrapper
======================
Implementation Details
======================
.. todo::
Recover the old documentation and update it
......@@ -17,6 +17,7 @@ Summary
bob.bio.video.annotator.Base
bob.bio.video.annotator.Wrapper
bob.bio.video.annotator.FailSafeVideo
bob.bio.video.video_wrap_skpipeline
Databases
......@@ -24,7 +25,7 @@ Databases
.. autosummary::
bob.bio.video.database.YoutubeBioDatabase
bob.bio.video.database.YoutubeDatabase
Details
-------
......
......@@ -10,11 +10,25 @@
This package is part of the ``bob.bio`` packages, which provide open source tools to run comparable and reproducible biometric recognition experiments.
In this package, tools to run video face recognition experiments are provided.
So far, a single set of tools is available, which are meta-classes that allow to use other well-established face recognition algorithms on video data.
For more detailed information about the structure of the ``bob.bio`` packages, please refer to the documentation of :ref:`bob.bio.base <bob.bio.base>`.
In the following, we provide more detailed information about the particularities of this package only.
In the following, we provide more detailed information about the particularities of this package only.
Get Started (TLTR)
==================
To run biometric experiments using the :doc:`vanilla_biometrics_intro` with video databases, please make usage of the `video-wrapper` `entry-point <https://packaging.python.org/specifications/entry-points/>`_.
For instance the example below uses the `video-wrapper` to run face recognition experiments using one of our baselines from :ref:`bob.bio.face <bob.bio.face>` and the Youtube Face datase::
$ bob bio pipelines vanilla-biometrics youtube arcface-insightface video-wrapper
Please, go through the documentation of this package and :ref:`bob.bio.base <bob.bio.base>` to see how these commands work.
Users Guide
===========
......@@ -22,7 +36,7 @@ Users Guide
.. toctree::
:maxdepth: 2
implementation
faq
annotators
Reference Manual
......
......@@ -2,43 +2,39 @@
# vim: set fileencoding=utf-8 :
from setuptools import setup, dist
dist.Distribution(dict(setup_requires=['bob.extension']))
dist.Distribution(dict(setup_requires=["bob.extension"]))
from bob.extension.utils import load_requirements, find_packages
install_requires = load_requirements()
# The only thing we do in this file is to call the setup() function with all
# parameters that define our package.
setup(
# This is the basic information about your project. Modify all this
# information before releasing code publicly.
name = 'bob.bio.video',
version = open("version.txt").read().rstrip(),
description = 'Run biometric recognition algorithms on videos',
url = 'https://gitlab.idiap.ch/bob/bob.bio.video',
license = 'BSD',
author = 'The biometric person recognition group at Idiap, Switzerland',
author_email = 'bob-devel@googlegroups.com',
keywords = 'bob',
name="bob.bio.video",
version=open("version.txt").read().rstrip(),
description="Run biometric recognition algorithms on videos",
url="https://gitlab.idiap.ch/bob/bob.bio.video",
license="BSD",
author="The biometric person recognition group at Idiap, Switzerland",
author_email="bob-devel@googlegroups.com",
keywords="bob",
# If you have a better, long description of your package, place it on the
# 'doc' directory and then hook it here
long_description = open('README.rst').read(),
long_description=open("README.rst").read(),
# This line is required for any distutils based packaging.
packages = find_packages(),
include_package_data = True,
packages=find_packages(),
include_package_data=True,
zip_safe=False,
# This line defines which packages should be installed when you "install"
# this package. All packages that are mentioned here, but are not installed
# on the current system will be installed locally and only visible to the
# scripts of this package. Don't worry - You won't need administrative
# privileges when using buildout.
install_requires = install_requires,
install_requires=install_requires,
# Your project should be called something like 'bob.<foo>' or
# 'bob.<foo>.<bar>'. To implement this correctly and still get all your
# packages to be imported w/o problems, you need to implement namespaces
......@@ -49,8 +45,6 @@ setup(
# Our database packages are good examples of namespace implementations
# using several layers. You can check them out here:
# https://www.idiap.ch/software/bob/packages
# This entry defines which scripts you will have inside the 'bin' directory
# once you install the package (or run 'bin/buildout'). The order of each
# entry under 'console_scripts' is like this:
......@@ -66,33 +60,27 @@ setup(
# In this simple example we will create a single program that will print
# the version of bob.
entry_points={
'bob.bio.database': [
'dummy-video = bob.bio.video.test.dummy.database:database',# for test purposes only
'mobio = bob.bio.video.config.database.mobio:database',
'youtube = bob.bio.video.config.database.youtube:database',
],
'bob.bio.config': [
'preprocessor-wrapper = bob.bio.video.config.chain_loading.preprocessor',
'extractor-wrapper = bob.bio.video.config.chain_loading.extractor',
'algorithm-wrapper = bob.bio.video.config.chain_loading.algorithm',
'annotator-wrapper = bob.bio.video.config.chain_loading.annotator',
'video-wrapper = bob.bio.video.config.chain_loading.video',
]
"bob.bio.database": [
"dummy-video = bob.bio.video.test.dummy.database:database", # for test purposes only
"mobio = bob.bio.video.config.database.mobio:database",
"youtube = bob.bio.video.config.database.youtube:database",
],
"bob.bio.config": [
"mobio = bob.bio.video.config.database.mobio",
"youtube = bob.bio.video.config.database.youtube",
"video-wrapper = bob.bio.video.config.video_wrapper",
],
},
# Classifiers are important if you plan to distribute this package through
# PyPI. You can find the complete list of classifiers that are valid and
# useful here (http://pypi.python.org/pypi?%3Aaction=list_classifiers).
classifiers = [
'Framework :: Bob',
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Natural Language :: English',
'Programming Language :: Python',
'Topic :: Scientific/Engineering :: Artificial Intelligence',
classifiers=[
"Framework :: Bob",
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: BSD License",
"Natural Language :: English",
"Programming Language :: Python",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
],
)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment