22#ifndef EOS_FITTING_HPP
23#define EOS_FITTING_HPP
25#include "eos/core/Landmark.hpp"
26#include "eos/core/LandmarkMapper.hpp"
27#include "eos/core/Mesh.hpp"
28#include "eos/morphablemodel/MorphableModel.hpp"
29#include "eos/morphablemodel/Blendshape.hpp"
30#include "eos/morphablemodel/EdgeTopology.hpp"
31#include "eos/fitting/orthographic_camera_estimation_linear.hpp"
32#include "eos/fitting/linear_shape_fitting.hpp"
33#include "eos/fitting/blendshape_fitting.hpp"
34#include "eos/fitting/contour_correspondence.hpp"
35#include "eos/fitting/closest_edge_fitting.hpp"
36#include "eos/fitting/RenderingParameters.hpp"
37#include "eos/cpp17/optional.hpp"
69inline Eigen::VectorXf
fit_shape(Eigen::Matrix<float, 3, 4> affine_camera_matrix,
71 const std::vector<morphablemodel::Blendshape>& blendshapes,
72 const std::vector<Eigen::Vector2f>& image_points,
73 const std::vector<int>& vertex_indices,
float lambda,
74 cpp17::optional<int> num_coefficients_to_fit,
75 std::vector<float>& pca_shape_coefficients,
76 std::vector<float>& blendshape_coefficients)
78 using Eigen::MatrixXf;
79 using Eigen::VectorXf;
83 std::vector<float> last_blendshape_coeffs, current_blendshape_coeffs;
84 std::vector<float> last_pca_coeffs, current_pca_coeffs;
85 current_blendshape_coeffs.resize(blendshapes.size());
89 VectorXf combined_shape;
92 last_blendshape_coeffs = current_blendshape_coeffs;
93 last_pca_coeffs = current_pca_coeffs;
96 const VectorXf mean_plus_blendshapes =
98 blendshapes_as_basis *
99 Eigen::Map<const VectorXf>(last_blendshape_coeffs.data(), last_blendshape_coeffs.size());
101 morphable_model.
get_shape_model(), affine_camera_matrix, image_points, vertex_indices,
102 mean_plus_blendshapes, lambda, num_coefficients_to_fit);
107 blendshapes, pca_model_shape, affine_camera_matrix, image_points, vertex_indices);
110 combined_shape = pca_model_shape +
111 blendshapes_as_basis * Eigen::Map<const VectorXf>(current_blendshape_coeffs.data(),
112 current_blendshape_coeffs.size());
114 std::abs(Eigen::Map<const VectorXf>(current_pca_coeffs.data(), current_pca_coeffs.size()).norm() -
115 Eigen::Map<const VectorXf>(last_pca_coeffs.data(), last_pca_coeffs.size()).norm()) >= 0.01 ||
117 Eigen::Map<const VectorXf>(current_blendshape_coeffs.data(), current_blendshape_coeffs.size()).norm() -
118 Eigen::Map<const VectorXf>(last_blendshape_coeffs.data(), last_blendshape_coeffs.size()).norm()) >= 0.01);
120 pca_shape_coefficients = current_pca_coeffs;
121 blendshape_coefficients = current_blendshape_coeffs;
123 return combined_shape;
140inline Eigen::VectorXf
fit_shape(Eigen::Matrix<float, 3, 4> affine_camera_matrix,
142 const std::vector<morphablemodel::Blendshape>& blendshapes,
143 const std::vector<Eigen::Vector2f>& image_points,
144 const std::vector<int>& vertex_indices,
float lambda = 3.0f,
145 cpp17::optional<int> num_coefficients_to_fit = cpp17::optional<int>())
147 std::vector<float> unused;
148 return fit_shape(affine_camera_matrix, morphable_model, blendshapes, image_points, vertex_indices, lambda,
149 num_coefficients_to_fit, unused, unused);
179 using Eigen::Vector2f;
180 using Eigen::Vector4f;
184 vector<Vector4f> model_points;
185 vector<int> vertex_indices;
186 vector<Vector2f> image_points;
189 for (
int i = 0; i < landmarks.size(); ++i)
191 const auto converted_name = landmark_mapper.
convert(landmarks[i].name);
196 const int vertex_idx = std::stoi(converted_name.get());
198 model_points.emplace_back(vertex.homogeneous());
199 vertex_indices.emplace_back(vertex_idx);
200 image_points.emplace_back(landmarks[i].coordinates);
202 return std::make_tuple(image_points, model_points, vertex_indices);
223inline std::vector<float>
225 const Eigen::Matrix<float, 3, 4>& affine_camera_matrix,
226 const std::vector<Eigen::Vector2f>& landmarks,
const std::vector<int>& vertex_ids,
227 cpp17::optional<float> lambda_expressions = cpp17::optional<float>(),
228 cpp17::optional<int> num_expression_coefficients_to_fit = cpp17::optional<int>())
230 std::vector<float> expression_coefficients;
231 if (cpp17::holds_alternative<morphablemodel::PcaModel>(expression_model))
233 const auto& pca_expression_model = cpp17::get<morphablemodel::PcaModel>(expression_model);
237 const Eigen::VectorXf face_instance_with_expression_mean =
238 face_instance + pca_expression_model.get_mean();
241 vertex_ids, face_instance_with_expression_mean,
242 lambda_expressions.value_or(65.0f),
243 num_expression_coefficients_to_fit);
244 }
else if (cpp17::holds_alternative<morphablemodel::Blendshapes>(expression_model))
246 const auto& expression_blendshapes = cpp17::get<morphablemodel::Blendshapes>(expression_model);
248 landmarks, vertex_ids);
251 throw std::runtime_error(
"The given expression_model doesn't contain a PcaModel or Blendshapes.");
307 int num_iterations, cpp17::optional<int> num_shape_coefficients_to_fit,
float lambda_identity,
308 cpp17::optional<int> num_expression_coefficients_to_fit, cpp17::optional<float> lambda_expressions,
309 std::vector<float>& pca_shape_coefficients, std::vector<float>& expression_coefficients,
310 std::vector<Eigen::Vector2f>& fitted_image_points)
313 assert(landmarks.size() >= 4);
314 assert(image_width > 0 && image_height > 0);
315 assert(num_iterations > 0);
318 if (num_shape_coefficients_to_fit)
320 if (num_shape_coefficients_to_fit.value() >
323 throw std::runtime_error(
324 "Specified more shape coefficients to fit than the given shape model contains.");
328 using Eigen::MatrixXf;
329 using Eigen::Vector2f;
330 using Eigen::Vector4f;
331 using Eigen::VectorXf;
334 if (!num_shape_coefficients_to_fit)
339 if (pca_shape_coefficients.empty())
341 pca_shape_coefficients.resize(num_shape_coefficients_to_fit.value());
357 VectorXf current_combined_shape =
367 vector<Vector4f> model_points;
368 vector<int> vertex_indices;
369 vector<Vector2f> image_points;
373 for (
int i = 0; i < landmarks.size(); ++i)
375 const auto converted_name = landmark_mapper.
convert(landmarks[i].name);
388 const auto found_vertex_idx =
392 vertex_idx = found_vertex_idx->second;
399 vertex_idx = std::stoi(converted_name.value());
401 model_points.emplace_back(current_mesh.vertices[vertex_idx].homogeneous());
402 vertex_indices.emplace_back(vertex_idx);
403 image_points.emplace_back(landmarks[i].coordinates);
412 const Eigen::Matrix<float, 3, 4> affine_from_ortho =
414 expression_coefficients =
416 image_points, vertex_indices, lambda_expressions, num_expression_coefficients_to_fit);
419 current_combined_shape = current_pca_shape + draw_sample(morphable_model.
get_expression_model().value(),
420 expression_coefficients);
429 const auto fixed_image_points = image_points;
430 const auto fixed_vertex_indices = vertex_indices;
432 for (
int i = 0; i < num_iterations; ++i)
434 image_points = fixed_image_points;
435 vertex_indices = fixed_vertex_indices;
437 vector<Vector2f> image_points_contour;
438 vector<int> vertex_indices_contour;
441 std::tie(image_points_contour, std::ignore, vertex_indices_contour) =
447 vertex_indices =
fitting::concat(vertex_indices, vertex_indices_contour);
451 vector<Vector2f> occluding_contour_landmarks;
452 if (yaw_angle >= 0.0f)
454 const auto contour_landmarks_ =
455 core::filter(landmarks, contour_landmarks.left_contour);
456 std::for_each(begin(contour_landmarks_), end(contour_landmarks_),
457 [&occluding_contour_landmarks](
const auto& lm) {
458 occluding_contour_landmarks.push_back({lm.coordinates[0], lm.coordinates[1]});
462 const auto contour_landmarks_ =
core::filter(landmarks, contour_landmarks.right_contour);
463 std::for_each(begin(contour_landmarks_), end(contour_landmarks_),
464 [&occluding_contour_landmarks](
const auto& lm) {
465 occluding_contour_landmarks.push_back({lm.coordinates[0], lm.coordinates[1]});
469 current_mesh, edge_topology, rendering_params, occluding_contour_landmarks, 180.0f);
470 image_points =
fitting::concat(image_points, edge_correspondences.first);
471 vertex_indices =
fitting::concat(vertex_indices, edge_correspondences.second);
474 model_points.clear();
475 for (
auto v : vertex_indices)
477 model_points.push_back({current_mesh.vertices[v][0], current_mesh.vertices[v][1],
478 current_mesh.vertices[v][2], 1.0f});
486 const Eigen::Matrix<float, 3, 4> affine_from_ortho =
490 const VectorXf mean_plus_expressions =
494 morphable_model.
get_shape_model(), affine_from_ortho, image_points, vertex_indices,
495 mean_plus_expressions, lambda_identity, num_shape_coefficients_to_fit);
501 image_points, vertex_indices, lambda_expressions, num_expression_coefficients_to_fit);
503 current_combined_shape =
513 fitted_image_points = image_points;
514 return {current_mesh, rendering_params};
559 int num_iterations = 5, cpp17::optional<int> num_shape_coefficients_to_fit = cpp17::nullopt,
560 float lambda_identity = 50.0f, cpp17::optional<int> num_expression_coefficients_to_fit = cpp17::nullopt,
561 cpp17::optional<float> lambda_expressions = cpp17::nullopt)
563 std::vector<float> pca_coeffs;
564 std::vector<float> blendshape_coeffs;
565 std::vector<Eigen::Vector2f> fitted_image_points;
566 return fit_shape_and_pose(morphable_model, landmarks, landmark_mapper, image_width, image_height,
567 edge_topology, contour_landmarks, model_contour, num_iterations,
568 num_shape_coefficients_to_fit, lambda_identity,
569 num_expression_coefficients_to_fit, lambda_expressions, pca_coeffs,
570 blendshape_coeffs, fitted_image_points);
616 const std::vector<int>& vertex_indices,
int image_width,
int image_height,
int num_iterations,
617 cpp17::optional<int> num_shape_coefficients_to_fit,
float lambda_identity,
618 cpp17::optional<int> num_expression_coefficients_to_fit, cpp17::optional<float> lambda_expressions,
619 std::vector<float>& pca_shape_coefficients, std::vector<float>& expression_coefficients,
620 std::vector<Eigen::Vector2f>& fitted_image_points)
623 assert(image_points.size() >= 4);
624 assert(image_points.size() == vertex_indices.size());
625 assert(image_width > 0 && image_height > 0);
626 assert(num_iterations > 0);
630 using Eigen::MatrixXf;
631 using Eigen::Vector2f;
632 using Eigen::Vector4f;
633 using Eigen::VectorXf;
636 if (!num_shape_coefficients_to_fit)
641 if (pca_shape_coefficients.empty())
643 pca_shape_coefficients.resize(num_shape_coefficients_to_fit.value());
659 VectorXf current_combined_shape =
669 vector<Vector4f> model_points;
671 for (
int i = 0; i < image_points.size(); ++i)
673 const int vertex_idx = vertex_indices[i];
674 Vector4f vertex(current_mesh.vertices[vertex_idx][0], current_mesh.vertices[vertex_idx][1],
675 current_mesh.vertices[vertex_idx][2], 1.0f);
676 model_points.emplace_back(vertex);
685 const Eigen::Matrix<float, 3, 4> affine_from_ortho =
687 expression_coefficients =
689 image_points, vertex_indices, lambda_expressions, num_expression_coefficients_to_fit);
692 current_combined_shape = current_pca_shape + draw_sample(morphable_model.
get_expression_model().value(),
693 expression_coefficients);
700 for (
int i = 0; i < num_iterations; ++i)
703 model_points.clear();
704 for (
auto v : vertex_indices)
706 model_points.push_back({current_mesh.vertices[v][0], current_mesh.vertices[v][1],
707 current_mesh.vertices[v][2], 1.0f});
715 const Eigen::Matrix<float, 3, 4> affine_from_ortho =
719 const VectorXf mean_plus_expressions =
723 morphable_model.
get_shape_model(), affine_from_ortho, image_points, vertex_indices,
724 mean_plus_expressions, lambda_identity, num_shape_coefficients_to_fit);
730 image_points, vertex_indices, lambda_expressions, num_expression_coefficients_to_fit);
732 current_combined_shape =
742 fitted_image_points = image_points;
743 return {current_mesh, rendering_params};
768 const std::vector<int>& vertex_indices,
int image_width,
int image_height,
int num_iterations,
769 cpp17::optional<int> num_shape_coefficients_to_fit,
float lambda_identity,
770 cpp17::optional<int> num_expression_coefficients_to_fit, cpp17::optional<float> lambda_expressions)
772 std::vector<float> pca_coeffs;
773 std::vector<float> blendshape_coeffs;
774 std::vector<Eigen::Vector2f> fitted_image_points;
775 return fit_shape_and_pose(morphable_model, image_points, vertex_indices, image_width, image_height,
776 num_iterations, num_shape_coefficients_to_fit, lambda_identity,
777 num_expression_coefficients_to_fit, lambda_expressions, pca_coeffs,
778 blendshape_coeffs, fitted_image_points);
Represents a mapping from one kind of landmarks to a different format (e.g. model vertices).
Definition: LandmarkMapper.hpp:53
cpp17::optional< std::string > convert(std::string landmark_name) const
Converts the given landmark name to the mapped name.
Definition: LandmarkMapper.hpp:116
Represents a set of estimated model parameters (rotation, translation) and camera parameters (viewing...
Definition: RenderingParameters.hpp:102
Eigen::Matrix4f get_modelview() const
Construct a model-view matrix from the RenderingParameters' rotation and translation,...
Definition: RenderingParameters.hpp:220
Eigen::Vector3f get_yaw_pitch_roll()
Returns the intrinsic rotation angles, also called Tait-Bryan angles, in degrees. The returned Vector...
Definition: RenderingParameters.hpp:179
Eigen::Matrix4f get_projection() const
Construct an orthographic or perspective projection matrix from the RenderingParameters' frustum (ort...
Definition: RenderingParameters.hpp:245
A class representing a 3D Morphable Model, consisting of a shape- and colour (albedo) PCA model.
Definition: MorphableModel.hpp:73
const std::vector< std::array< double, 2 > > & get_texture_coordinates() const
Definition: MorphableModel.hpp:413
const auto & get_landmark_definitions() const
Definition: MorphableModel.hpp:403
const std::vector< std::array< int, 3 > > & get_texture_triangle_indices() const
Definition: MorphableModel.hpp:423
const auto & get_expression_model() const
Definition: MorphableModel.hpp:150
const PcaModel & get_shape_model() const
Definition: MorphableModel.hpp:125
bool has_separate_expression_model() const
Definition: MorphableModel.hpp:388
const PcaModel & get_color_model() const
Definition: MorphableModel.hpp:135
Eigen::Vector3f get_mean_at_point(int vertex_index) const
Definition: PcaModel.hpp:134
int get_num_principal_components() const
Definition: PcaModel.hpp:88
const std::vector< std::array< int, 3 > > & get_triangle_list() const
Definition: PcaModel.hpp:113
const Eigen::VectorXf & get_mean() const
Definition: PcaModel.hpp:123
Eigen::VectorXf draw_sample(RNG &engine, float sigma=1.0f) const
Definition: PcaModel.hpp:150
std::vector< Landmark< LandmarkType > > LandmarkCollection
A trivial collection of landmarks that belong together.
Definition: Landmark.hpp:47
LandmarkCollection< T > filter(const LandmarkCollection< T > &landmarks, const std::vector< std::string > &filter)
Shorthand for a 2D floating point landmark type.
Definition: Landmark.hpp:69
ScaledOrthoProjectionParameters estimate_orthographic_projection_linear(std::vector< Eigen::Vector2f > image_points, std::vector< Eigen::Vector4f > model_points, bool is_viewport_upsidedown, cpp17::optional< int > viewport_height=cpp17::nullopt)
Definition: orthographic_camera_estimation_linear.hpp:72
Eigen::Vector4f get_opencv_viewport(int width, int height)
Returns a glm/OpenGL compatible viewport vector that flips y and has the origin on the top-left,...
Definition: RenderingParameters.hpp:325
std::vector< float > fit_shape_to_landmarks_linear(const morphablemodel::PcaModel &shape_model, Eigen::Matrix< float, 3, 4 > affine_camera_matrix, const std::vector< Eigen::Vector2f > &landmarks, const std::vector< int > &vertex_ids, Eigen::VectorXf base_face=Eigen::VectorXf(), float lambda=3.0f, cpp17::optional< int > num_coefficients_to_fit=cpp17::optional< int >(), cpp17::optional< float > detector_standard_deviation=cpp17::optional< float >(), cpp17::optional< float > model_standard_deviation=cpp17::optional< float >())
Definition: linear_shape_fitting.hpp:60
std::vector< float > fit_blendshapes_to_landmarks_nnls(const std::vector< morphablemodel::Blendshape > &blendshapes, const Eigen::VectorXf &face_instance, Eigen::Matrix< float, 3, 4 > affine_camera_matrix, const std::vector< Eigen::Vector2f > &landmarks, const std::vector< int > &vertex_ids)
Definition: blendshape_fitting.hpp:138
std::vector< float > fit_expressions(const morphablemodel::ExpressionModel &expression_model, const Eigen::VectorXf &face_instance, const Eigen::Matrix< float, 3, 4 > &affine_camera_matrix, const std::vector< Eigen::Vector2f > &landmarks, const std::vector< int > &vertex_ids, cpp17::optional< float > lambda_expressions=cpp17::optional< float >(), cpp17::optional< int > num_expression_coefficients_to_fit=cpp17::optional< int >())
Fits the given expression model to landmarks.
Definition: fitting.hpp:224
auto get_corresponding_pointset(const T &landmarks, const core::LandmarkMapper &landmark_mapper, const morphablemodel::MorphableModel &morphable_model)
Takes a LandmarkCollection of 2D landmarks and, using the landmark_mapper, finds the corresponding 3D...
Definition: fitting.hpp:176
auto concat(const std::vector< T > &vec_a, const std::vector< T > &vec_b)
Concatenates two std::vector's of the same type and returns the concatenated vector....
Definition: contour_correspondence.hpp:388
Eigen::Matrix< float, 3, 4 > get_3x4_affine_camera_matrix(RenderingParameters params, int width, int height)
Creates a 3x4 affine camera matrix from given fitting parameters. The matrix transforms points direct...
Definition: RenderingParameters.hpp:337
Eigen::VectorXf fit_shape(Eigen::Matrix< float, 3, 4 > affine_camera_matrix, const morphablemodel::MorphableModel &morphable_model, const std::vector< morphablemodel::Blendshape > &blendshapes, const std::vector< Eigen::Vector2f > &image_points, const std::vector< int > &vertex_indices, float lambda, cpp17::optional< int > num_coefficients_to_fit, std::vector< float > &pca_shape_coefficients, std::vector< float > &blendshape_coefficients)
Definition: fitting.hpp:69
std::pair< std::vector< Eigen::Vector2f >, std::vector< int > > find_occluding_edge_correspondences(const core::Mesh &mesh, const morphablemodel::EdgeTopology &edge_topology, const fitting::RenderingParameters &rendering_parameters, const std::vector< Eigen::Vector2f > &image_edges, float distance_threshold=64.0f, bool perform_self_occlusion_check=true)
For a given list of 2D edge points, find corresponding 3D vertex IDs.
Definition: closest_edge_fitting.hpp:278
std::tuple< std::vector< Eigen::Vector2f >, std::vector< Eigen::Vector4f >, std::vector< int > > get_contour_correspondences(const core::LandmarkCollection< Eigen::Vector2f > &landmarks, const ContourLandmarks &contour_landmarks, const ModelContour &model_contour, float yaw_angle, const core::Mesh &mesh, const Eigen::Matrix4f &view_model, const Eigen::Matrix4f &ortho_projection, const Eigen::Vector4f &viewport, float frontal_range_threshold=7.5f)
Definition: contour_correspondence.hpp:237
std::pair< core::Mesh, fitting::RenderingParameters > fit_shape_and_pose(const morphablemodel::MorphableModel &morphable_model, const core::LandmarkCollection< Eigen::Vector2f > &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, cpp17::optional< int > num_shape_coefficients_to_fit, float lambda_identity, cpp17::optional< int > num_expression_coefficients_to_fit, cpp17::optional< float > lambda_expressions, std::vector< float > &pca_shape_coefficients, std::vector< float > &expression_coefficients, std::vector< Eigen::Vector2f > &fitted_image_points)
Fit the pose (camera), shape model, and expression blendshapes to landmarks, in an iterative way.
Definition: fitting.hpp:302
cpp17::variant< PcaModel, Blendshapes > ExpressionModel
Type alias to represent an expression model, which can either consist of blendshapes or a PCA model.
Definition: ExpressionModel.hpp:43
Eigen::MatrixXf to_matrix(const std::vector< Blendshape > &blendshapes)
Copies the blendshapes into a matrix, with each column being a blendshape.
Definition: Blendshape.hpp:118
core::Mesh sample_to_mesh(const Eigen::VectorXf &shape_instance, const Eigen::VectorXf &color_instance, const std::vector< std::array< int, 3 > > &tvi, const std::vector< std::array< int, 3 > > &tci, const std::vector< std::array< double, 2 > > &texture_coordinates=std::vector< std::array< double, 2 > >(), const std::vector< std::array< int, 3 > > &texture_triangle_indices=std::vector< std::array< int, 3 > >())
Definition: MorphableModel.hpp:584
Namespace containing all of eos's 3D model fitting functionality.
Defines which 2D landmarks comprise the right and left face contour.
Definition: contour_correspondence.hpp:140
Definition of the vertex indices that define the right and left model contour.
Definition: contour_correspondence.hpp:71
Definition: orthographic_camera_estimation_linear.hpp:42
A struct containing a 3D shape model's edge topology.
Definition: EdgeTopology.hpp:54