void Adam_refit_batch()

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());
	}
}