22#ifndef BLENDSHAPEFITTING_HPP_
23#define BLENDSHAPEFITTING_HPP_
25#include "eos/morphablemodel/Blendshape.hpp"
29#include "Eigen/Sparse"
59 const std::vector<morphablemodel::Blendshape>& blendshapes,
const Eigen::VectorXf& face_instance,
60 Eigen::Matrix<float, 3, 4> affine_camera_matrix,
const std::vector<Eigen::Vector2f>& landmarks,
61 const std::vector<int>& vertex_ids,
float lambda = 500.0f)
63 assert(landmarks.size() == vertex_ids.size());
65 using Eigen::MatrixXf;
66 using Eigen::VectorXf;
68 const auto num_blendshapes = blendshapes.size();
69 const int num_landmarks =
static_cast<int>(landmarks.size());
76 MatrixXf V_hat_h = MatrixXf::Zero(4 * num_landmarks, num_blendshapes);
78 for (
int i = 0; i < num_landmarks; ++i)
80 V_hat_h.block(row_index, 0, 3, V_hat_h.cols()) =
81 blendshapes_as_basis.block(vertex_ids[i] * 3, 0, 3, blendshapes_as_basis.cols());
85 MatrixXf P = MatrixXf::Zero(3 * num_landmarks, 4 * num_landmarks);
86 for (
int i = 0; i < num_landmarks; ++i)
88 P.block<3, 4>(3 * i, 4 * i) = affine_camera_matrix;
92 VectorXf y = VectorXf::Ones(3 * num_landmarks);
93 for (
int i = 0; i < num_landmarks; ++i)
95 y(3 * i) = landmarks[i][0];
96 y((3 * i) + 1) = landmarks[i][1];
100 VectorXf v_bar = VectorXf::Ones(4 * num_landmarks);
101 for (
int i = 0; i < num_landmarks; ++i)
103 v_bar(4 * i) = face_instance(vertex_ids[i] * 3);
104 v_bar((4 * i) + 1) = face_instance(vertex_ids[i] * 3 + 1);
105 v_bar((4 * i) + 2) = face_instance(vertex_ids[i] * 3 + 2);
110 const MatrixXf A = P * V_hat_h;
111 const MatrixXf b = P * v_bar - y;
113 const MatrixXf AtAReg =
114 A.transpose() * A + lambda * Eigen::MatrixXf::Identity(num_blendshapes, num_blendshapes);
115 const MatrixXf rhs = -A.transpose() * b;
117 const VectorXf coefficients = AtAReg.colPivHouseholderQr().solve(rhs);
119 return std::vector<float>(coefficients.data(), coefficients.data() + coefficients.size());
139 const std::vector<morphablemodel::Blendshape>& blendshapes,
const Eigen::VectorXf& face_instance,
140 Eigen::Matrix<float, 3, 4> affine_camera_matrix,
const std::vector<Eigen::Vector2f>& landmarks,
141 const std::vector<int>& vertex_ids)
143 assert(landmarks.size() == vertex_ids.size());
145 using Eigen::MatrixXf;
146 using Eigen::VectorXf;
148 const auto num_blendshapes = blendshapes.size();
149 const int num_landmarks =
static_cast<int>(landmarks.size());
156 MatrixXf V_hat_h = MatrixXf::Zero(4 * num_landmarks, num_blendshapes);
158 for (
int i = 0; i < num_landmarks; ++i)
160 V_hat_h.block(row_index, 0, 3, V_hat_h.cols()) =
161 blendshapes_as_basis.block(vertex_ids[i] * 3, 0, 3, blendshapes_as_basis.cols());
166 Eigen::SparseMatrix<float> P(3 * num_landmarks, 4 * num_landmarks);
167 std::vector<Eigen::Triplet<float>> P_coefficients;
168 for (
int i = 0; i < num_landmarks; ++i)
170 for (
int x = 0; x < affine_camera_matrix.rows(); ++x)
172 for (
int y = 0; y < affine_camera_matrix.cols(); ++y)
174 P_coefficients.push_back(
175 Eigen::Triplet<float>(3 * i + x, 4 * i + y, affine_camera_matrix(x, y)));
179 P.setFromTriplets(P_coefficients.begin(), P_coefficients.end());
182 VectorXf y = VectorXf::Ones(3 * num_landmarks);
183 for (
int i = 0; i < num_landmarks; ++i)
185 y(3 * i) = landmarks[i][0];
186 y((3 * i) + 1) = landmarks[i][1];
191 VectorXf v_bar = VectorXf::Ones(4 * num_landmarks);
192 for (
int i = 0; i < num_landmarks; ++i)
194 v_bar(4 * i) = face_instance(vertex_ids[i] * 3);
195 v_bar((4 * i) + 1) = face_instance(vertex_ids[i] * 3 + 1);
196 v_bar((4 * i) + 2) = face_instance(vertex_ids[i] * 3 + 2);
201 const MatrixXf A = P * V_hat_h;
202 const MatrixXf b = P * v_bar - y;
205 VectorXf coefficients;
206 Eigen::NNLS<MatrixXf> nnls(A, 100);
207 bool non_singular = nnls.solve(-b);
208 coefficients.noalias() = nnls.x();
210 return std::vector<float>(coefficients.data(), coefficients.data() + coefficients.size());
std::vector< float > fit_blendshapes_to_landmarks_linear(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, float lambda=500.0f)
Definition: blendshape_fitting.hpp:58
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
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
Namespace containing all of eos's 3D model fitting functionality.