41 #ifndef PCL_NDT_2D_IMPL_H_
42 #define PCL_NDT_2D_IMPL_H_
44 #include <pcl/registration/boost.h>
46 #include <Eigen/Eigenvalues>
58 template <
unsigned N = 3,
typename T =
double>
63 Eigen::Matrix<T, N, 1>
grad;
70 r.
hessian = Eigen::Matrix<T, N, N>::Zero();
71 r.
grad = Eigen::Matrix<T, N, 1>::Zero();
97 template <
typename Po
intT>
121 Eigen::Vector2d sx = Eigen::Vector2d::Zero();
122 Eigen::Matrix2d sxx = Eigen::Matrix2d::Zero();
125 Eigen::Vector2d p(cloud[*i].x, cloud[*i].y);
127 sxx += p * p.transpose();
133 mean_ = sx /
static_cast<double>(
n_);
135 Eigen::Matrix2d covar =
136 (sxx - 2 * (sx *
mean_.transpose())) /
static_cast<double>(
n_) +
139 Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> solver(covar);
140 if (solver.eigenvalues()[0] < min_covar_eigvalue_mult * solver.eigenvalues()[1]) {
141 PCL_DEBUG(
"[pcl::NormalDist::estimateParams] NDT normal fit: adjusting "
143 solver.eigenvalues()[0]);
144 Eigen::Matrix2d l = solver.eigenvalues().asDiagonal();
145 Eigen::Matrix2d q = solver.eigenvectors();
147 l(0, 0) = l(1, 1) * min_covar_eigvalue_mult;
148 covar = q * l * q.transpose();
167 const double& cos_theta,
168 const double& sin_theta)
const
174 const double x = transformed_pt.x;
175 const double y = transformed_pt.y;
176 const Eigen::Vector2d p_xy(transformed_pt.x, transformed_pt.y);
177 const Eigen::Vector2d q = p_xy -
mean_;
178 const Eigen::RowVector2d qt_cvi(q.transpose() *
covar_inv_);
179 const double exp_qt_cvi_q = std::exp(-0.5 *
double(qt_cvi * q));
180 r.
value = -exp_qt_cvi_q;
182 Eigen::Matrix<double, 2, 3> jacobian;
183 jacobian << 1, 0, -(x * sin_theta + y * cos_theta), 0, 1,
184 x * cos_theta - y * sin_theta;
186 for (std::size_t i = 0; i < 3; i++)
187 r.
grad[i] =
double(qt_cvi * jacobian.col(i)) * exp_qt_cvi_q;
190 const Eigen::Vector2d d2q_didj(y * sin_theta - x * cos_theta,
191 -(x * sin_theta + y * cos_theta));
193 for (std::size_t i = 0; i < 3; i++)
194 for (std::size_t j = 0; j < 3; j++)
197 (double(-qt_cvi * jacobian.col(i)) * double(-qt_cvi * jacobian.col(j)) +
198 (-qt_cvi * ((i == 2 && j == 2) ? d2q_didj : Eigen::Vector2d::Zero())) +
199 (-jacobian.col(j).transpose() *
covar_inv_ * jacobian.col(i)));
217 template <
typename Po
intT>
225 const Eigen::Vector2f& about,
226 const Eigen::Vector2f& extent,
227 const Eigen::Vector2f& step)
228 :
min_(about - extent)
235 std::size_t used_points = 0;
236 for (std::size_t i = 0; i < cloud->size(); i++)
242 PCL_DEBUG(
"[pcl::NDTSingleGrid] NDT single grid %dx%d using %d/%d points\n",
250 for (
int x = 0; x <
cells_[0]; x++)
251 for (
int y = 0; y <
cells_[1]; y++)
264 const double& cos_theta,
265 const double& sin_theta)
const
271 return n->
test(transformed_pt, cos_theta, sin_theta);
283 Eigen::Vector2f idxf;
284 for (std::size_t i = 0; i < 2; i++)
285 idxf[i] = (p.getVector3fMap()[i] -
min_[i]) /
step_[i];
286 Eigen::Vector2i idxi = idxf.cast<
int>();
287 for (std::size_t i = 0; i < 2; i++)
288 if (idxi[i] >=
cells_[i] || idxi[i] < 0)
309 template <
typename Po
intT>
310 class NDT2D :
public boost::noncopyable {
323 const Eigen::Vector2f& about,
324 const Eigen::Vector2f& extent,
325 const Eigen::Vector2f& step)
327 Eigen::Vector2f dx(step[0] / 2, 0);
328 Eigen::Vector2f dy(0, step[1] / 2);
344 const double& cos_theta,
345 const double& sin_theta)
const
349 r += single_grid->test(transformed_pt, cos_theta, sin_theta);
365 template <
typename Po
intT>
366 struct NumTraits<
pcl::ndt2d::NormalDist<PointT>> {
378 RequireInitialization = 1,
389 template <
typename Po
intSource,
typename Po
intTarget>
392 PointCloudSource& output,
const Eigen::Matrix4f& guess)
394 PointCloudSource intm_cloud = output;
399 if (guess != Eigen::Matrix4f::Identity()) {
400 transformation_ = guess;
409 Eigen::Matrix4f& transformation = transformation_;
413 const Eigen::Matrix3f initial_rot(transformation.block<3, 3>(0, 0));
414 const Eigen::Vector3f rot_x(initial_rot * Eigen::Vector3f::UnitX());
415 const double z_rotation = std::atan2(rot_x[1], rot_x[0]);
417 Eigen::Vector3d xytheta_transformation(
418 transformation(0, 3), transformation(1, 3), z_rotation);
420 while (!converged_) {
421 const double cos_theta = std::cos(xytheta_transformation[2]);
422 const double sin_theta = std::sin(xytheta_transformation[2]);
423 previous_transformation_ = transformation;
427 for (std::size_t i = 0; i < intm_cloud.size(); i++)
428 score += target_ndt.
test(intm_cloud[i], cos_theta, sin_theta);
430 PCL_DEBUG(
"[pcl::NormalDistributionsTransform2D::computeTransformation] NDT score "
431 "%f (x=%f,y=%f,r=%f)\n",
433 xytheta_transformation[0],
434 xytheta_transformation[1],
435 xytheta_transformation[2]);
437 if (score.
value != 0) {
439 Eigen::EigenSolver<Eigen::Matrix3d> solver;
440 solver.compute(score.
hessian,
false);
441 double min_eigenvalue = 0;
442 for (
int i = 0; i < 3; i++)
443 if (solver.eigenvalues()[i].real() < min_eigenvalue)
444 min_eigenvalue = solver.eigenvalues()[i].real();
448 if (min_eigenvalue < 0) {
449 double lambda = 1.1 * min_eigenvalue - 1;
450 score.
hessian += Eigen::Vector3d(-lambda, -lambda, -lambda).asDiagonal();
451 solver.compute(score.
hessian,
false);
452 PCL_DEBUG(
"[pcl::NormalDistributionsTransform2D::computeTransformation] adjust "
453 "hessian: %f: new eigenvalues:%f %f %f\n",
455 solver.eigenvalues()[0].real(),
456 solver.eigenvalues()[1].real(),
457 solver.eigenvalues()[2].real());
459 assert(solver.eigenvalues()[0].real() >= 0 &&
460 solver.eigenvalues()[1].real() >= 0 &&
461 solver.eigenvalues()[2].real() >= 0);
463 Eigen::Vector3d delta_transformation(-score.
hessian.inverse() * score.
grad);
464 Eigen::Vector3d new_transformation =
465 xytheta_transformation + newton_lambda_.cwiseProduct(delta_transformation);
467 xytheta_transformation = new_transformation;
470 transformation.block<3, 3>(0, 0).matrix() = Eigen::Matrix3f(Eigen::AngleAxisf(
471 static_cast<float>(xytheta_transformation[2]), Eigen::Vector3f::UnitZ()));
472 transformation.block<3, 1>(0, 3).matrix() =
473 Eigen::Vector3f(
static_cast<float>(xytheta_transformation[0]),
474 static_cast<float>(xytheta_transformation[1]),
480 PCL_ERROR(
"[pcl::NormalDistributionsTransform2D::computeTransformation] no "
481 "overlap: try increasing the size or reducing the step of the grid\n");
489 if (update_visualizer_)
490 update_visualizer_(output, *indices_, *target_, *indices_);
495 Eigen::Matrix4f transformation_delta =
496 transformation.inverse() * previous_transformation_;
498 0.5 * (transformation_delta.coeff(0, 0) + transformation_delta.coeff(1, 1) +
499 transformation_delta.coeff(2, 2) - 1);
500 double translation_sqr =
501 transformation_delta.coeff(0, 3) * transformation_delta.coeff(0, 3) +
502 transformation_delta.coeff(1, 3) * transformation_delta.coeff(1, 3) +
503 transformation_delta.coeff(2, 3) * transformation_delta.coeff(2, 3);
505 if (nr_iterations_ >= max_iterations_ ||
506 ((transformation_epsilon_ > 0 && translation_sqr <= transformation_epsilon_) &&
507 (transformation_rotation_epsilon_ > 0 &&
508 cos_angle >= transformation_rotation_epsilon_)) ||
509 ((transformation_epsilon_ <= 0) &&
510 (transformation_rotation_epsilon_ > 0 &&
511 cos_angle >= transformation_rotation_epsilon_)) ||
512 ((transformation_epsilon_ > 0 && translation_sqr <= transformation_epsilon_) &&
513 (transformation_rotation_epsilon_ <= 0))) {
517 final_transformation_ = transformation;
523 #endif // PCL_NDT_2D_IMPL_H_