390 PointCloudSource& output,
const Eigen::Matrix4f& guess)
392 PointCloudSource intm_cloud = output;
397 if (guess != Eigen::Matrix4f::Identity()) {
398 transformation_ = guess;
407 Eigen::Matrix4f& transformation = transformation_;
411 const Eigen::Matrix3f initial_rot(transformation.block<3, 3>(0, 0));
412 const Eigen::Vector3f rot_x(initial_rot * Eigen::Vector3f::UnitX());
413 const double z_rotation = std::atan2(rot_x[1], rot_x[0]);
415 Eigen::Vector3d xytheta_transformation(
416 transformation(0, 3), transformation(1, 3), z_rotation);
418 while (!converged_) {
419 const double cos_theta = std::cos(xytheta_transformation[2]);
420 const double sin_theta = std::sin(xytheta_transformation[2]);
421 previous_transformation_ = transformation;
425 for (std::size_t i = 0; i < intm_cloud.size(); i++)
426 score += target_ndt.
test(intm_cloud[i], cos_theta, sin_theta);
428 PCL_DEBUG(
"[pcl::NormalDistributionsTransform2D::computeTransformation] NDT score "
429 "%f (x=%f,y=%f,r=%f)\n",
431 xytheta_transformation[0],
432 xytheta_transformation[1],
433 xytheta_transformation[2]);
435 if (score.
value != 0) {
437 Eigen::EigenSolver<Eigen::Matrix3d> solver;
438 solver.compute(score.
hessian,
false);
439 double min_eigenvalue = 0;
440 for (
int i = 0; i < 3; i++)
441 if (solver.eigenvalues()[i].real() < min_eigenvalue)
442 min_eigenvalue = solver.eigenvalues()[i].real();
446 if (min_eigenvalue < 0) {
447 double lambda = 1.1 * min_eigenvalue - 1;
448 score.
hessian += Eigen::Vector3d(-lambda, -lambda, -lambda).asDiagonal();
449 solver.compute(score.
hessian,
false);
450 PCL_DEBUG(
"[pcl::NormalDistributionsTransform2D::computeTransformation] adjust "
451 "hessian: %f: new eigenvalues:%f %f %f\n",
453 solver.eigenvalues()[0].real(),
454 solver.eigenvalues()[1].real(),
455 solver.eigenvalues()[2].real());
457 assert(solver.eigenvalues()[0].real() >= 0 &&
458 solver.eigenvalues()[1].real() >= 0 &&
459 solver.eigenvalues()[2].real() >= 0);
461 Eigen::Vector3d delta_transformation(-score.
hessian.inverse() * score.
grad);
462 Eigen::Vector3d new_transformation =
463 xytheta_transformation + newton_lambda_.cwiseProduct(delta_transformation);
465 xytheta_transformation = new_transformation;
468 transformation.block<3, 3>(0, 0).matrix() = Eigen::Matrix3f(Eigen::AngleAxisf(
469 static_cast<float>(xytheta_transformation[2]), Eigen::Vector3f::UnitZ()));
470 transformation.block<3, 1>(0, 3).matrix() =
471 Eigen::Vector3f(
static_cast<float>(xytheta_transformation[0]),
472 static_cast<float>(xytheta_transformation[1]),
478 PCL_ERROR(
"[pcl::NormalDistributionsTransform2D::computeTransformation] no "
479 "overlap: try increasing the size or reducing the step of the grid\n");
487 if (update_visualizer_)
488 update_visualizer_(output, *indices_, *target_, *indices_);
493 Eigen::Matrix4f transformation_delta =
494 transformation.inverse() * previous_transformation_;
496 0.5 * (transformation_delta.coeff(0, 0) + transformation_delta.coeff(1, 1) +
497 transformation_delta.coeff(2, 2) - 1);
498 double translation_sqr =
499 transformation_delta.coeff(0, 3) * transformation_delta.coeff(0, 3) +
500 transformation_delta.coeff(1, 3) * transformation_delta.coeff(1, 3) +
501 transformation_delta.coeff(2, 3) * transformation_delta.coeff(2, 3);
503 if (nr_iterations_ >= max_iterations_ ||
504 ((transformation_epsilon_ > 0 && translation_sqr <= transformation_epsilon_) &&
505 (transformation_rotation_epsilon_ > 0 &&
506 cos_angle >= transformation_rotation_epsilon_)) ||
507 ((transformation_epsilon_ <= 0) &&
508 (transformation_rotation_epsilon_ > 0 &&
509 cos_angle >= transformation_rotation_epsilon_)) ||
510 ((transformation_epsilon_ > 0 && translation_sqr <= transformation_epsilon_) &&
511 (transformation_rotation_epsilon_ <= 0))) {
515 final_transformation_ = transformation;