22#ifndef MULTI_IMAGE_FITTING_HPP_
23#define MULTI_IMAGE_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"
89inline std::pair<std::vector<core::Mesh>, std::vector<fitting::RenderingParameters>>
fit_shape_and_pose(
91 const std::vector<morphablemodel::Blendshape>& blendshapes,
93 const core::LandmarkMapper& landmark_mapper, std::vector<int> image_width, std::vector<int> image_height,
96 cpp17::optional<int> num_shape_coefficients_to_fit,
float lambda,
97 cpp17::optional<fitting::RenderingParameters> initial_rendering_params,
98 std::vector<float>& pca_shape_coefficients, std::vector<std::vector<float>>& blendshape_coefficients,
99 std::vector<std::vector<Eigen::Vector2f>>& fitted_image_points)
101 assert(blendshapes.size() > 0);
102 assert(landmarks.size() > 0 && landmarks.size() == image_width.size() &&
103 image_width.size() == image_height.size());
104 assert(num_iterations > 0);
106 int num_images =
static_cast<int>(landmarks.size());
107 for (
int j = 0; j < num_images; ++j)
109 assert(landmarks[j].size() >= 4);
110 assert(image_width[j] > 0 && image_height[j] > 0);
114 using Eigen::MatrixXf;
115 using Eigen::Vector2f;
116 using Eigen::Vector4f;
117 using Eigen::VectorXf;
120 if (!num_shape_coefficients_to_fit)
125 if (pca_shape_coefficients.empty())
127 pca_shape_coefficients.resize(num_shape_coefficients_to_fit.value());
133 if (blendshape_coefficients.empty())
135 for (
int j = 0; j < num_images; ++j)
137 std::vector<float> current_blendshape_coefficients;
138 current_blendshape_coefficients.resize(blendshapes.size());
139 blendshape_coefficients.push_back(current_blendshape_coefficients);
147 vector<VectorXf> current_combined_shapes;
148 vector<core::Mesh> current_meshes;
149 for (
int j = 0; j < num_images; ++j)
151 VectorXf current_combined_shape =
153 blendshapes_as_basis * Eigen::Map<const Eigen::VectorXf>(blendshape_coefficients[j].data(),
154 blendshape_coefficients[j].size());
155 current_combined_shapes.push_back(current_combined_shape);
161 current_meshes.push_back(current_mesh);
165 vector<vector<Vector4f>> model_points;
166 vector<vector<int>> vertex_indices;
167 vector<vector<Vector2f>> image_points;
169 for (
int j = 0; j < num_images; ++j)
171 vector<Vector4f> current_model_points;
172 vector<int> current_vertex_indices;
173 vector<Vector2f> current_image_points;
178 for (
int i = 0; i < landmarks[j].size(); ++i)
180 const auto converted_name = landmark_mapper.
convert(landmarks[j][i].name);
185 const int vertex_idx = std::stoi(converted_name.value());
186 current_model_points.emplace_back(current_meshes[j].vertices[vertex_idx].homogeneous());
187 current_vertex_indices.emplace_back(vertex_idx);
188 current_image_points.emplace_back(landmarks[j][i].coordinates);
191 model_points.push_back(current_model_points);
192 vertex_indices.push_back(current_vertex_indices);
193 image_points.push_back(current_image_points);
198 vector<fitting::RenderingParameters> rendering_params;
199 for (
int j = 0; j < num_images; ++j)
205 rendering_params.push_back(current_rendering_params);
207 const Eigen::Matrix<float, 3, 4> affine_from_ortho =
210 blendshapes, current_pca_shape, affine_from_ortho, image_points[j], vertex_indices[j]);
214 current_combined_shapes[j] =
216 Eigen::Map<const Eigen::VectorXf>(blendshape_coefficients[j].data(),
217 blendshape_coefficients[j].size());
226 vector<vector<int>> fixed_vertex_indices(vertex_indices);
227 vector<vector<Vector2f>> fixed_image_points(image_points);
229 for (
int i = 0; i < num_iterations; ++i)
231 vector<Eigen::Matrix<float, 3, 4>> affine_from_orthos;
232 vector<VectorXf> mean_plus_blendshapes;
234 image_points = fixed_image_points;
235 vertex_indices = fixed_vertex_indices;
237 for (
int j = 0; j < num_images; ++j)
240 vector<Vector2f> image_points_contour;
241 vector<int> vertex_indices_contour;
242 const auto yaw_angle = rendering_params[j].get_yaw_pitch_roll()[0];
244 std::tie(image_points_contour, std::ignore, vertex_indices_contour) =
246 landmarks[j], contour_landmarks, model_contour, yaw_angle, current_meshes[j],
247 rendering_params[j].get_modelview(), rendering_params[j].get_projection(),
250 vertex_indices[j] =
fitting::concat(vertex_indices[j], vertex_indices_contour);
251 image_points[j] =
fitting::concat(image_points[j], image_points_contour);
254 vector<Vector2f> occluding_contour_landmarks;
255 if (yaw_angle >= 0.0f)
258 landmarks[j], contour_landmarks.left_contour);
260 begin(contour_landmarks_), end(contour_landmarks_),
261 [&occluding_contour_landmarks](
auto&& lm) {
262 occluding_contour_landmarks.push_back({lm.coordinates[0], lm.coordinates[1]});
266 auto contour_landmarks_ =
core::filter(landmarks[j], contour_landmarks.right_contour);
268 begin(contour_landmarks_), end(contour_landmarks_),
269 [&occluding_contour_landmarks](
auto&& lm) {
270 occluding_contour_landmarks.push_back({lm.coordinates[0], lm.coordinates[1]});
274 current_meshes[j], edge_topology, rendering_params[j], occluding_contour_landmarks, 180.0f);
275 image_points[j] =
fitting::concat(image_points[j], edge_correspondences.first);
276 vertex_indices[j] =
fitting::concat(vertex_indices[j], edge_correspondences.second);
279 model_points[j].clear();
280 for (
auto v : vertex_indices[j])
282 model_points[j].push_back({current_meshes[j].vertices[v][0], current_meshes[j].vertices[v][1],
283 current_meshes[j].vertices[v][2], 1.0f});
292 const Eigen::Matrix<float, 3, 4> affine_from_ortho =
294 affine_from_orthos.push_back(affine_from_ortho);
297 VectorXf current_mean_plus_blendshapes =
299 blendshapes_as_basis * Eigen::Map<const Eigen::VectorXf>(blendshape_coefficients[j].data(),
300 blendshape_coefficients[j].size());
301 mean_plus_blendshapes.push_back(current_mean_plus_blendshapes);
304 morphable_model.
get_shape_model(), affine_from_orthos, image_points, vertex_indices,
305 mean_plus_blendshapes, lambda, num_shape_coefficients_to_fit);
310 for (
int j = 0; j < num_images; ++j)
313 blendshapes, current_pca_shape, affine_from_orthos[j], image_points[j], vertex_indices[j]);
315 current_combined_shapes[j] =
317 blendshapes_as_basis * Eigen::Map<const Eigen::VectorXf>(blendshape_coefficients[j].data(),
318 blendshape_coefficients[j].size());
327 fitted_image_points = image_points;
328 return {current_meshes, rendering_params};
369inline std::pair<std::vector<core::Mesh>, std::vector<fitting::RenderingParameters>>
371 const std::vector<morphablemodel::Blendshape>& blendshapes,
377 cpp17::optional<int> num_shape_coefficients_to_fit = cpp17::nullopt,
float lambda = 30.0f)
380 vector<float> pca_shape_coefficients;
381 vector<vector<float>> blendshape_coefficients;
382 vector<vector<Eigen::Vector2f>> fitted_image_points;
384 return fit_shape_and_pose(morphable_model, blendshapes, landmarks, landmark_mapper, image_width,
385 image_height, edge_topology, contour_landmarks, model_contour, num_iterations,
386 num_shape_coefficients_to_fit, lambda, cpp17::nullopt, pca_shape_coefficients,
387 blendshape_coefficients, 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
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 PcaModel & get_shape_model() const
Definition: MorphableModel.hpp:125
const PcaModel & get_color_model() const
Definition: MorphableModel.hpp:135
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
std::vector< float > fit_shape_to_landmarks_linear_multi(const morphablemodel::PcaModel &shape_model, const std::vector< Eigen::Matrix< float, 3, 4 > > &affine_camera_matrices, const std::vector< std::vector< Eigen::Vector2f > > &landmarks, const std::vector< std::vector< int > > &vertex_ids, std::vector< Eigen::VectorXf > base_faces=std::vector< 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:178
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_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
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
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
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.
This class represents a 3D mesh consisting of vertices, vertex colour information and texture coordin...
Definition: Mesh.hpp:45
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