Skip to content

Commit

Permalink
Added project(...) function to PcaModel
Browse files Browse the repository at this point in the history
This is to project a given data instance (e.g. a given shape instance) onto the PCA space, to get the resulting PCA coefficients.
Also added Python bindings for it.

There is one peculiarity that we seem to need to divide the resulting coefficients with their corresponding eigenvalues. I think that this shouldn't be needed, as we project using the rescaled PCA basis. This will need some further checking.
  • Loading branch information
patrikhuber committed Dec 22, 2019
1 parent f1f83d0 commit 4694d6f
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 1 deletion.
25 changes: 25 additions & 0 deletions include/eos/morphablemodel/PcaModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,31 @@ class PcaModel
return eigenvalues(index);
};

/**
* Projects the given data instance into the model space, and returns the PCA coefficients.
*
* @param[in] instance A 3m x 1 col-vector (xyzxyz...)', where m is the number of model-vertices.
* @return The PCA coefficients of the projected data.
*/
std::vector<float> project(const Eigen::VectorXf& instance) const
{
// We are not transposing the basis - it's 3*num_vtx x num_components, which is correct for the
// projection.
// instance and mean are col-vectors, we transpose that to be a row-vector.
Eigen::VectorXf coeffs = (instance - mean).transpose() * rescaled_pca_basis;

// In the simple example below:
// sample = m.get_shape_model().draw_sample([0.5, -0.5, 0, 1, -1])
// c = m.get_shape_model().project(sample)
// we seem to need to divide the resulting coeffs by the eigenvalues, to make
// the output correct (i.e. the same as the input). I am not sure why. We should
// go through it on paper again. At the same time we can check github.com/patrikhuber/eos/issues/257.
coeffs = coeffs.array() / eigenvalues.array();

std::vector<float> coefficients(coeffs.data(), coeffs.data() + coeffs.size());
return coefficients;
};

private:
Eigen::VectorXf mean; ///< A 3m x 1 col-vector (xyzxyz...)', where m is the number of model-vertices.
Eigen::MatrixXf orthonormal_pca_basis; ///< m x n (rows x cols) = numShapeDims x numShapePcaCoeffs,
Expand Down
3 changes: 2 additions & 1 deletion python/generate-python-bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,8 @@ PYBIND11_MODULE(eos, eos_module)
.def("get_orthonormal_pca_basis", &morphablemodel::PcaModel::get_orthonormal_pca_basis, "Returns the orthonormal PCA basis matrix, i.e. the eigenvectors. Each column of the matrix is an eigenvector.")
.def("get_rescaled_pca_basis", &morphablemodel::PcaModel::get_rescaled_pca_basis, "Returns the rescaled PCA basis matrix, i.e. the eigenvectors. Each column of the matrix is an eigenvector, and each eigenvector has been rescaled by multiplying it with the square root of its eigenvalue.")
.def("get_eigenvalues", &morphablemodel::PcaModel::get_eigenvalues, "Returns the models eigenvalues.")
.def("draw_sample", (Eigen::VectorXf(morphablemodel::PcaModel::*)(std::vector<float>)const)&morphablemodel::PcaModel::draw_sample, "Returns a sample from the model with the given PCA coefficients. The given coefficients should follow a standard normal distribution, i.e. not be scaled with their eigenvalues/variances.", py::arg("coefficients"));
.def("draw_sample", (Eigen::VectorXf(morphablemodel::PcaModel::*)(std::vector<float>)const)&morphablemodel::PcaModel::draw_sample, "Returns a sample from the model with the given PCA coefficients. The given coefficients should follow a standard normal distribution, i.e. not be scaled with their eigenvalues/variances.", py::arg("coefficients"))
.def("project", &morphablemodel::PcaModel::project, "Projects the given data instance into the model space, and returns the PCA coefficients.", py::arg("instance"));

py::class_<morphablemodel::MorphableModel> morphable_model(morphablemodel_module, "MorphableModel", "A class representing a 3D Morphable Model, consisting of a shape- and colour (albedo) PCA model, as well as texture (uv) coordinates.");

Expand Down

0 comments on commit 4694d6f

Please sign in to comment.