From 4aa5a6aa32c5df19c6ee51c5be2ef8f765ca0d40 Mon Sep 17 00:00:00 2001
From: Andre Anjos <andre.dos.anjos@gmail.com>
Date: Thu, 24 Apr 2014 12:43:50 +0200
Subject: [PATCH] Complete, with documentation, tests and doctests

---
 MANIFEST.in                          |   1 +
 README.rst                           |  97 ++++-----
 buildout.cfg                         |   2 +
 doc/conf.py                          | 290 +++++++++++++++++++++++++++
 doc/guide.rst                        | 128 ++++++++++++
 doc/img/favicon.ico                  | Bin 0 -> 4286 bytes
 doc/img/logo.png                     | Bin 0 -> 11280 bytes
 doc/index.rst                        |  71 +++++++
 doc/links.rst                        |  82 ++++++++
 doc/plot/show_lena.py                |  23 +++
 doc/py_api.rst                       |  13 ++
 setup.py                             |   8 +-
 xbob/ip/flandmark/flandmark.cpp      |   2 +
 xbob/ip/flandmark/script/__init__.py |   0
 xbob/ip/flandmark/script/annotate.py | 131 ------------
 15 files changed, 658 insertions(+), 190 deletions(-)
 create mode 100644 doc/conf.py
 create mode 100644 doc/guide.rst
 create mode 100644 doc/img/favicon.ico
 create mode 100644 doc/img/logo.png
 create mode 100644 doc/index.rst
 create mode 100644 doc/links.rst
 create mode 100644 doc/plot/show_lena.py
 create mode 100644 doc/py_api.rst
 delete mode 100644 xbob/ip/flandmark/script/__init__.py
 delete mode 100644 xbob/ip/flandmark/script/annotate.py

diff --git a/MANIFEST.in b/MANIFEST.in
index 9589412..ecdd145 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,2 +1,3 @@
 include README.rst buildout.cfg bootstrap.py
+recursive-include doc *.rst *.py
 recursive-include xbob *.cpp *.h *.dat
diff --git a/README.rst b/README.rst
index e2c010e..774b605 100644
--- a/README.rst
+++ b/README.rst
@@ -14,14 +14,13 @@
    :target: https://pypi.python.org/pypi/xbob.ip.flandmark
 
 ==============================
- Python Bindings to flandmark
+ Python Bindings to Flandmark
 ==============================
 
