diff --git a/setup.py b/setup.py index a3098efa10f2fef50b5136b0ab732126bc450424..1ff89aaa5c3eba8f8697b1396cb79379ca9496ac 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ from xbob.extension import Extension, build_ext setup( name="xbob.flandmark", - version="1.0.7", + version="1.0.8", description="Python bindings to the flandmark keypoint localization library", license="GPLv3", author='Andre Anjos', diff --git a/xbob/flandmark/__init__.py b/xbob/flandmark/__init__.py index 488e568525578d7bcde2daa37106c5f5a4c3b87f..8e637dc3857288e46c6f9002b15282e4b2e89f45 100644 --- a/xbob/flandmark/__init__.py +++ b/xbob/flandmark/__init__.py @@ -88,3 +88,39 @@ class Localizer(_flandmark.Localizer): else: raise TypeError, "Localizer accepts images as numpy.ndarray objects with either 2 or 3 dimensions" + + def __call__(self, image, b_y, b_x, b_height, b_width): + """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. + + b_y + The top-left y-coordinate of the bounding box + + b_x + The top-left x-coordinate of the bounding box + + b_height + The height of the bounding box + + b_width + The width of the bounding box + + Returns the landmarks which are a list of tuples + (representing x,y coordinates) with the landmarks. + """ + + if image.ndim == 3: + from bob.ip import rgb_to_gray + gray = rgb_to_gray(image) + return super(Localizer, self).__call__(gray, b_y, b_x, b_height, b_width) + + elif image.ndim == 2: + return super(Localizer, self).__call__(gray, b_y, b_x, b_height, b_width) + + else: + raise TypeError, "Localizer accepts images as numpy.ndarray objects with either 2 or 3 dimensions" diff --git a/xbob/flandmark/ext/ext.cpp b/xbob/flandmark/ext/ext.cpp index c25eb2cb637040cab98cc29ee809c7b0eeaca513..9fea90ba6742280f3aff39b24b79107dbe819186 100644 --- a/xbob/flandmark/ext/ext.cpp +++ b/xbob/flandmark/ext/ext.cpp @@ -64,9 +64,9 @@ class Localizer { } /** - * Locates the landmarks from an input image + * Detect and locates the landmarks from an input image */ - tuple operator() (bob::python::const_ndarray input) { + tuple call1(bob::python::const_ndarray input) { //checks type const bob::core::array::typeinfo& type = input.type(); if ((type.dtype != bob::core::array::t_uint8) || (type.nd != 2)) { @@ -115,9 +115,41 @@ class Localizer { } return tuple(retval); + } + + + /** + * Detect and locates the landmarks from an input image + */ + object call2(bob::python::const_ndarray input, const int b_y, const int b_x, const int b_height, const int b_width) + { + //checks type + const bob::core::array::typeinfo& type = input.type(); + if ((type.dtype != bob::core::array::t_uint8) || (type.nd != 2)) { + PYTHON_ERROR(TypeError, "Input data must be a 2D numpy.array with dtype=uint8 (i.e. a gray-scaled image), but you passed %s", type.str().c_str()); + } + //converts to IplImage + boost::shared_ptr<IplImage> ipl_image(cvCreateImageHeader(cvSize(type.shape[1], type.shape[0]), IPL_DEPTH_8U, 1), std::ptr_fun(delete_image)); + ipl_image->imageData = (char*)input.bz<uint8_t,2>().data(); + + int bbox[4] = {b_x, b_y, b_x + b_width, b_y + b_height}; + { + bob::python::no_gil unlock; + flandmark_detect(ipl_image.get(), bbox, m_flandmark.get(), + m_landmarks.get()); + } + + list lmlist; ///< landmark list + + for (int i = 0; i < (2*m_flandmark->data.options.M); i += 2) { + lmlist.append(make_tuple(m_landmarks[i], m_landmarks[i+1])); + } + + return object(lmlist); } + private: //representation boost::shared_ptr<CvHaarClassifierCascade> m_cascade; @@ -131,6 +163,7 @@ BOOST_PYTHON_MODULE(_flandmark) { bob::python::setup_python("bindings to flandmark - a library for the localization of facial landmarks"); class_<Localizer>("Localizer", "A key-point localization for faces using flandmark", init<const std::string&, const std::string&>((arg("detector"), arg("localizer")), "Initializes with both an OpenCV face detector model and an flandmark model")) - .def("__call__", &Localizer::operator(), (arg("self"), arg("image")), "Locates (possibly multiple) key-points on the given input image. Returns a list of located faces (by OpenCV's model), each attached to a list of key-points.") + .def("__call__", &Localizer::call1, (arg("image")), "Locates (possibly multiple) key-points on the given input image. Returns a list of located faces (by OpenCV's model), each attached to a list of key-points.") + .def("__call__", &Localizer::call2, (arg("image"), arg("b_y"), arg("b_x"), arg("b_height"), arg("b_width")), "Locates (possibly multiple) key-points on the given input image, given a bounding box and returns them as a list.") ; }