22#ifndef EOS_LINEAR_SHAPE_FITTING_HPP
23#define EOS_LINEAR_SHAPE_FITTING_HPP
25#include "eos/morphablemodel/PcaModel.hpp"
26#include "eos/cpp17/optional.hpp"
30#include "Eigen/Sparse"
62 const std::vector<Eigen::Vector2f>& landmarks,
const std::vector<int>& vertex_ids,
63 Eigen::VectorXf base_face = Eigen::VectorXf(),
float lambda = 3.0f,
64 cpp17::optional<int> num_coefficients_to_fit = cpp17::optional<int>(),
65 cpp17::optional<float> detector_standard_deviation = cpp17::optional<float>(),
66 cpp17::optional<float> model_standard_deviation = cpp17::optional<float>())
68 assert(landmarks.size() == vertex_ids.size());
70 using Eigen::VectorXf;
71 using Eigen::MatrixXf;
74 const int num_landmarks =
static_cast<int>(landmarks.size());
76 if (base_face.size() == 0)
83 MatrixXf V_hat_h = MatrixXf::Zero(4 * num_landmarks, num_coeffs_to_fit);
85 for (
int i = 0; i < num_landmarks; ++i)
90 V_hat_h.block(row_index, 0, 3, V_hat_h.cols()) =
91 basis_rows.block(0, 0, basis_rows.rows(), num_coeffs_to_fit);
96 Eigen::SparseMatrix<float> P(3 * num_landmarks, 4 * num_landmarks);
97 std::vector<Eigen::Triplet<float>> P_coefficients;
98 for (
int i = 0; i < num_landmarks; ++i) {
99 for (
int x = 0; x < affine_camera_matrix.rows(); ++x) {
100 for (
int y = 0; y < affine_camera_matrix.cols(); ++y) {
101 P_coefficients.push_back(
102 Eigen::Triplet<float>(3 * i + x, 4 * i + y, affine_camera_matrix(x, y)));
106 P.setFromTriplets(P_coefficients.begin(), P_coefficients.end());
114 const float sigma_squared_2D = std::pow(detector_standard_deviation.value_or(std::sqrt(3.0f)), 2) +
115 std::pow(model_standard_deviation.value_or(0.0f), 2);
117 const VectorXf Omega = VectorXf::Constant(3 * num_landmarks, 1.0f / sigma_squared_2D);
123 VectorXf y = VectorXf::Ones(3 * num_landmarks);
124 for (
int i = 0; i < num_landmarks; ++i)
126 y(3 * i) = landmarks[i][0];
127 y((3 * i) + 1) = landmarks[i][1];
132 VectorXf v_bar = VectorXf::Ones(4 * num_landmarks);
133 for (
int i = 0; i < num_landmarks; ++i)
135 v_bar(4 * i) = base_face(vertex_ids[i] * 3);
136 v_bar((4 * i) + 1) = base_face(vertex_ids[i] * 3 + 1);
137 v_bar((4 * i) + 2) = base_face(vertex_ids[i] * 3 + 2);
142 const MatrixXf A = P * V_hat_h;
143 const MatrixXf b = P * v_bar - y;
144 const MatrixXf AtOmegaAReg = A.transpose() * Omega.asDiagonal() * A +
145 lambda * Eigen::MatrixXf::Identity(num_coeffs_to_fit, num_coeffs_to_fit);
146 const MatrixXf rhs = -A.transpose() * Omega.asDiagonal() * b;
154 const VectorXf c_s = AtOmegaAReg.colPivHouseholderQr().solve(rhs);
156 return std::vector<float>(c_s.data(), c_s.data() + c_s.size());
177inline std::vector<float>
179 const std::vector<Eigen::Matrix<float, 3, 4>>& affine_camera_matrices,
180 const std::vector<std::vector<Eigen::Vector2f>>& landmarks,
181 const std::vector<std::vector<int>>& vertex_ids,
182 std::vector<Eigen::VectorXf> base_faces = std::vector<Eigen::VectorXf>(),
184 cpp17::optional<int> num_coefficients_to_fit = cpp17::optional<int>(),
185 cpp17::optional<float> detector_standard_deviation = cpp17::optional<float>(),
186 cpp17::optional<float> model_standard_deviation = cpp17::optional<float>())
188 assert(affine_camera_matrices.size() == landmarks.size() &&
189 landmarks.size() == vertex_ids.size());
190 const int num_images =
static_cast<int>(affine_camera_matrices.size());
191 for (
int j = 0; j < num_images; ++j) {
192 assert(landmarks[j].size() == vertex_ids[j].size());
195 using Eigen::VectorXf;
196 using Eigen::MatrixXf;
201 lambda *= num_images;
203 std::size_t total_num_landmarks_dimension = 0;
204 for (
const auto& l : landmarks) {
205 total_num_landmarks_dimension += l.size();
210 MatrixXf V_hat_h = MatrixXf::Zero(4 * total_num_landmarks_dimension, num_coeffs_to_fit);
211 int V_hat_h_row_index = 0;
213 Eigen::SparseMatrix<float> P(3 * total_num_landmarks_dimension, 4 * total_num_landmarks_dimension);
214 std::vector<Eigen::Triplet<float>> P_coefficients;
221 const float sigma_squared_2D = std::pow(detector_standard_deviation.value_or(std::sqrt(3.0f)), 2) +
222 std::pow(model_standard_deviation.value_or(0.0f), 2);
224 const VectorXf Omega = VectorXf::Constant(3 * total_num_landmarks_dimension, 1.0f / sigma_squared_2D);
226 VectorXf y = VectorXf::Ones(3 * total_num_landmarks_dimension);
229 VectorXf v_bar = VectorXf::Ones(4 * total_num_landmarks_dimension);
233 for (
int k = 0; k < num_images; ++k)
236 assert(landmarks[k].size() == vertex_ids[k].size());
238 const int num_landmarks =
static_cast<int>(landmarks[k].size());
240 if (base_faces[k].size() == 0)
242 base_faces[k] = shape_model.
get_mean();
248 for (
int i = 0; i < num_landmarks; ++i)
253 V_hat_h.block(V_hat_h_row_index, 0, 3, V_hat_h.cols()) =
254 basis_rows_.block(0, 0, basis_rows_.rows(), num_coeffs_to_fit);
255 V_hat_h_row_index += 4;
259 for (
int i = 0; i < num_landmarks; ++i) {
260 for (
int x = 0; x < affine_camera_matrices[k].rows(); ++x) {
261 for (
int y = 0; y < affine_camera_matrices[k].cols(); ++y) {
262 P_coefficients.push_back(Eigen::Triplet<float>(3 * P_index + x, 4 * P_index + y,
263 affine_camera_matrices[k](x, y)));
269 P.setFromTriplets(P_coefficients.begin(), P_coefficients.end());
273 for (
int i = 0; i < num_landmarks; ++i) {
274 y(3 * y_index) = landmarks[k][i][0];
275 y((3 * y_index) + 1) = landmarks[k][i][1];
281 for (
int i = 0; i < num_landmarks; ++i) {
282 v_bar(4 * v_bar_index) = base_faces[k](vertex_ids[k][i] * 3);
283 v_bar((4 * v_bar_index) + 1) = base_faces[k](vertex_ids[k][i] * 3 + 1);
284 v_bar((4 * v_bar_index) + 2) = base_faces[k](vertex_ids[k][i] * 3 + 2);
291 const MatrixXf A = P * V_hat_h;
292 const MatrixXf b = P * v_bar - y;
293 const MatrixXf AtOmegaAReg = A.transpose() * Omega.asDiagonal() * A +
294 lambda * Eigen::MatrixXf::Identity(num_coeffs_to_fit, num_coeffs_to_fit);
295 const MatrixXf rhs = -A.transpose() * Omega.asDiagonal() * b;
299 const VectorXf c_s = AtOmegaAReg.colPivHouseholderQr().solve(rhs);
301 return std::vector<float>(c_s.data(), c_s.data() + c_s.size());
This class represents a PCA-model that consists of:
Definition: PcaModel.hpp:59
int get_num_principal_components() const
Definition: PcaModel.hpp:88
Eigen::MatrixXf get_rescaled_pca_basis_at_point(int vertex_id) const
Definition: PcaModel.hpp:223
const Eigen::VectorXf & get_mean() const
Definition: PcaModel.hpp:123
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
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
Namespace containing all of eos's 3D model fitting functionality.