-This package is a simple Boost.Python wrapper to the (rather quick) open-source
-facial landmark detector `flandmark
-<http://cmp.felk.cvut.cz/~uricamic/flandmark/index.php>`_, **version 1.0.7**
-(or the github state as of 10/february/2013).
-If you use this package, the author asks you to cite the following paper::
+This package is a simple Python wrapper to the (rather quick) open-source
+facial landmark detector `Flandmark`_, **version 1.0.7** (or the github state
+as of 10/february/2013). If you use this package, the author asks you to cite
+the following paper::
 
   @inproceedings{Uricar-Franc-Hlavac-VISAPP-2012,
     author =      {U{\v{r}}i{\v{c}}{\'{a}}{\v{r}}, Michal and Franc, Vojt{\v{e}}ch and Hlav{\'{a}}{\v{c}}, V{\'{a}}clav},
@@ -46,8 +45,8 @@ If you use this package, the author asks you to cite the following paper::
     www = {http://www.visapp.visigrapp.org},
   }
 
-You should also cite `Bob <http://www.idiap.ch/software/bob/>`_, as a core
-framework::
+You should also cite `Bob`_, as a core framework, in which these bindings are
+based on::
 
   @inproceedings{Anjos_ACMMM_2012,
     author = {A. Anjos AND L. El Shafey AND R. Wallace AND M. G\"unther AND C. McCool AND S. Marcel},
@@ -62,67 +61,59 @@ framework::
 Installation
 ------------
 
-You can just add a dependence for ``xbob.ip.flandmark`` on your ``setup.py`` to
-automatically download and have this package available at your satellite
-package. This works well if Bob_ is installed centrally at your machine.
+Install it through normal means, via PyPI or use ``zc.buildout`` to bootstrap
+the package and run test units.
 
-Otherwise, you will need to tell ``buildout`` how to build the package locally
-and how to find Bob_. For that, just add a custom egg recipe to your
-buildout that will fetch the package and compile it locally, setting the
-buildout variable ``prefixes`` to where Bob_ is installed (a build directory
-will work as well). For example::
+Documentation
+-------------
 
-  [buildout]
-  parts = flandmark <other parts here...>
-  ...
-  prefixes = /Users/andre/work/bob/build/debug
+You can generate the documentation for this package, after installation, using
+Sphinx::
 
-  ...
+  $ sphinx-build -b html doc sphinx
 
-  [flandmark]
-  recipe = xbob.buildout:develop
+This shall place in the directory ``sphinx``, the current version for the
+documentation of the package.
 
-  ...
+Testing
+-------
 
-Development
------------
+You can run a set of tests using the nose test runner::
 
-To develop these bindings, you will need the open-source library Bob_ installed
-somewhere. At least version 1.1 of Bob is required. If you have compiled Bob
-yourself and installed it on a non-standard location, you will need to note
-down the path leading to the root of that installation.
+  $ nosetests -sv xbob.ap
 
-Just type::
+.. warning::
 
-  $ python bootstrap.py
-  $ ./bin/buildout
+   If Bob <= 1.2.1 is installed on your python path, nose will automatically
+   load the old version of the insulate plugin available in Bob, which will
+   trigger the loading of incompatible shared libraries (from Bob itself), in
+   to your working binary. This will cause a stack corruption. Either remove
+   the centrally installed version of Bob, or build your own version of Python
+   in which Bob <= 1.2.1 is not installed.
 
-If Bob is installed in a non-standard location, edit the file ``buildout.cfg``
-to set the root to Bob's local installation path. Remember to use the **same
-python interpreter** that was used to compile Bob_, then execute the same steps
-as above.
+You can run our documentation tests using sphinx itself::
 
-Usage
------
+  $ sphinx-build -b doctest doc sphinx
 
-Pretty simple, just do something like::
+You can test overall test coverage with::
 
-  import bob
-  from xbob import flandmark
+  $ nosetests --with-coverage --cover-package=xbob.ip.flandmark
 
-  video = bob.io.VideoReader('myvideo.avi')
-  localizer = flandmark.Localizer()
+The ``coverage`` egg must be installed for this to work properly.
 
-  for frame in video:
-    print localizer(frame)
+Development
+-----------
 
-If you already have a detected bounding box, you can plug the coordinates of the bounding box into the localizer call::
+To develop this package, install using ``zc.buildout``, using the buildout
+configuration found on the root of the package::
 
-  landmarks = localizer(image, top, left, height, width)
+  $ python bootstrap.py
+  ...
+  $ ./bin/buildout
 
-In total, 8 ``landmarks`` are returned by the localizer.
-For the list and the interpretation of the landmarks, please have a look `here <http://cmp.felk.cvut.cz/~uricamic/flandmark/index.php>`_.
+Tweak the options in ``buildout.cfg`` to disable/enable verbosity and debug
+builds.
 
-.. warning::
-  Since version 1.1 of this package, the landmarks are returned in the Bob_-typical order, which is ``(y,x)``.
-  Please update your code to this new behavior.
+.. Place your references here:
+.. _flandmark: http://cmp.felk.cvut.cz/~uricamic/flandmark/index.php
+.. _bob: https://www.idiap.ch/software/bob
diff --git a/buildout.cfg b/buildout.cfg
index 2455a14..6eb656b 100644
--- a/buildout.cfg
+++ b/buildout.cfg
@@ -12,6 +12,7 @@ develop = src/xbob.extension
           src/xbob.blitz
           src/xbob.io
           src/xbob.ip.color
+          src/xbob.ip.draw
           .
 
 ; options for xbob.buildout extension
@@ -25,6 +26,7 @@ xbob.extension = git https://github.com/bioidiap/xbob.extension branch=prototype
 xbob.blitz = git https://github.com/bioidiap/xbob.blitz
 xbob.io = git https://github.com/bioidiap/xbob.io
 xbob.ip.color = git https://github.com/bioidiap/xbob.ip.color
+xbob.ip.draw = git https://github.com/bioidiap/xbob.ip.draw
 
 [scripts]
 recipe = xbob.buildout:scripts
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 0000000..072d633
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,290 @@
+#!/usr/bin/env python
+# vim: set fileencoding=utf-8 :
+# Andre Anjos <andre.anjos@idiap.ch>
+# Tue 15 Oct 16:37:18 2013 CEST
+#
+# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
+
+import os
+import sys
+import glob
+import pkg_resources
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = [
+  'sphinx.ext.todo',
+  'sphinx.ext.coverage',
+  'sphinx.ext.pngmath',
+  'sphinx.ext.ifconfig',
+  'sphinx.ext.autodoc',
+  'sphinx.ext.autosummary',
+  'sphinx.ext.doctest',
+  'sphinx.ext.intersphinx',
+  'matplotlib.sphinxext.plot_directive',
+  ]
+
+# The viewcode extension appeared only on Sphinx >= 1.0.0
+import sphinx
+if sphinx.__version__ >= "1.0":
+  extensions.append('sphinx.ext.viewcode')
+
+# Always includes todos
+todo_include_todos = True
+
+# If we are on OSX, the 'dvipng' path maybe different
+dvipng_osx = '/opt/local/libexec/texlive/binaries/dvipng'
+if os.path.exists(dvipng_osx): pngmath_dvipng = dvipng_osx
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'xbob.ip.flandmark'
+import time
+copyright = u'%s, Idiap Research Institute' % time.strftime('%Y')
+
+# Grab the setup entry
+distribution = pkg_resources.require('xbob.ip.flandmark')[0]
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = distribution.version
+# The full version, including alpha/beta/rc tags.
+release = distribution.version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['links.rst']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+if sphinx.__version__ >= "1.0":
+  html_theme = 'nature'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further.  For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents.  If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar.  Default is the same as html_title.
+#html_short_title = 'xbob_ip_flandmark'
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+html_logo = 'img/logo.png'
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+html_favicon = 'img/favicon.ico'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it.  The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'xbob_ip_flandmark_doc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+latex_paper_size = 'a4'
+
+# The font size ('10pt', '11pt' or '12pt').
+latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+  ('index', 'xbob_ip_flandmark.tex', u'Python bindings to the Flandmark frontal-face keypoint localizer', u'Biometrics Group, Idiap Research Institute', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+latex_logo = ''
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+# Included after all input documents
+rst_epilog = """
+.. |project| replace:: Bob
+.. |url| replace:: https://www.idiap.ch/software/bob/
+.. |version| replace:: %s
+.. |current-year| date:: %%Y
+""" % (version,)
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+    ('index', 'xbob_ip_flandmark', u'Python bindings to Flandmark frontal-face keypoint localizer', [u'Idiap Research Institute'], 1)
+]
+
+# Default processing flags for sphinx
+autoclass_content = 'both'
+autodoc_member_order = 'bysource'
+autodoc_default_flags = ['members', 'undoc-members', 'inherited-members', 'show-inheritance']
+
+def smaller_than(v1, v2):
+  """Compares scipy/numpy version numbers"""
+
+  c1 = v1.split('.')
+  c2 = v2.split('.')[:len(c1)] #clip to the compared version
+  for i, k in enumerate(c2):
+    n1 = c1[i]
+    n2 = c2[i]
+    try:
+      n1 = int(n1)
+      n2 = int(n2)
+    except ValueError:
+      n1 = str(n1)
+      n2 = str(n2)
+    if n1 > n2: return False
+  return True
+
+# Some name mangling to find the correct sphinx manuals for some packages
+numpy_version = __import__('numpy').version.version
+if smaller_than(numpy_version, '1.5.z'):
+  numpy_version = '.'.join(numpy_version.split('.')[:-1]) + '.x'
+else:
+  numpy_version = '.'.join(numpy_version.split('.')[:-1]) + '.0'
+numpy_manual = 'http://docs.scipy.org/doc/numpy-%s/' % numpy_version
+
+# For inter-documentation mapping:
+intersphinx_mapping = {
+  'http://docs.python.org/%d.%d/' % sys.version_info[:2]: None,
+  numpy_manual: None,
+  }
+
+try:
+  __import__('cv2')
+  has_opencv = True
+except ImportError:
+  has_opencv = False
+
+def setup(app):
+  app.add_config_value('has_opencv', has_opencv, True)
diff --git a/doc/guide.rst b/doc/guide.rst
new file mode 100644
index 0000000..6c5841b
--- /dev/null
+++ b/doc/guide.rst
@@ -0,0 +1,128 @@
+.. vim: set fileencoding=utf-8 :
+.. Andre Anjos <andre.dos.anjos@gmail.com>
+.. Sat 16 Nov 20:52:58 2013
+
+.. testsetup::
+
+   def get_file(f):
+     from os.path import join
+     from pkg_resources import resource_filename
+     return resource_filename('xbob.ip.flandmark', join('data', f))
+
+   LENA = get_file('lena.jpg')
+   MULTI = get_file('multi.jpg')
+   CASCADE = get_file('haarcascade_frontalface_alt.xml')
+
+=============
+ Users Guide
+=============
+
+Flandmark detects 8 coordinates of important keypoints in **frontal** human
+faces. To properly work, the keypoint localizer requires the input of an image
+(of type ``uint8``, gray-scaled) and of a bounding box describing a rectangle
+where the face is supposed to be located in the image (see
+:py:class:`xbob.ip.flandmark.Flandmark.locate`).
+
+The keypoints returned are, in this order:
+
+[0]
+  Face center
+
+[1]
+  Canthus-rl (inner corner of the right eye).
+
+  .. note::
+
+     The "right eye" means the right eye at the face w.r.t. the person on the
+     image. That is the left eye in the image, from the viewer's perspective.
+
+[2]
+  Canthus-lr (inner corner of the left eye)
+
+[3]
+  Mouth-corner-r (right corner of the mouth)
+
+[4]
+  Mouth-corner-l (left corner of the mouth)
+
+[5]
+  Canthus-rr (outer corner of the right eye)
+
+[6]
+  Canthus-ll (outer corner of the left eye)
+
+[7]
+  Nose
+
+Each point is returned as tuple defining the pixel positions in the form
+``(y, x)``.
+
+The input bounding box describes the rectangle coordinates using 4 values:
+``(y, x, height, width)``. Square bounding boxes, i.e. when ``height ==
+width``, will give best results.
+
+If you don't know the bounding box coordinates of faces on the provided image,
+you will need to either manually annotate them or use an automatic face
+detector. OpenCV_, if compiled with Python support, provides an easy to use
+frontal face detector. The code below shall detect most frontal faces in a
+provided (gray-scaled) image:
+
+.. ifconfig:: not has_opencv
+
+  .. warning::
+
+     OpenCV for the current installation in which this manual was generated was
+     not compiled with Python support. The code below cannot be tested and it
+     may work differently than what is announced. In doubt, consult the OpenCV
+     guide.
+
+  .. code-block:: python
+
+     >>> from cv2 import CascadeClassifier, cv
+     >>> from xbob.io import load
+     >>> from xbob.ip.color import rgb_to_gray
+     >>> cc = CascadeClassifier(CASCADE) # uses 'haarcascade_frontalface_alt.xml'
+     >>> lena_gray = rgb_to_gray(load(LENA) # uses 'lena.jpg'
+     >>> face_bbxs = cc.detectMultiScale(lena_gray, 1.3, 4, 0, (20, 20))
+     >>> print face_bbxs
+     [[214, 202, 183, 183]]
+
+.. ifconfig:: has_opencv
+
+  .. doctest::
+     :options: +NORMALIZE_WHITESPACE, +ELLIPSIS
+
+     >>> from cv2 import CascadeClassifier, cv
+     >>> from xbob.io import load
+     >>> from xbob.ip.color import rgb_to_gray
+     >>> cc = CascadeClassifier(get_file('haarcascade_frontalface_alt.xml'))
+     >>> lena_gray = rgb_to_gray(load(get_file('lena.jpg')))
+     >>> face_bbxs = cc.detectMultiScale(lena_gray, 1.3, 4, 0, (20, 20))
+     >>> print face_bbxs
+     [[214, 202, 183, 183]]
+
+The function ``detectMultiScale`` returns OpenCV_ rectangles as 2D
+:py:class:`numpy.ndarray`'s. Each row corresponds to a detected face at the
+input image. Notice the format of each bounding box differs from that of Bob_.
+Their format is ``(x, y, width, height)``.
+
+Once in possession of bounding boxes for the provided, gray-scaled image, you
+can find the keypoints in the following way:
+
+.. doctest::
+   :options: +NORMALIZE_WHITESPACE, +ELLIPSIS
+
+   >>> x, y, width, height = [214, 202, 183, 183] #or from OpenCV
+   >>> from xbob.ip.flandmark import Flandmark
+   >>> localizer = Flandmark()
+   >>> keypoints = localizer.locate(lena_gray, y, x, height, width)
+   >>> keypoints
+   [[...]]
+
+You can use the package ``xbob.ip.draw`` to draw the rectangles and keypoints
+on the target image. A complete script would be something like:
+
+.. plot:: plot/show_lena.py
+   :include-source: True
+
+.. include:: links.rst
diff --git a/doc/img/favicon.ico b/doc/img/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..4cc3264302627d40868261add69eb755856611b6
GIT binary patch
literal 4286
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

literal 0
HcmV?d00001

diff --git a/doc/img/logo.png b/doc/img/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9dd573a01019afd1af58a881996930e5212699d
GIT binary patch
literal 11280
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

literal 0
HcmV?d00001

diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 0000000..b1795da
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,71 @@
+.. vim: set fileencoding=utf-8 :
+.. Andre Anjos <andre.anjos@idiap.ch>
+.. Thu  3 Apr 13:47:28 2014 CEST
+..
+.. Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
+
+=======================================================================
+ Python Bindings to the Flandmark Keypoint Localizer for Frontal Faces
+=======================================================================
+
+.. todolist::
+
+
+This package is a simple Python wrapper to the (rather quick) open-source
+facial landmark detector `Flandmark`_, **version 1.0.7** (or the github state
+as of 10/february/2013).  If you use this package, the author asks you to cite
+the following paper::
+
+  @inproceedings{Uricar-Franc-Hlavac-VISAPP-2012,
+    author =      {U{\v{r}}i{\v{c}}{\'{a}}{\v{r}}, Michal and Franc, Vojt{\v{e}}ch and Hlav{\'{a}}{\v{c}}, V{\'{a}}clav},
+    title =       {Detector of Facial Landmarks Learned by the Structured Output {SVM}},
+    year =        {2012},
+    pages =       {547-556},
+    booktitle =   {VISAPP '12: Proceedings of the 7th International Conference on Computer Vision Theory and Applications},
+    editor =      {Csurka, Gabriela and Braz, Jos{\'{e}}},
+    publisher =   {SciTePress --- Science and Technology Publications},
+    address =     {Portugal},
+    volume =      {1},
+    isbn =        {978-989-8565-03-7},
+    book_pages =  {747},
+    month =       {February},
+    day =         {24-26},
+    venue =       {Rome, Italy},
+    keywords =    {Facial Landmark Detection, Structured Output Classification, Support Vector Machines, Deformable Part Models},
+    prestige =    {important},
+    authorship =  {50-40-10},
+    status =      {published},
+    project =     {FP7-ICT-247525 HUMAVIPS, PERG04-GA-2008-239455 SEMISOL, Czech Ministry of Education project 1M0567},
+    www = {http://www.visapp.visigrapp.org},
+  }
+
+You should also cite `Bob`_, as a core framework, in which these bindings are
+based on::
+
+  @inproceedings{Anjos_ACMMM_2012,
+    author = {A. Anjos AND L. El Shafey AND R. Wallace AND M. G\"unther AND C. McCool AND S. Marcel},
+    title = {Bob: a free signal processing and machine learning toolbox for researchers},
+    year = {2012},
+    month = oct,
+    booktitle = {20th ACM Conference on Multimedia Systems (ACMMM), Nara, Japan},
+    publisher = {ACM Press},
+    url = {http://publications.idiap.ch/downloads/papers/2012/Anjos_Bob_ACMMM12.pdf},
+  }
+
+Documentation
+-------------
+
+.. toctree::
+   :maxdepth: 2
+
+   guide
+   py_api
+
+Indices and tables
+------------------
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
+.. include:: links.rst
diff --git a/doc/links.rst b/doc/links.rst
new file mode 100644
index 0000000..cc43362
--- /dev/null
+++ b/doc/links.rst
@@ -0,0 +1,82 @@
+.. vim: set fileencoding=utf-8 :
+.. Andre Anjos <andre.anjos@idiap.ch>
+.. Tue 20 Mar 2012 08:57:32 CET
+..
+.. Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland
+
+.. This file contains all links we use for documentation in a centralized place
+
+.. Place here references to all citations in lower case
+
+.. _argparse: http://code.google.com/p/argparse/
+.. _blitz++: http://www.oonumerics.org/blitz
+.. _bob's idiap guide: http://github.com/idiap/bob/wiki/Using-Bob-at-Idiap
+.. _bob's website: https://www.idiap.ch/software/bob
+.. _bob: https://www.idiap.ch/software/bob
+.. _boost: http://www.boost.org
+.. _buildbot: http://trac.buildbot.net
+.. _buildout: http://pypi.python.org/pypi/zc.buildout/
+.. _c++: http://www2.research.att.com/~bs/C++.html
+.. _cmake: http://www.cmake.org
+.. _doxygen: http://www.doxygen.org
+.. _dvipng: http://savannah.nongnu.org/projects/dvipng/
+.. _ffmpeg: http://ffmpeg.org
+.. _libav: http://libav.org
+.. _fftw: http://www.fftw.org/
+.. _fink: http://www.finkproject.org
+.. _git: http://git-scm.com/
+.. _github: http://github.com/
+.. _google perftools: http://code.google.com/p/google-perftools
+.. _hdf5: http://www.hdfgroup.org/HDF5
+.. _idiap: http://www.idiap.ch
+.. _ipython: http://ipython.scipy.org
+.. _lapack: http://www.netlib.org/lapack
+.. _latex: http://www.latex-project.org/
+.. _libjpeg: http://libjpeg.sourceforge.net/
+.. _libnetpbm: http://netpbm.sourceforge.net/doc/libnetpbm.html
+.. _libpng: http://libpng.org/pub/png/libpng.html
+.. _libsvm: http://www.csie.ntu.edu.tw/~cjlin/libsvm/
+.. _libtiff: http://www.remotesensing.org/libtiff/
+.. _giflib: http://giflib.sourceforge.net/
+.. _macports installation instructions: http://www.macports.org/install.php
+.. _macports: http://www.macports.org
+.. _matio: http://matio.sourceforge.net
+.. _matlab: http://www.mathworks.ch/products/matlab/
+.. _matplotlib: http://matplotlib.sourceforge.net
+.. _numpy: http://numpy.scipy.org
+.. _nose: http://nose.readthedocs.org
+.. _opencv: http://opencv.org/
+.. _pil: http://www.pythonware.com/products/pil/
+.. _pillow: https://pypi.python.org/pypi/Pillow/
+.. _python: http://www.python.org
+.. _pypi: http://pypi.python.org
+.. _qt4: http://qt.nokia.com/
+.. _satellite packages: https://github.com/idiap/bob/wiki/Satellite-Packages
+.. _scipy: http://www.scipy.org
+.. _setuptools: http://trac.edgewall.org/wiki/setuptools
+.. _sphinx: http://sphinx.pocoo.org
+.. _sqlalchemy: http://www.sqlalchemy.org/
+.. _sqlite: http://www.sqlite.org/
+.. _submit a new bug report: https://github.com/idiap/bob/issues
+.. _torch 3 vision: http://torch3vision.idiap.ch
+.. _torch 3: http://www.torch.ch
+.. _torch 5: http://torch5.sourceforge.net
+.. _torch: https://github.com/andresy/torch
+.. _vlfeat launchpad webpage: https://launchpad.net/~gezakovacs/+archive/vlfeat
+.. _vlfeat: http://www.vlfeat.org/
+.. _flandmark: http://cmp.felk.cvut.cz/~uricamic/flandmark/index.php
+
+.. Place here references to licenses
+
+.. _apache-2.0: http://www.opensource.org/licenses/Apache-2.0
+.. _artistic-2.0: http://www.opensource.org/licenses/Artistic-2.0
+.. _bsd-2-clause: http://www.opensource.org/licenses/BSD-2-Clause
+.. _bsd-3-clause: http://www.opensource.org/licenses/BSD-3-Clause
+.. _bsl-1.0: http://www.opensource.org/licenses/BSL-1.0
+.. _gpl-2.0: http://www.opensource.org/licenses/GPL-2.0
+.. _gpl-3.0: http://www.opensource.org/licenses/GPL-3.0
+.. _hdf5 license: ftp://ftp.hdfgroup.org/HDF5/current/src/unpacked/COPYING
+.. _lgpl-2.1: http://www.opensource.org/licenses/LGPL-2.1
+.. _libpng license: http://www.libpng.org/pub/png/src/libpng-LICENSE.txt
+.. _mit: http://www.opensource.org/licenses/MIT
+.. _python-2.0: http://www.opensource.org/licenses/Python-2.0
diff --git a/doc/plot/show_lena.py b/doc/plot/show_lena.py
new file mode 100644
index 0000000..1997264
--- /dev/null
+++ b/doc/plot/show_lena.py
@@ -0,0 +1,23 @@
+from matplotlib import pyplot
+from xbob.ip.flandmark import Flandmark
+from xbob.ip.draw import box, cross
+from xbob.ip.color import rgb_to_gray
+
+def get_data(f):
+  from os.path import join
+  from pkg_resources import resource_filename
+  from xbob.io import load
+  return load(resource_filename('xbob.ip.flandmark', join('data', f)))
+
+lena = get_data('lena.jpg')
+lena_gray = rgb_to_gray(lena)
+x, y, width, height = [214, 202, 183, 183] #or from OpenCV
+localizer = Flandmark()
+keypoints = localizer.locate(lena_gray, y, x, height, width)
+
+# draw the keypoints and bounding box
+box(lena, (y, x), (height, width), (255, 0, 0)) # red bounding box
+for k in keypoints:
+  cross(lena, k.astype(int), 5, (255, 255, 0)) # yellow key points
+
+pyplot.imshow(lena.transpose(1, 2, 0))
diff --git a/doc/py_api.rst b/doc/py_api.rst
new file mode 100644
index 0000000..d37bb04
--- /dev/null
+++ b/doc/py_api.rst
@@ -0,0 +1,13 @@
+.. vim: set fileencoding=utf-8 :
+.. Andre Anjos <andre.dos.anjos@gmail.com>
+.. Sat 16 Nov 20:52:58 2013
+
+============
+ Python API
+============
+
+This section includes information for using the pure Python API of
+``xbob.ip.flandmark``.
+
+.. automodule:: xbob.ip.flandmark
+
diff --git a/setup.py b/setup.py
index d4e837e..ece118d 100644
--- a/setup.py
+++ b/setup.py
@@ -36,6 +36,8 @@ setup(
       'xbob.blitz',
       'xbob.io', #for tests
       'xbob.ip.color', #for tests
+      'xbob.ip.draw', #for doc generation
+      'matplotlib', #for doc generation
     ],
 
     namespace_packages=[
@@ -43,12 +45,6 @@ setup(
       "xbob.ip",
       ],
 
-    entry_points = {
-      'console_scripts': [
-        'xbob_flandmark.py = xbob.flandmark.script.annotate:main',
-        ],
-      },
-
     ext_modules=[
       Extension("xbob.ip.flandmark.version",
         [
diff --git a/xbob/ip/flandmark/flandmark.cpp b/xbob/ip/flandmark/flandmark.cpp
index 2b47b3c..8d0fadc 100644
--- a/xbob/ip/flandmark/flandmark.cpp
+++ b/xbob/ip/flandmark/flandmark.cpp
@@ -174,7 +174,9 @@ static auto s_call = xbob::extension::FunctionDoc(
     "\n"
     "0. Face center\n"
     "1. Canthus-rl (inner corner of the right eye).\n"
+    "\n"
     "   .. note::\n"
+    "      \n"
     "      The \"right eye\" means the right eye at the face w.r.t. the person "
     "on the image. That is the left eye in the image, from the viewer's "
     "perspective.\n"
diff --git a/xbob/ip/flandmark/script/__init__.py b/xbob/ip/flandmark/script/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/xbob/ip/flandmark/script/annotate.py b/xbob/ip/flandmark/script/annotate.py
deleted file mode 100644
index 1963e52..0000000
--- a/xbob/ip/flandmark/script/annotate.py
+++ /dev/null
@@ -1,131 +0,0 @@
-#!/usr/bin/env python
-# vim: set fileencoding=utf-8 :
-# Andre Anjos <andre.anjos@idiap.ch>
-# Fri 21 Sep 2012 10:43:12 CEST
-
-"""Annotates videos, dumps annotations as text files.
-
-The text files will contain one line per annotated frame. Each line contains a
-single detected face and associated landmarks. Only the biggest detection found
-on the frame is considered. The entries in each line are:
-
-[0]
-  The frame number (starting from 0)
-
-[1:5] 4 items
-  The bounding-box coordinates as detected by OpenCV (x, y, width, height)
-
-[5:] 8 pairs
-  Each pair corresponds to a keypoint in the order defined by the model:
-
-  [5:7]
-    Face center (as defined by the OpenCV detected bounding box)
-
-  [7:9]
-    Canthus-rl (inner corner of the right eye). Note: The "right eye" means
-    the right eye at face w.r.t. itself - that is the left eye in the image.
-
-  [9:11]
-    Canthus-lr (inner corder of the left eye)
-
-  [11:13]
-    Mouth-corner-r (right corner of the mouth)
-
-  [13:15]
-    Mouth-corner-l (left corner of the mouth)
-
-  [15:17]
-    Canthus-rr (outer corner of the right eye)
-
-  [17:19]
-    Canthus-ll (outer corner of the left eye)
-
-  [19:21]
-    Nose
-
-If no faces are found on the frame, the line will only display an invalid
-bounding box with zeros, e.g. `327 0 0 0 0`. No landmarks will be displayed in
-this case.
-"""
-
-import os
-import sys
-import bob
-from .. import Localizer
-import pkg_resources
-
-def get_biggest(dets):
-  """Returns the biggest detection found"""
-  retval = dets[0]
-  for d in dets[1:]:
-    if retval['bbox'][2] < d['bbox'][2]: retval = d
-  return retval
-
-def main():
-
-  import argparse
-
-  parser = argparse.ArgumentParser(description=__doc__,
-      formatter_class=argparse.RawDescriptionHelpFormatter)
-
-  parser.add_argument('video', metavar='VIDEO', type=str,
-      help="Video file to load")
-
-  parser.add_argument('output', metavar='OUTPUT', type=str,
-      default=None, nargs='?',
-      help="If you prefer the output diverged to a file, enter this argument")
-
-  parser.add_argument('-v', '--verbose', default=False, action='store_true',
-      help="Increases the output verbosity level")
-
-  from ..version import __version__
-  name = os.path.basename(os.path.splitext(sys.argv[0])[0])
-  parser.add_argument('-V', '--version', action='version',
-      version='Automatic Video Keypoint Annotation Tool v%s (%s)' % (__version__, name))
-
-  args = parser.parse_args()
-
-  if not os.path.exists(args.video):
-    parser.error("Input video file '%s' cannot be read" % args.video)
-
-  output = sys.stdout
-
-  if args.output is not None:
-    dirname = os.path.dirname(args.output)
-
-    if dirname and not os.path.exists(dirname):
-      try:
-        os.makedirs(dirname)
-      except OSError as exc:
-        import errno
-        if exc.errno == errno.EEXIST: pass
-        else: raise
-
-    output = open(args.output, 'wt')
-
-  op = Localizer()
-  v = bob.io.VideoReader(args.video)
-  if args.verbose and args.output is not None:
-    print "Locating faces in %d frames" % len(v),
-  for k, frame in enumerate(v):
-    dets = op(frame)
-    if dets:
-      biggest = get_biggest(dets)
-      bbox = biggest['bbox']
-      landmarks = biggest['landmark']
-      output.write("%d %d %d %d %d " % ((k,) + bbox))
-      lstr = " ".join("%d %d" % (round(p[1]), round(p[0])) for p in landmarks)
-      output.write(lstr + "\n")
-      if args.verbose and args.output is not None:
-        sys.stdout.write('.')
-        sys.stdout.flush()
-
-    else:
-      output.write("%d 0 0 0 0\n" % k)
-      if args.verbose and args.output is not None:
-        sys.stdout.write('x')
-        sys.stdout.flush()
-
-  if args.verbose and args.output is not None:
-    sys.stdout.write('\n')
-    sys.stdout.flush()
-- 
GitLab