Commit 857a5de8 authored by patrikhuber's avatar patrikhuber

Changed detector standard deviation calculations to follow the original paper

- We now use the same values and formulas as in Smith & Aldrian for the detector 2D variance.
- This changes the ranges of values a bit, so set an equivalent reasonable regularisation default value
parent 806a7444
......@@ -201,8 +201,7 @@ int main(int argc, char *argv[])
}
// Estimate the shape coefficients by fitting the shape to the landmarks:
float lambda = 1e4f; // the regularisation parameter
vector<float> fitted_coeffs = fitting::fit_shape_to_landmarks_linear(morphable_model, affine_cam, image_points, vertex_indices, lambda);
vector<float> fitted_coeffs = fitting::fit_shape_to_landmarks_linear(morphable_model, affine_cam, image_points, vertex_indices);
// Obtain the full mesh and draw it using the estimated camera:
render::Mesh mesh = morphable_model.draw_sample(fitted_coeffs, vector<float>());
......
......@@ -31,6 +31,7 @@
#include "boost/optional.hpp"
#include <vector>
#include <cmath>
#include <cassert>
namespace eos {
......@@ -52,11 +53,11 @@ namespace eos {
* @param[in] vertex_ids The vertex ids in the model that correspond to the 2D points.
* @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). Not tested thoroughly.
* @param[in] detector_standard_deviation The standard deviation of the 2D landmarks given (e.g. of the detector used).
* @param[in] model_standard_deviation The standard deviation of the 3D vertex points in the 3D model.
* @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).
*/
inline std::vector<float> fit_shape_to_landmarks_linear(morphablemodel::MorphableModel morphable_model, cv::Mat affine_camera_matrix, std::vector<cv::Vec2f> landmarks, std::vector<int> vertex_ids, float lambda=20.0f, boost::optional<int> num_coefficients_to_fit=boost::optional<int>(), boost::optional<float> detector_standard_deviation=boost::optional<float>(), boost::optional<float> model_standard_deviation=boost::optional<float>())
inline std::vector<float> fit_shape_to_landmarks_linear(morphablemodel::MorphableModel morphable_model, cv::Mat affine_camera_matrix, std::vector<cv::Vec2f> landmarks, std::vector<int> vertex_ids, float lambda=3.0f, boost::optional<int> num_coefficients_to_fit=boost::optional<int>(), boost::optional<float> detector_standard_deviation=boost::optional<float>(), boost::optional<float> model_standard_deviation=boost::optional<float>())
{
using cv::Mat;
assert(landmarks.size() == vertex_ids.size());
......@@ -82,13 +83,13 @@ inline std::vector<float> fit_shape_to_landmarks_linear(morphablemodel::Morphabl
}
// The variances: Add the 2D and 3D standard deviations.
// If the user doesn't provide them, we choose the following:
// 2D (detector) variance: Assuming the detector has a standard deviation of 3 pixels, and the face size (IED) is around 80px. That's 3.75% of the IED. Note: Maybe this should even be in pixel, so 4 instead of 0.04.
// 2D (detector) standard deviation: In pixel, we follow [1] and choose sqrt(3) as the default value.
// 3D (model) variance: 0.0f. It only makes sense to set it to something when we have a different variance for different vertices.
float sigma_2D_3D = detector_standard_deviation.get_value_or(0.04f) + model_standard_deviation.get_value_or(0.0f);
// Note: Isn't it a bit strange to add these as they have different units/normalisations? Check the paper.
// The 3D variance has to be projected to 2D (for details, see paper [1]) so the units do match up.
float sigma_squared_2D = std::pow(detector_standard_deviation.get_value_or(std::sqrt(3.0f)), 2) + std::pow(model_standard_deviation.get_value_or(0.0f), 2);
Mat Sigma = Mat::zeros(3 * num_landmarks, 3 * num_landmarks, CV_32FC1);
for (int i = 0; i < 3 * num_landmarks; ++i) {
Sigma.at<float>(i, i) = 1.0f / sigma_2D_3D; // the higher the sigma_2D_3D, the smaller the diagonal entries of Sigma will be
Sigma.at<float>(i, i) = 1.0f / std::sqrt(sigma_squared_2D); // the higher the sigma_squared_2D, the smaller the diagonal entries of Sigma will be
}
Mat Omega = Sigma.t() * Sigma; // just squares the diagonal
// The landmarks in matrix notation (in homogeneous coordinates), $3N\times 1$
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment