in visualization/FitAdam/src/FitToBody.cpp [1501:1714]
void Adam_refit_batch(TotalModel &adam,
std::vector<smpl::SMPLParams*> &frame_param,
std::vector<Eigen::MatrixXd> &BodyJoints,
std::vector<Eigen::MatrixXd> &rFoot,
std::vector<Eigen::MatrixXd> &lFoot,
std::vector<Eigen::MatrixXd> &rHandJoints,
std::vector<Eigen::MatrixXd> &lHandJoints,
std::vector<Eigen::MatrixXd> &faceJoints,
std::vector<Eigen::MatrixXd> &PAF,
uint regressor_type,
bool bFreezeShape,
bool euler,
bool bDCT)
{
const uint num_t = frame_param.size();
Eigen::MatrixXd surface_constraint(6, 0);
ceres::Problem problem;
ceres::Solver::Options options;
ceres::Solver::Summary summary;
auto& common_adam_coeffs = frame_param[0]->m_adam_coeffs;
std::vector<AdamFitData> data;
std::vector<AdamFullCost*> adam_cost;
data.reserve(num_t); // The capacity must be remained. Otherwise previous reference (in AdamFullCost) will be invalidated.
for (uint t = 0u; t < num_t; t++)
{
data.emplace_back(adam, BodyJoints[t], rFoot[t], lFoot[t], faceJoints[t], lHandJoints[t], rHandJoints[t], PAF[t], surface_constraint, true);
adam_cost.emplace_back(new AdamFullCost(data.back(), regressor_type, false, euler));
problem.AddResidualBlock(adam_cost.back(),
NULL,
frame_param[t]->m_adam_t.data(),
frame_param[t]->m_adam_pose.data(),
common_adam_coeffs.data());
}
SetSolverOptions(&options);
options.function_tolerance = 1e-4;
options.max_num_iterations = 30;
options.use_nonmonotonic_steps = false;
options.num_linear_solver_threads = 1;
options.minimizer_progress_to_stdout = true;
//Body Prior (coef) //////////////////////////////////////////////////////////////////////////
CoeffsParameterNormDiff* cost_prior_body_coeffs = new CoeffsParameterNormDiff(TotalModel::NUM_SHAPE_COEFFICIENTS);
ceres::LossFunction* loss_weight_prior_body_coeffs = new ceres::ScaledLoss(NULL,
1e-4 * num_t,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(cost_prior_body_coeffs,
loss_weight_prior_body_coeffs,
common_adam_coeffs.data());
//Body Prior (pose) //////////////////////////////////////////////////////////////////////////
if (euler)
{
for (uint t = 0u; t < num_t; t++)
{
ceres::CostFunction *cost_prior_body_pose = new ceres::AutoDiffCostFunction
<AdamBodyPoseParamPrior,
TotalModel::NUM_POSE_PARAMETERS,
TotalModel::NUM_POSE_PARAMETERS>(new AdamBodyPoseParamPrior(TotalModel::NUM_POSE_PARAMETERS));
ceres::LossFunction* loss_weight_prior_body_pose = new ceres::ScaledLoss(NULL,
1e-2,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(cost_prior_body_pose,
loss_weight_prior_body_pose,
frame_param[t]->m_adam_pose.data());
}
}
else
{
Eigen::Matrix<double, 72, TotalModel::NUM_POSE_PARAMETERS> prior_A; prior_A.setZero();
prior_A.block<72, 66>(0, 0) = adam.smpl_pose_prior_A.block<72, 66>(0, 0); // for body, use the prior from SMPL
Eigen::Matrix<double, TotalModel::NUM_POSE_PARAMETERS, 1> prior_mu; prior_mu.setZero();
prior_mu.block<66, 1>(0, 0) = -adam.smpl_pose_prior_mu.block<66, 1>(0, 0); // use the prior from SMPL
Eigen::MatrixXd hand_prior_A(120, TotalModel::NUM_POSE_PARAMETERS); hand_prior_A.setZero();
Eigen::Matrix<double, TotalModel::NUM_POSE_PARAMETERS, 1> hand_prior_mu; hand_prior_mu.setZero();
hand_prior_mu.block<60, 1>(66, 0) = -adam.hand_pose_prior_mu; hand_prior_mu.block<60, 1>(126, 0) = adam.hand_pose_prior_mu;
for (int i = 66; i < 126; i += 3) hand_prior_mu(i, 0) = -hand_prior_mu(i, 0);
hand_prior_A.block<60, 60>(0, 66) = -adam.hand_pose_prior_A; hand_prior_A.block<60, 60>(60, 126) = adam.hand_pose_prior_A;
for (int i = 66; i < 126; i += 3) hand_prior_A.col(i) = -hand_prior_A.col(i);
for (uint t = 0u; t < num_t; t++)
{
ceres::CostFunction *pose_reg = new ceres::NormalPrior(prior_A, prior_mu);
ceres::LossFunction* pose_reg_loss = new ceres::ScaledLoss(NULL,
1,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(pose_reg,
pose_reg_loss,
frame_param[t]->m_adam_pose.data());
ceres::CostFunction *hand_pose_reg = new ceres::NormalPrior(hand_prior_A, hand_prior_mu);
ceres::LossFunction *hand_pose_reg_loss = new ceres::ScaledLoss(NULL,
0.1,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(hand_pose_reg,
hand_pose_reg_loss,
frame_param[t]->m_adam_pose.data());
}
}
// DCT smoothing loss
std::vector<double*> pose_blocks;
for (uint t = 0u; t < num_t; t++) pose_blocks.emplace_back(frame_param[t]->m_adam_pose.data());
std::vector<double*> trans_blocks;
for (uint t = 0u; t < num_t; t++) trans_blocks.emplace_back(frame_param[t]->m_adam_t.data());
const uint low_comp = ceil(0.125 * num_t); // should not be 0
const uint low_comp_hand = ceil(0.125 * num_t);
if (bDCT)
{
DCTCost* smooth_cost_pose = new DCTCost(num_t, low_comp, TotalModel::NUM_POSE_PARAMETERS, 0, 60, 500); // DCT for body only
problem.AddResidualBlock(smooth_cost_pose, nullptr, pose_blocks);
DCTCost* smooth_cost_wrist = new DCTCost(num_t, low_comp, TotalModel::NUM_POSE_PARAMETERS, 60, 66, 100); // DCT for wrist only
problem.AddResidualBlock(smooth_cost_wrist, nullptr, pose_blocks);
DCTCost* smooth_cost_pose_hand = new DCTCost(num_t, low_comp_hand, TotalModel::NUM_POSE_PARAMETERS, 66, 186, 10); // DCT for fingers only
problem.AddResidualBlock(smooth_cost_pose_hand, nullptr, pose_blocks);
DCTCost* smooth_cost_trans = new DCTCost(num_t, low_comp, 3, 0, 3, 10);
problem.AddResidualBlock(smooth_cost_trans, nullptr, trans_blocks);
}
else
{
// smoothing on body is too strong, do not fit the fingers
/*
for (uint t = 0u; t < num_t; t++)
{
Eigen::MatrixXd ones = Eigen::MatrixXd::Zero(TotalModel::NUM_POSE_PARAMETERS - 60, TotalModel::NUM_POSE_PARAMETERS);
ones.block(0, 60, TotalModel::NUM_POSE_PARAMETERS - 60, TotalModel::NUM_POSE_PARAMETERS - 60).setIdentity();
Eigen::VectorXd b(TotalModel::NUM_POSE_PARAMETERS);
std::copy(frame_param[t]->m_adam_pose.data(), frame_param[t]->m_adam_pose.data() + TotalModel::NUM_POSE_PARAMETERS, b.data());
ceres::CostFunction* keep_hand_joint_angle = new ceres::NormalPrior(ones, b);
ceres::LossFunction* keep_hand_joint_angle_loss = new ceres::ScaledLoss(NULL,
100000,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(keep_hand_joint_angle, keep_hand_joint_angle_loss, frame_param[t]->m_adam_pose.data());
}
*/
TemporalSmoothCostDiff* smooth_cost_pose = new TemporalSmoothCostDiff(num_t, TotalModel::NUM_POSE_PARAMETERS, 0, 60);
ceres::LossFunction *smooth_cost_pose_loss = new ceres::ScaledLoss(NULL,
250000,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(smooth_cost_pose, smooth_cost_pose_loss, pose_blocks);
TemporalSmoothCostDiff* smooth_cost_pose_wrist = new TemporalSmoothCostDiff(num_t, TotalModel::NUM_POSE_PARAMETERS, 60, 66);
ceres::LossFunction *smooth_cost_pose_loss_wrist = new ceres::ScaledLoss(NULL,
10000,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(smooth_cost_pose_wrist, smooth_cost_pose_loss_wrist, pose_blocks);
TemporalSmoothCostDiff* smooth_cost_pose_hand = new TemporalSmoothCostDiff(num_t, TotalModel::NUM_POSE_PARAMETERS, 66, TotalModel::NUM_POSE_PARAMETERS);
ceres::LossFunction *smooth_cost_pose_loss_hand = new ceres::ScaledLoss(NULL,
100,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(smooth_cost_pose_hand, smooth_cost_pose_loss_hand, pose_blocks);
TemporalSmoothCostDiff* smooth_cost_trans = new TemporalSmoothCostDiff(num_t, 3, 0, 3);
ceres::LossFunction *smooth_cost_trans_loss = new ceres::ScaledLoss(NULL,
500,
ceres::TAKE_OWNERSHIP);
problem.AddResidualBlock(smooth_cost_trans, smooth_cost_trans_loss, trans_blocks);
}
for (uint t = 0; t < num_t; t++)
{
std::fill(adam_cost[t]->m_targetPts_weight.data() + 5 * adam_cost[t]->m_nCorrespond_adam2joints,
adam_cost[t]->m_targetPts_weight.data() + 5 * (adam_cost[t]->m_nCorrespond_adam2joints + 8), 1.0);
// adam_cost[t]->m_targetPts_weight[adam_cost[t]->m_nCorrespond_adam2joints + 0] =
// adam_cost[t]->m_targetPts_weight[adam_cost[t]->m_nCorrespond_adam2joints + 1] =
// adam_cost[t]->m_targetPts_weight[adam_cost[t]->m_nCorrespond_adam2joints + 2] =
// adam_cost[t]->m_targetPts_weight[adam_cost[t]->m_nCorrespond_adam2joints + 3] =
// adam_cost[t]->m_targetPts_weight[adam_cost[t]->m_nCorrespond_adam2joints + 4] =
// adam_cost[t]->m_targetPts_weight[adam_cost[t]->m_nCorrespond_adam2joints + 5] =
// adam_cost[t]->m_targetPts_weight[adam_cost[t]->m_nCorrespond_adam2joints + 6] =
// adam_cost[t]->m_targetPts_weight[adam_cost[t]->m_nCorrespond_adam2joints + 7] = 1.0; // foot vertices
}
if (bFreezeShape)
{
problem.SetParameterBlockConstant(common_adam_coeffs.data());
}
// for (uint t = 0; t < num_t; t++)
// {
// adam_cost[t]->toggle_activate(false, false, false);
// adam_cost[t]->toggle_rigid_body(true);
// }
// ceres::Solve(options, &problem, &summary);
// for (uint t = 0; t < num_t; t++)
// {
// adam_cost[t]->toggle_activate(true, false, false);
// adam_cost[t]->toggle_rigid_body(false);
// }
// ceres::Solve(options, &problem, &summary);
// std::cout << summary.FullReport() << std::endl;
for (uint t = 0; t < num_t; t++)
{
adam_cost[t]->toggle_activate(true, true, true);
if (!bDCT)
{
std::fill(adam_cost[t]->m_targetPts_weight.data() + 6 * 5, adam_cost[t]->m_targetPts_weight.data() + 7 * 5, 1.0);
std::fill(adam_cost[t]->m_targetPts_weight.data() + 11 * 5, adam_cost[t]->m_targetPts_weight.data() + 12 * 5, 1.0);
// adam_cost[t]->m_targetPts_weight[6] = adam_cost[t]->m_targetPts_weight[11] = 1;
}
}
ceres::Solve(options, &problem, &summary);
std::cout << summary.FullReport() << std::endl;
// duplicate the shape coeffs
for (uint t = 1; t < num_t; t++)
{
std::copy(common_adam_coeffs.data(), common_adam_coeffs.data() + TotalModel::NUM_SHAPE_COEFFICIENTS, frame_param[t]->m_adam_coeffs.data());
}
}