Commit 58b54cf1 authored by Philipp Kopp's avatar Philipp Kopp

Merge branch 'devel' into multi_image_fit_devel

parents d34e1793 a143f1d7
cmake_minimum_required(VERSION 3.1.3) cmake_minimum_required(VERSION 3.1.3)
project(eos) project(eos)
set(eos_VERSION_MAJOR 0) set(eos_VERSION_MAJOR 0)
set(eos_VERSION_MINOR 11) set(eos_VERSION_MINOR 12)
set(eos_VERSION_PATCH 0) set(eos_VERSION_PATCH 1)
set(eos_VERSION ${eos_VERSION_MAJOR}.${eos_VERSION_MINOR}.${eos_VERSION_PATCH}) set(eos_VERSION ${eos_VERSION_MAJOR}.${eos_VERSION_MINOR}.${eos_VERSION_PATCH})
set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY USE_FOLDERS ON)
......
include README.md LICENSE include README.md LICENSE
global-include CMakeLists.txt *.cmake global-include CMakeLists.txt *.cmake
recursive-include 3rdparty/cereal-1.1.1/include * recursive-include 3rdparty/cereal/include *
recursive-include 3rdparty/eigen/Eigen *
recursive-include 3rdparty/eigen3-nnls/src *.h recursive-include 3rdparty/eigen3-nnls/src *.h
recursive-include 3rdparty/glm/glm * recursive-include 3rdparty/glm/glm *
recursive-include 3rdparty/nanoflann/include * recursive-include 3rdparty/nanoflann/include *
recursive-include 3rdparty/pybind11 * recursive-include 3rdparty/pybind11 *
recursive-include cmake *
recursive-include include * recursive-include include *
recursive-include python * recursive-include python *
...@@ -32,9 +32,10 @@ At the moment, it mainly provides the following functionality: ...@@ -32,9 +32,10 @@ At the moment, it mainly provides the following functionality:
To use the library in your own project, just add the following directories to your include path: To use the library in your own project, just add the following directories to your include path:
* `eos/include` * `eos/include`
* `eos/3rdparty/cereal-1.1.1/include` * `eos/3rdparty/cereal/include`
* `eos/3rdparty/glm` * `eos/3rdparty/glm`
* `eos/3rdparty/nanoflann/include` * `eos/3rdparty/nanoflann/include`
* `eos/3rdparty/eigen/Eigen`
* `eos/3rdparty/eigen3-nnls/src` * `eos/3rdparty/eigen3-nnls/src`
**Make sure to clone with `--recursive` to download the required submodules!** **Make sure to clone with `--recursive` to download the required submodules!**
...@@ -84,9 +85,10 @@ The full model is available at [http://www.cvssp.org/facemodel](http://www.cvssp ...@@ -84,9 +85,10 @@ The full model is available at [http://www.cvssp.org/facemodel](http://www.cvssp
## Python bindings ## Python bindings
eos includes python bindings for some of its functionality (and more can be added!). Set `-DEOS_GENERATE_PYTHON_BINDINGS=on` when running `cmake` to build them (and optionally set `PYTHON_EXECUTABLE` to point to your python interpreter if it's not found automatically). eos includes python bindings for some of its functionality (and more can be added!). An experimental package is on PyPI: Try `pip install eos-py`. You will still need the data files from this repository.
In case of issues, build the bindings manually: Clone the repository and set `-DEOS_GENERATE_PYTHON_BINDINGS=on` when running `cmake` (and optionally set `PYTHON_EXECUTABLE` to point to your python interpreter if it's not found automatically).
After building the bindings, they can be used like any python module: After having obtained the bindings, they can be used like any python module:
``` ```
import eos import eos
......
...@@ -380,7 +380,7 @@ int main(int argc, char *argv[]) ...@@ -380,7 +380,7 @@ int main(int argc, char *argv[])
// Colour model fitting (this needs a Morphable Model with colour (albedo) model, see note above main()): // Colour model fitting (this needs a Morphable Model with colour (albedo) model, see note above main()):
if (!morphable_model.has_color_model()) if (!morphable_model.has_color_model())
{ {
cout << "The MorphableModel used does not contain a colour (albedo) model. ImageCost requires a model that contains a colour PCA model. You may want to use the full Surrey Face Model or remove this section."; cout << "Error: The MorphableModel used does not contain a colour (albedo) model. ImageCost requires a model that contains a colour PCA model. You may want to use the full Surrey Face Model or remove this section.";
return EXIT_FAILURE; return EXIT_FAILURE;
} }
std::vector<double> colour_coefficients; std::vector<double> colour_coefficients;
......
This diff is collapsed.
...@@ -538,7 +538,7 @@ inline std::pair<core::Mesh, fitting::RenderingParameters> fit_shape_and_pose(co ...@@ -538,7 +538,7 @@ inline std::pair<core::Mesh, fitting::RenderingParameters> fit_shape_and_pose(co
* @param[in] lambda Regularisation parameter of the PCA shape fitting. * @param[in] lambda Regularisation parameter of the PCA shape fitting.
* @return The fitted model shape instance and the final pose. * @return The fitted model shape instance and the final pose.
*/ */
inline std::pair<core::Mesh, fitting::RenderingParameters> fit_shape_and_pose(const morphablemodel::MorphableModel& morphable_model, const std::vector<morphablemodel::Blendshape>& blendshapes, const core::LandmarkCollection<cv::Vec2f>& landmarks, const core::LandmarkMapper& landmark_mapper, int image_width, int image_height, const morphablemodel::EdgeTopology& edge_topology, const fitting::ContourLandmarks& contour_landmarks, const fitting::ModelContour& model_contour, int num_iterations = 5, boost::optional<int> num_shape_coefficients_to_fit = boost::none, float lambda = 30.0f) inline std::pair<core::Mesh, fitting::RenderingParameters> fit_shape_and_pose(const morphablemodel::MorphableModel& morphable_model, const std::vector<morphablemodel::Blendshape>& blendshapes, const core::LandmarkCollection<cv::Vec2f>& landmarks, const core::LandmarkMapper& landmark_mapper, int image_width, int image_height, const morphablemodel::EdgeTopology& edge_topology, const fitting::ContourLandmarks& contour_landmarks, const fitting::ModelContour& model_contour, int num_iterations = 5, boost::optional<int> num_shape_coefficients_to_fit = boost::none, float lambda = 50.0f)
{ {
std::vector<float> pca_coeffs; std::vector<float> pca_coeffs;
std::vector<float> blendshape_coeffs; std::vector<float> blendshape_coeffs;
......
...@@ -102,6 +102,20 @@ inline Eigen::MatrixXf to_matrix(const std::vector<Blendshape>& blendshapes) ...@@ -102,6 +102,20 @@ inline Eigen::MatrixXf to_matrix(const std::vector<Blendshape>& blendshapes)
return blendshapes_as_basis; return blendshapes_as_basis;
}; };
/**
* @brief Maps an std::vector of coefficients with Eigen::Map, so it can be multiplied
* with a blendshapes matrix.
*
* Note that the resulting Eigen::Map only lives as long as the data given lives and is in scope.
*
* @param[in] coefficients Vector of blendshape coefficients.
* @return An Eigen::Map pointing to the given coefficients data.
*/
inline Eigen::Map<const Eigen::VectorXf> to_vector(const std::vector<float>& coefficients)
{
return Eigen::Map<const Eigen::VectorXf>(coefficients.data(), coefficients.size());
};
} /* namespace morphablemodel */ } /* namespace morphablemodel */
} /* namespace eos */ } /* namespace eos */
......
...@@ -33,7 +33,7 @@ end ...@@ -33,7 +33,7 @@ end
% We'll use default values to the following arguments, if they're not % We'll use default values to the following arguments, if they're not
% provided: % provided:
if (~exist('edge_topology', 'var')), edge_topology = '../share/sfm_3448_edge_topology.json'; end if (~exist('edge_topology', 'var')), edge_topology = '../share/sfm_3448_edge_topology.json'; end
if (~exist('contour_landmarks', 'var')), contour_landmarks = '../share/ibug2did.txt'; end if (~exist('contour_landmarks', 'var')), contour_landmarks = '../share/ibug_to_sfm.txt'; end
if (~exist('model_contour', 'var')), model_contour = '../share/model_contours.json'; end if (~exist('model_contour', 'var')), model_contour = '../share/model_contours.json'; end
if (~exist('num_iterations', 'var')), num_iterations = 5; end if (~exist('num_iterations', 'var')), num_iterations = 5; end
if (~exist('num_shape_coefficients_to_fit', 'var')), num_shape_coefficients_to_fit = -1; end if (~exist('num_shape_coefficients_to_fit', 'var')), num_shape_coefficients_to_fit = -1; end
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
%% Set up some required paths to files: %% Set up some required paths to files:
model_file = '../share/sfm_shape_3448.bin'; model_file = '../share/sfm_shape_3448.bin';
blendshapes_file = '../share/expression_blendshapes_3448.bin'; blendshapes_file = '../share/expression_blendshapes_3448.bin';
landmark_mappings = '../share/ibug2did.txt'; landmark_mappings = '../share/ibug_to_sfm.txt';
%% Load an image and its landmarks in ibug format: %% Load an image and its landmarks in ibug format:
image = imread('../bin/data/image_0010.png'); image = imread('../bin/data/image_0010.png');
......
...@@ -10,9 +10,9 @@ def main(): ...@@ -10,9 +10,9 @@ def main():
model = eos.morphablemodel.load_model("../share/sfm_shape_3448.bin") model = eos.morphablemodel.load_model("../share/sfm_shape_3448.bin")
blendshapes = eos.morphablemodel.load_blendshapes("../share/expression_blendshapes_3448.bin") blendshapes = eos.morphablemodel.load_blendshapes("../share/expression_blendshapes_3448.bin")
landmark_mapper = eos.core.LandmarkMapper('../share/ibug2did.txt') landmark_mapper = eos.core.LandmarkMapper('../share/ibug_to_sfm.txt')
edge_topology = eos.morphablemodel.load_edge_topology('../share/sfm_3448_edge_topology.json') edge_topology = eos.morphablemodel.load_edge_topology('../share/sfm_3448_edge_topology.json')
contour_landmarks = eos.fitting.ContourLandmarks.load('../share/ibug2did.txt') contour_landmarks = eos.fitting.ContourLandmarks.load('../share/ibug_to_sfm.txt')
model_contour = eos.fitting.ModelContour.load('../share/model_contours.json') model_contour = eos.fitting.ModelContour.load('../share/model_contours.json')
(mesh, pose, shape_coeffs, blendshape_coeffs) = eos.fitting.fit_shape_and_pose(model, blendshapes, (mesh, pose, shape_coeffs, blendshape_coeffs) = eos.fitting.fit_shape_and_pose(model, blendshapes,
......
...@@ -105,6 +105,8 @@ PYBIND11_PLUGIN(eos) { ...@@ -105,6 +105,8 @@ PYBIND11_PLUGIN(eos) {
.def("get_shape_model", [](const morphablemodel::MorphableModel& m) { return m.get_shape_model(); }, "Returns the PCA shape model of this Morphable Model.") // Not sure if that'll really be const in Python? I think Python does a copy each time this gets called? .def("get_shape_model", [](const morphablemodel::MorphableModel& m) { return m.get_shape_model(); }, "Returns the PCA shape model of this Morphable Model.") // Not sure if that'll really be const in Python? I think Python does a copy each time this gets called?
.def("get_color_model", [](const morphablemodel::MorphableModel& m) { return m.get_color_model(); }, "Returns the PCA colour (albedo) model of this Morphable Model.") // (continued from above:) We may want to use py::overload, but in any case, we need to tell pybind11 if it should use the const or non-const overload. .def("get_color_model", [](const morphablemodel::MorphableModel& m) { return m.get_color_model(); }, "Returns the PCA colour (albedo) model of this Morphable Model.") // (continued from above:) We may want to use py::overload, but in any case, we need to tell pybind11 if it should use the const or non-const overload.
.def("get_mean", &morphablemodel::MorphableModel::get_mean, "Returns the mean of the shape- and colour model as a Mesh.") .def("get_mean", &morphablemodel::MorphableModel::get_mean, "Returns the mean of the shape- and colour model as a Mesh.")
.def("draw_sample", (core::Mesh(morphablemodel::MorphableModel::*)(std::vector<float>, std::vector<float>) const)&morphablemodel::MorphableModel::draw_sample, "Returns a sample from the model with the given shape- and colour PCA coefficients.", py::arg("shape_coefficients"), py::arg("color_coefficients"))
.def("has_color_model", &morphablemodel::MorphableModel::has_color_model, "Returns true if this Morphable Model contains a colour model, and false if it is a shape-only model.")
; ;
morphablemodel_module.def("load_model", &morphablemodel::load_model, "Load a Morphable Model from a cereal::BinaryInputArchive (.bin) from the harddisk.", py::arg("filename")); morphablemodel_module.def("load_model", &morphablemodel::load_model, "Load a Morphable Model from a cereal::BinaryInputArchive (.bin) from the harddisk.", py::arg("filename"));
......
...@@ -88,7 +88,7 @@ class CMakeBuild(build_ext): ...@@ -88,7 +88,7 @@ class CMakeBuild(build_ext):
setup( setup(
name='eos-py', name='eos-py',
version='0.11.0', version='0.12.1',
author='Patrik Huber', author='Patrik Huber',
author_email='patrikhuber@gmail.com', author_email='patrikhuber@gmail.com',
description='Python bindings for eos - A lightweight 3D Morphable Face Model fitting library in modern C++11/14', description='Python bindings for eos - A lightweight 3D Morphable Face Model fitting library in modern C++11/14',
......
...@@ -10,7 +10,7 @@ Files in this directory: ...@@ -10,7 +10,7 @@ Files in this directory:
- sfm_shape_3448.bin: - sfm_shape_3448.bin:
The public shape-only Surrey 3D Morphable Face Model. The public shape-only Surrey 3D Morphable Face Model.
To obtain a full 3DMM and higher resolution levels, follow the instructions To obtain a full 3DMM and higher resolution levels, follow the instructions
at <todo: add link to the page of the Uni>. at cvssp.org/facemodel.
Details about the different models can be found in: Details about the different models can be found in:
"A Multiresolution 3D Morphable Face Model and Fitting Framework", "A Multiresolution 3D Morphable Face Model and Fitting Framework",
P. Huber, G. Hu, R. Tena, P. Mortazavian, W. Koppen, W. Christmas, M. Rätsch, J. Kittler, P. Huber, G. Hu, R. Tena, P. Mortazavian, W. Koppen, W. Christmas, M. Rätsch, J. Kittler,
...@@ -22,7 +22,9 @@ Files in this directory: ...@@ -22,7 +22,9 @@ Files in this directory:
- sfm_3448_edge_topology.json: - sfm_3448_edge_topology.json:
Contains a precomputed list of the model's edges, and the two faces and vertices that are Contains a precomputed list of the model's edges, and the two faces and vertices that are
adjacent to each edge. Used in the edge-fitting. adjacent to each edge. Uses 1-based indexing ("0" has a special meaning of "no adjacent
vertex/edge") - this may change to 0-based in the future to be consistent with the rest of
the library. The file is used in the edge-fitting.
- model_contours.json: - model_contours.json:
Definition of the model's contour vertices of the right and left side of the face. Definition of the model's contour vertices of the right and left side of the face.
......
...@@ -28,13 +28,11 @@ target_link_libraries(scm-to-cereal eos ${OpenCV_LIBS} ${Boost_LIBRARIES}) ...@@ -28,13 +28,11 @@ target_link_libraries(scm-to-cereal eos ${OpenCV_LIBS} ${Boost_LIBRARIES})
add_executable(bfm-binary-to-cereal bfm-binary-to-cereal.cpp) add_executable(bfm-binary-to-cereal bfm-binary-to-cereal.cpp)
target_link_libraries(bfm-binary-to-cereal eos ${OpenCV_LIBS} ${Boost_LIBRARIES}) target_link_libraries(bfm-binary-to-cereal eos ${OpenCV_LIBS} ${Boost_LIBRARIES})
# Reads an edgestruct CSV file created from Matlab, and converts it to json: # Reads an edgestruct CSV file created from Matlab, and converts it to json:
add_executable(edgestruct-csv-to-json edgestruct-csv-to-json.cpp) add_executable(edgestruct-csv-to-json edgestruct-csv-to-json.cpp)
target_link_libraries(edgestruct-csv-to-json eos ${Boost_LIBRARIES}) target_link_libraries(edgestruct-csv-to-json eos ${Boost_LIBRARIES})
# Install targets:
# install target:
install(TARGETS scm-to-cereal DESTINATION bin) install(TARGETS scm-to-cereal DESTINATION bin)
install(TARGETS bfm-binary-to-cereal DESTINATION bin) install(TARGETS bfm-binary-to-cereal DESTINATION bin)
install(TARGETS edgestruct-csv-to-json DESTINATION bin) install(TARGETS edgestruct-csv-to-json DESTINATION bin)
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