return{current_mesh,rendering_params};// I think we could also work with a Mat face_instance in this function instead of a Mesh, but it would convolute the code more (i.e. more complicated to access vertices).
return{current_meshs,rendering_params};// I think we could also work with a Mat face_instance in this function instead of a Mesh, but it would convolute the code more (i.e. more complicated to access vertices).
};
/**
* @brief Fit the pose (camera), shape model, and expression blendshapes to landmarks,
* in an iterative way. Can fit to more than one set of landmarks, thus multiple images.
*
* Convenience function that fits pose (camera), the shape model, and expression blendshapes
* to landmarks, in an iterative (alternating) way. It fits both sides of the face contour as well.
*
* If you want to access the values of shape or blendshape coefficients, or want to set starting
* values for them, use the following overload to this function:
* \p num_iterations: Results are good for even a single iteration. For single-image fitting and
* for full convergence of all parameters, it can take up to 300 iterations. In tracking,
* particularly if initialising with the previous frame, it works well with as low as 1 to 5
* iterations.
* \p edge_topology is used for the occluding-edge face contour fitting.
* \p contour_landmarks and \p model_contour are used to fit the front-facing contour.
*
* @param[in] morphable_model The 3D Morphable Model used for the shape fitting.
* @param[in] blendshapes A vector of blendshapes that are being fit to the landmarks in addition to the PCA model.
* @param[in] landmarks 2D landmarks from an image to fit the model to.
* @param[in] landmark_mapper Mapping info from the 2D landmark points to 3D vertex indices.
* @param[in] image_width Width of the input image (needed for the camera model).
* @param[in] image_height Height of the input image (needed for the camera model).
* @param[in] edge_topology Precomputed edge topology of the 3D model, needed for fast edge-lookup.
* @param[in] contour_landmarks 2D image contour ids of left or right side (for example for ibug landmarks).
* @param[in] model_contour The model contour indices that should be considered to find the closest corresponding 3D vertex.
* @param[in] num_iterations Number of iterations that the different fitting parts will be alternated for.
* @param[in] num_shape_coefficients_to_fit How many shape-coefficients to fit (all others will stay 0). Should be bigger than zero, or boost::none to fit all coefficients.
* @param[in] lambda Regularisation parameter of the PCA shape fitting.
* @return The fitted model shape instance and the final pose.
* for a simpler overload with reasonable defaults and no optional output.
*
* \p num_iterations: Results are good for even a single iteration. For single-image fitting and
* for full convergence of all parameters, it can take up to 300 iterations. In tracking,
* particularly if initialising with the previous frame, it works well with as low as 1 to 5
* iterations.
* \p edge_topology is used for the occluding-edge face contour fitting.
* \p contour_landmarks and \p model_contour are used to fit the front-facing contour.
*
* Todo: Add a convergence criterion.
*
* @param[in] morphable_model The 3D Morphable Model used for the shape fitting.
* @param[in] blendshapes A vector of blendshapes that are being fit to the landmarks in addition to the PCA model.
* @param[in] landmarks 2D landmarks from an image to fit the model to.
* @param[in] landmark_mapper Mapping info from the 2D landmark points to 3D vertex indices.
* @param[in] image_width Width of the input image (needed for the camera model).
* @param[in] image_height Height of the input image (needed for the camera model).
* @param[in] edge_topology Precomputed edge topology of the 3D model, needed for fast edge-lookup.
* @param[in] contour_landmarks 2D image contour ids of left or right side (for example for ibug landmarks).
* @param[in] model_contour The model contour indices that should be considered to find the closest corresponding 3D vertex.
* @param[in] num_iterations Number of iterations that the different fitting parts will be alternated for.
* @param[in] num_shape_coefficients_to_fit How many shape-coefficients to fit (all others will stay 0). Should be bigger than zero, or boost::none to fit all coefficients.
* @param[in] lambda Regularisation parameter of the PCA shape fitting.
* @param[in] initial_rendering_params Currently ignored (not used).
* @param[in,out] pca_shape_coefficients If given, will be used as initial PCA shape coefficients to start the fitting. Will contain the final estimated coefficients.
* @param[in,out] blendshape_coefficients If given, will be used as initial expression blendshape coefficients to start the fitting. Will contain the final estimated coefficients.
* @param[out] fitted_image_points Debug parameter: Returns all the 2D points that have been used for the fitting.
* @return The fitted model shape instance and the final pose.
//we have to create a new vector here if the blendshape_coefficients are empty, as otherwise the new vector is not empty anymore and contains one element
* @param[in] landmarks 2D landmarks from an image to fit the model to.
* @param[in] vertex_ids The vertex ids in the model that correspond to the 2D points.
* @param[in] base_face The base or reference face from where the fitting is started. Usually this would be the models mean face, which is what will be used if the parameter is not explicitly specified.
* @param[in] lambda The regularisation parameter (weight of the prior towards the mean).
* @param[in] lambda The regularisation parameter (weight of the prior towards the mean). Gets normalized by the number of images given.
* @param[in] num_coefficients_to_fit How many shape-coefficients to fit (all others will stay 0). Should be bigger than zero, or boost::none to fit all coefficients.
* @param[in] detector_standard_deviation The standard deviation of the 2D landmarks given (e.g. of the detector used), in pixels.
* @param[in] model_standard_deviation The standard deviation of the 3D vertex points in the 3D model, projected to 2D (so the value is in pixels).
* @return The estimated shape-coefficients (alphas).
assert(affine_camera_matrix.size()==landmarks.size()&&landmarks.size()==vertex_ids.size());// same number of instances (i.e. images/frames) for each of them
MatrixXfbasis_rows_=morphable_model.get_shape_model().get_rescaled_pca_basis_at_point(vertex_ids[i]);// In the paper, the orthonormal basis might be used? I'm not sure, check it. It's even a mess in the paper. PH 26.5.2014: I think the rescaled basis is fine/better.
// Earlier, we set Sigma in a for-loop and then computed Omega, but it was really unnecessary:
// Sigma(i, i) = sqrt(sigma_squared_2D), but then Omega is Sigma.t() * Sigma (squares the diagonal) - so we just assign 1/sigma_squared_2D to Omega here.
MatrixXfbasis_rows_=morphable_model.get_shape_model().get_rescaled_pca_basis_at_point(vertex_ids[k][i]);// In the paper, the orthonormal basis might be used? I'm not sure, check it. It's even a mess in the paper. PH 26.5.2014: I think the rescaled basis is fine/better.
* Fits the shape of a Morphable Model to given 2D landmarks (i.e. estimates the maximum likelihood solution of the shape coefficients) as proposed in [1].
* It's a linear, closed-form solution fitting of the shape, with regularisation (prior towards the mean).
*
* [1] O. Aldrian & W. Smith, Inverse Rendering of Faces with a 3D Morphable Model, PAMI 2013.
*
* Note: Using less than the maximum number of coefficients to fit is not thoroughly tested yet and may contain an error.
* Note: Returns coefficients following standard normal distribution (i.e. all have similar magnitude). Why? Because we fit using the normalised basis?
* Note: The standard deviations given should be a vector, i.e. different for each landmark. This is not implemented yet.
*
* @param[in] morphable_model The Morphable Model whose shape (coefficients) are estimated.
* @param[in] affine_camera_matrix A 3x4 affine camera matrix from model to screen-space (should probably be of type CV_32FC1 as all our calculations are done with float).
* @param[in] landmarks 2D landmarks from an image to fit the model to.
* @param[in] vertex_ids The vertex ids in the model that correspond to the 2D points.
* @param[in] base_face The base or reference face from where the fitting is started. Usually this would be the models mean face, which is what will be used if the parameter is not explicitly specified.
* @param[in] lambda The regularisation parameter (weight of the prior towards the mean).
* @param[in] num_coefficients_to_fit How many shape-coefficients to fit (all others will stay 0). Should be bigger than zero, or boost::none to fit all coefficients.
* @param[in] detector_standard_deviation The standard deviation of the 2D landmarks given (e.g. of the detector used), in pixels.
* @param[in] model_standard_deviation The standard deviation of the 3D vertex points in the 3D model, projected to 2D (so the value is in pixels).
* @return The estimated shape-coefficients (alphas).
assert(affine_camera_matrix.size()==landmarks.size()&&landmarks.size()==vertex_ids.size());// same number of instances (i.e. images/frames) for each of them
Matbasis_rows=morphable_model.get_shape_model().get_normalised_pca_basis(vertex_ids[k][i]);// In the paper, the not-normalised basis might be used? I'm not sure, check it. It's even a mess in the paper. PH 26.5.2014: I think the normalised basis is fine/better.
Sigma.at<float>(Sigma_index,Sigma_index)=1.0f/std::sqrt(sigma_squared_2D);// the higher the sigma_squared_2D, the smaller the diagonal entries of Sigma will be
++Sigma_index;
}
//Mat Omega = Sigma.t() * Sigma; // just squares the diagonal
// => moved outside the loop
// The landmarks in matrix notation (in homogeneous coordinates), $3N\times 1$
//Mat y = Mat::ones(3 * num_landmarks, 1, CV_32FC1);
Eigen::FullPivLU<RowMajorMatrixXf> luOfAtOmegaAReg(AtOmegaAReg_Eigen); // Calculate the full-pivoting LU decomposition of the regularized AtA. Note: We could also try FullPivHouseholderQR if our system is non-minimal (i.e. there are more constraints than unknowns).
float threshold = std::abs(luOfAtOmegaAReg.maxPivot()) * luOfAtOmegaAReg.threshold(); // originaly "2 * ..." but I commented it out
RowMajorMatrixXf AtARegInv_EigenFullLU = luOfAtOmegaAReg.inverse(); // Note: We should use ::solve() instead
Mat AtOmegaARegInvFullLU(AtARegInv_EigenFullLU.rows(), AtARegInv_EigenFullLU.cols(), CV_32FC1, AtARegInv_EigenFullLU.data()); // create an OpenCV Mat header for the Eigen data
*/
// Solve using OpenCV:
Matc_s;// Note/Todo: We get coefficients ~ N(0, sigma) I think. They are not multiplied with the eigenvalues.
boolnon_singular=cv::solve(AtOmegaAReg,-A.t()*Omega.t()*b,c_s,cv::DECOMP_SVD);// DECOMP_SVD calculates the pseudo-inverse if the matrix is not invertible.
// Because we're using SVD, non_singular will always be true. If we were to use e.g. Cholesky, we could return an expected<T>.
/* using RowMajorMatrixXf = Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
// asserts... copy from fit_shape_to_landmarks_linear_multi?
intnum_images=affine_camera_matrix.size();
Matblendshapes_as_basis(blendshapes[0].deformation.rows,blendshapes.size(),CV_32FC1);// assert blendshapes.size() > 0 and all of them have same number of rows, and 1 col
// Multi: actually, the expression fitting we keep like that: Use the current global shape and estimate expression BS for each frame separately. There's no use in doing that jointly for all frames.
for(intimg=0;img<num_images;++img){// just for debug purposes here.
combined_shape[img]=pca_model_shape+blendshapes_as_basis*Mat(current_blendshape_coeffs[img]);// Note/Todo: There's actually no need to do this in the loop here? We can just do it once, at the end?
py::modulemorphablemodel_module=eos_module.def_submodule("morphablemodel","Functionality to represent a Morphable Model, its PCA models, and functions to load models and blendshapes.");
...
...
@@ -107,10 +107,13 @@ PYBIND11_PLUGIN(eos) {
.def("get_mean",&morphablemodel::MorphableModel::get_mean,"Returns the mean of the shape- and colour model as a Mesh.")
.def("draw_sample",(core::Mesh(morphablemodel::MorphableModel::*)(std::vector<float>,std::vector<float>)const)&morphablemodel::MorphableModel::draw_sample,"Returns a sample from the model with the given shape- and colour PCA coefficients.",py::arg("shape_coefficients"),py::arg("color_coefficients"))
.def("has_color_model",&morphablemodel::MorphableModel::has_color_model,"Returns true if this Morphable Model contains a colour model, and false if it is a shape-only model.")
.def("get_texture_coordinates",&morphablemodel::MorphableModel::get_texture_coordinates,"Returns the texture coordinates for all the vertices in the model.")
;
morphablemodel_module.def("load_model",&morphablemodel::load_model,"Load a Morphable Model from a cereal::BinaryInputArchive (.bin) from the harddisk.",py::arg("filename"));
morphablemodel_module.def("save_model",&morphablemodel::save_model,"Save a Morphable Model as cereal::BinaryOutputArchive.",py::arg("model"),py::arg("filename"));
morphablemodel_module.def("load_pca_model",&morphablemodel::load_pca_model,"Load a PCA model from a cereal::BinaryInputArchive (.bin) from the harddisk.",py::arg("filename"));
morphablemodel_module.def("save_pca_model",&morphablemodel::save_pca_model,"Save a PCA model as cereal::BinaryOutputArchive.",py::arg("model"),py::arg("filename"));