From 47c73ab74471418f42562edcbbd9060aad3e2ec1 Mon Sep 17 00:00:00 2001 From: Andre Anjos <andre.anjos@idiap.ch> Date: Fri, 21 Sep 2012 10:40:00 +0200 Subject: [PATCH] Better package standardization --- MANIFEST.in | 2 + README.rst | 70 +++++++++++++++++++++++++++++++++ flandmark/__init__.py | 91 ++++++++++++++++++++++++++++++++++++++++++- flandmark/ext/ext.cpp | 2 +- flandmark/test.py | 5 +-- setup.py | 37 +++++++++++++++++- 6 files changed, 200 insertions(+), 7 deletions(-) create mode 100644 MANIFEST.in create mode 100644 README.rst diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..d361b96 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include README.rst *.cfg bootstrap.py +recursive-include flandmark *.sql3 *.cpp *.h *.xml *.dat diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..37720e0 --- /dev/null +++ b/README.rst @@ -0,0 +1,70 @@ +============================== + 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>`_. 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}, + } + +Installation +------------ + +To install these bindings, you will need the open-source library `Bob +<http://www.idiap.ch/software/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. + +Just type:: + + $ python bootstrap.py + $ ./bin/buildout + +If Bob is installed in a non-standard location, remember to use the **same +python interpreter** that was used to compile Bob (replace ``<bob-root>`` with +the root of your local installation of Bob):: + + $ <bob-root>/bin/python bootstrap.py + $ PKG_CONFIG_PATH=<bob-root>/lib/pkgconfig ./bin/buildout + +The `PKG_CONFIG_PATH` variable will help ``buildout`` find the correct include +and link paths to your non-stock Bob installation. + +Usage +----- + +Pretty simple, just do something like:: + + import bob + import flandmark + + video = bob.io.VideoReader('myvideo.avi') + localize = flandmark.Localizer() + + for i, frame in enumerate(video): + print localize(frame) diff --git a/flandmark/__init__.py b/flandmark/__init__.py index 6766446..3ad5d7b 100644 --- a/flandmark/__init__.py +++ b/flandmark/__init__.py @@ -1 +1,90 @@ -from ._flandmark import * +from . import _flandmark + +from pkg_resources import resource_filename + +def __filename__(f): + """Returns the test file on the "data" subdirectory""" + return resource_filename(__name__, f) + +class Localizer(_flandmark.Localizer): + """A fast and effective facial landmark localization framework based on + flandmark + + Consult http://cmp.felk.cvut.cz/~uricamic/flandmark/index.php for more + information. + """ + + def __init__(self, detection_model=resource_filename(__name__, + 'haarcascade_frontalface_alt.xml'), + localization_model=resource_filename(__name__, + 'flandmark_model.dat')): + """Builds a new facial localization model. + + Raises RuntimeError's if the models either don't exist or can't be loaded. + + Keyword parameters: + + detection_model + An OpenCV (xml) detection model file for a CvHaarClassifierCascade. If not + specified, use a default installed with the package. + + localization_model + A flandmark localization model file. If not specified, use a default + installed with the package. The default model provides the following + keypoints, in this order: + + [0] + Face center + + [1] + 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. + + [2] + Canthus-lr (inner corder 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 + """ + super(Localizer, self).__init__(detection_model, localization_model) + + def __call__(self, image): + """Localizes facial keypoints on all faces detected at the input image. + + Keyword parameters: + + image + Either a gray-scale or colored image where to run the detection and + localization. + + Returns a tuple composed of dictionaries. Each dictionary in the list has + two entries: ``bbox`` and ``landmark``. The ``bbox`` entry corresponds to + the OpenCV cascade face detected, whereas the ``landmark`` contains a list + of tuples (representing x,y coordinates) with the landmarks. + + If no faces are detected on the input image, than the returned tuple is + empty. + """ + + if image.ndim == 3: + from bob.ip import rgb_to_gray + gray = rgb_to_gray(image) + return super(Localizer, self).__call__(gray) + + elif image.ndim == 2: + return super(Localizer, self).__call__(gray) + + else: + raise TypeError, "Localizer accepts images as numpy.ndarray objects with either 2 or 3 dimensions" diff --git a/flandmark/ext/ext.cpp b/flandmark/ext/ext.cpp index 2c14351..a768e26 100644 --- a/flandmark/ext/ext.cpp +++ b/flandmark/ext/ext.cpp @@ -106,7 +106,7 @@ class Localizer { // The first point represents the center of the bounding box used by // the flandmark library. - for (int i = 2; i < (2*m_flandmark->data.options.M); i += 2) { + for (int i = 0; i < (2*m_flandmark->data.options.M); i += 2) { lmlist.append(make_tuple(m_landmarks[i], m_landmarks[i+1])); } det["landmark"] = lmlist; diff --git a/flandmark/test.py b/flandmark/test.py index 501958d..81f7840 100644 --- a/flandmark/test.py +++ b/flandmark/test.py @@ -30,8 +30,8 @@ class FlandmarkTest(unittest.TestCase): v = bob.io.VideoReader(INPUT_VIDEO) - for i, f in enumerate(v): - self.assertTrue(op(bob.ip.rgb_to_gray(f))) + for f in v: + self.assertTrue(op(f)) def xtest02_broken(self): @@ -39,6 +39,5 @@ class FlandmarkTest(unittest.TestCase): "flandmark/flandmark_model.dat") for i, f in enumerate(bob.io.VideoReader(INPUT_VIDEO)): - v = bob.ip.rgb_to_gray(f) print v self.assertTrue(op(v)) diff --git a/setup.py b/setup.py index 55da9ad..c7f9cb9 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ import sys import subprocess -from distutils.core import setup +from setuptools import setup, find_packages from distutils.extension import Extension def pkgconfig(package): @@ -82,8 +82,30 @@ def setup_bob_extension(ext_name, sources): ) setup( + name="flandmark", version="1.0.6", + description="", + license="GPLv3", + author='Andre Anjos', + author_email='andre.anjos@idiap.ch', + long_description=open('README.rst').read(), + + packages=find_packages(), + include_package_data=True, + zip_safe=False, + + install_requires=[ + 'setuptools', + 'bob', + ], + + entry_points = { + 'console_scripts': [ + 'annotate.py = flandmark.script.annotate:main', + ], + }, + ext_modules=[ setup_bob_extension("flandmark._flandmark", [ @@ -91,4 +113,15 @@ setup( "flandmark/ext/liblbp.cpp", "flandmark/ext/ext.cpp", ]) - ]) + ], + + classifiers = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', + 'Natural Language :: English', + 'Programming Language :: Python', + 'Topic :: Scientific/Engineering :: Artificial Intelligence', + ], + + ) -- GitLab