41 #ifndef PCL_REGISTRATION_IMPL_GICP_HPP_
42 #define PCL_REGISTRATION_IMPL_GICP_HPP_
44 #include <pcl/registration/exceptions.h>
48 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
51 unsigned int nr_threads)
55 threads_ = omp_get_num_procs();
57 threads_ = nr_threads;
58 PCL_DEBUG(
"[pcl::GeneralizedIterativeClosestPoint::setNumberOfThreads] Setting "
59 "number of threads to %u.\n",
64 PCL_WARN(
"[pcl::GeneralizedIterativeClosestPoint::setNumberOfThreads] "
65 "Parallelization is requested, but OpenMP is not available! Continuing "
66 "without parallelization.\n");
70 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
71 template <
typename Po
intT>
78 if (k_correspondences_ > static_cast<int>(cloud->
size())) {
79 PCL_ERROR(
"[pcl::GeneralizedIterativeClosestPoint::computeCovariances] Number or "
80 "points in cloud (%lu) is less than k_correspondences_ (%lu)!\n",
89 std::vector<float> nn_dist_sq(k_correspondences_);
92 if (cloud_covariances.size() < cloud->
size())
93 cloud_covariances.resize(cloud->
size());
95 #pragma omp parallel for num_threads(threads_) schedule(dynamic, 32) \
96 shared(cloud, cloud_covariances) firstprivate(mean, cov, nn_indices, nn_dist_sq)
97 for (std::ptrdiff_t i = 0; i < static_cast<std::ptrdiff_t>(cloud->
size()); ++i) {
98 const PointT& query_point = (*cloud)[i];
104 kdtree->
nearestKSearch(query_point, k_correspondences_, nn_indices, nn_dist_sq);
107 for (
int j = 0; j < k_correspondences_; j++) {
109 const double ptx = (*cloud)[nn_indices[j]].x - query_point.x,
110 pty = (*cloud)[nn_indices[j]].y - query_point.y,
111 ptz = (*cloud)[nn_indices[j]].z - query_point.z;
117 cov(0, 0) += ptx * ptx;
119 cov(1, 0) += pty * ptx;
120 cov(1, 1) += pty * pty;
122 cov(2, 0) += ptz * ptx;
123 cov(2, 1) += ptz * pty;
124 cov(2, 2) += ptz * ptz;
127 mean /=
static_cast<double>(k_correspondences_);
129 for (
int k = 0; k < 3; k++)
130 for (
int l = 0; l <= k; l++) {
131 cov(k, l) /=
static_cast<double>(k_correspondences_);
132 cov(k, l) -= mean[k] * mean[l];
133 cov(l, k) = cov(k, l);
137 Eigen::JacobiSVD<Eigen::Matrix3d> svd(cov, Eigen::ComputeFullU);
139 Eigen::Matrix3d U = svd.matrixU();
142 for (
int k = 0; k < 3; k++) {
143 Eigen::Vector3d col = U.col(k);
147 cov.noalias() += v * col * col.transpose();
149 cloud_covariances[i] = cov;
153 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
159 Eigen::Matrix3d& dR_dPhi,
160 Eigen::Matrix3d& dR_dTheta,
161 Eigen::Matrix3d& dR_dPsi)
const
163 const double cphi = std::cos(phi), sphi = std::sin(phi);
164 const double ctheta = std::cos(theta), stheta = std::sin(theta);
165 const double cpsi = std::cos(psi), spsi = std::sin(psi);
170 dR_dPhi(0, 1) = sphi * spsi + cphi * cpsi * stheta;
171 dR_dPhi(1, 1) = -cpsi * sphi + cphi * spsi * stheta;
172 dR_dPhi(2, 1) = cphi * ctheta;
174 dR_dPhi(0, 2) = cphi * spsi - cpsi * sphi * stheta;
175 dR_dPhi(1, 2) = -cphi * cpsi - sphi * spsi * stheta;
176 dR_dPhi(2, 2) = -ctheta * sphi;
178 dR_dTheta(0, 0) = -cpsi * stheta;
179 dR_dTheta(1, 0) = -spsi * stheta;
180 dR_dTheta(2, 0) = -ctheta;
182 dR_dTheta(0, 1) = cpsi * ctheta * sphi;
183 dR_dTheta(1, 1) = ctheta * sphi * spsi;
184 dR_dTheta(2, 1) = -sphi * stheta;
186 dR_dTheta(0, 2) = cphi * cpsi * ctheta;
187 dR_dTheta(1, 2) = cphi * ctheta * spsi;
188 dR_dTheta(2, 2) = -cphi * stheta;
190 dR_dPsi(0, 0) = -ctheta * spsi;
191 dR_dPsi(1, 0) = cpsi * ctheta;
194 dR_dPsi(0, 1) = -cphi * cpsi - sphi * spsi * stheta;
195 dR_dPsi(1, 1) = -cphi * spsi + cpsi * sphi * stheta;
198 dR_dPsi(0, 2) = cpsi * sphi - cphi * spsi * stheta;
199 dR_dPsi(1, 2) = sphi * spsi + cphi * cpsi * stheta;
203 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
208 Eigen::Matrix3d dR_dPhi;
209 Eigen::Matrix3d dR_dTheta;
210 Eigen::Matrix3d dR_dPsi;
211 getRDerivatives(x[3], x[4], x[5], dR_dPhi, dR_dTheta, dR_dPsi);
213 g[3] = (dR_dPhi * dCost_dR_T).trace();
214 g[4] = (dR_dTheta * dCost_dR_T).trace();
215 g[5] = (dR_dPsi * dCost_dR_T).trace();
218 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
224 Eigen::Matrix3d& ddR_dPhi_dPhi,
225 Eigen::Matrix3d& ddR_dPhi_dTheta,
226 Eigen::Matrix3d& ddR_dPhi_dPsi,
227 Eigen::Matrix3d& ddR_dTheta_dTheta,
228 Eigen::Matrix3d& ddR_dTheta_dPsi,
229 Eigen::Matrix3d& ddR_dPsi_dPsi)
const
231 const double sphi = std::sin(phi), stheta = std::sin(theta), spsi = std::sin(psi);
232 const double cphi = std::cos(phi), ctheta = std::cos(theta), cpsi = std::cos(psi);
233 ddR_dPhi_dPhi(0, 0) = 0.0;
234 ddR_dPhi_dPhi(1, 0) = 0.0;
235 ddR_dPhi_dPhi(2, 0) = 0.0;
236 ddR_dPhi_dPhi(0, 1) = -cpsi * stheta * sphi + spsi * cphi;
237 ddR_dPhi_dPhi(1, 1) = -cpsi * cphi - spsi * stheta * sphi;
238 ddR_dPhi_dPhi(2, 1) = -ctheta * sphi;
239 ddR_dPhi_dPhi(0, 2) = -spsi * sphi - cpsi * stheta * cphi;
240 ddR_dPhi_dPhi(1, 2) = -spsi * stheta * cphi + cpsi * sphi;
241 ddR_dPhi_dPhi(2, 2) = -ctheta * cphi;
243 ddR_dPhi_dTheta(0, 0) = 0.0;
244 ddR_dPhi_dTheta(1, 0) = 0.0;
245 ddR_dPhi_dTheta(2, 0) = 0.0;
246 ddR_dPhi_dTheta(0, 1) = cpsi * ctheta * cphi;
247 ddR_dPhi_dTheta(1, 1) = spsi * ctheta * cphi;
248 ddR_dPhi_dTheta(2, 1) = -stheta * cphi;
249 ddR_dPhi_dTheta(0, 2) = -cpsi * ctheta * sphi;
250 ddR_dPhi_dTheta(1, 2) = -spsi * ctheta * sphi;
251 ddR_dPhi_dTheta(2, 2) = stheta * sphi;
253 ddR_dPhi_dPsi(0, 0) = 0.0;
254 ddR_dPhi_dPsi(1, 0) = 0.0;
255 ddR_dPhi_dPsi(2, 0) = 0.0;
256 ddR_dPhi_dPsi(0, 1) = -spsi * stheta * cphi + cpsi * sphi;
257 ddR_dPhi_dPsi(1, 1) = spsi * sphi + cpsi * stheta * cphi;
258 ddR_dPhi_dPsi(2, 1) = 0.0;
259 ddR_dPhi_dPsi(0, 2) = cpsi * cphi + spsi * stheta * sphi;
260 ddR_dPhi_dPsi(1, 2) = -cpsi * stheta * sphi + spsi * cphi;
261 ddR_dPhi_dPsi(2, 2) = 0.0;
263 ddR_dTheta_dTheta(0, 0) = -cpsi * ctheta;
264 ddR_dTheta_dTheta(1, 0) = -spsi * ctheta;
265 ddR_dTheta_dTheta(2, 0) = stheta;
266 ddR_dTheta_dTheta(0, 1) = -cpsi * stheta * sphi;
267 ddR_dTheta_dTheta(1, 1) = -spsi * stheta * sphi;
268 ddR_dTheta_dTheta(2, 1) = -ctheta * sphi;
269 ddR_dTheta_dTheta(0, 2) = -cpsi * stheta * cphi;
270 ddR_dTheta_dTheta(1, 2) = -spsi * stheta * cphi;
271 ddR_dTheta_dTheta(2, 2) = -ctheta * cphi;
273 ddR_dTheta_dPsi(0, 0) = spsi * stheta;
274 ddR_dTheta_dPsi(1, 0) = -cpsi * stheta;
275 ddR_dTheta_dPsi(2, 0) = 0.0;
276 ddR_dTheta_dPsi(0, 1) = -spsi * ctheta * sphi;
277 ddR_dTheta_dPsi(1, 1) = cpsi * ctheta * sphi;
278 ddR_dTheta_dPsi(2, 1) = 0.0;
279 ddR_dTheta_dPsi(0, 2) = -spsi * ctheta * cphi;
280 ddR_dTheta_dPsi(1, 2) = cpsi * ctheta * cphi;
281 ddR_dTheta_dPsi(2, 2) = 0.0;
283 ddR_dPsi_dPsi(0, 0) = -cpsi * ctheta;
284 ddR_dPsi_dPsi(1, 0) = -spsi * ctheta;
285 ddR_dPsi_dPsi(2, 0) = 0.0;
286 ddR_dPsi_dPsi(0, 1) = -cpsi * stheta * sphi + spsi * cphi;
287 ddR_dPsi_dPsi(1, 1) = -cpsi * cphi - spsi * stheta * sphi;
288 ddR_dPsi_dPsi(2, 1) = 0.0;
289 ddR_dPsi_dPsi(0, 2) = -spsi * sphi - cpsi * stheta * cphi;
290 ddR_dPsi_dPsi(1, 2) = -spsi * stheta * cphi + cpsi * sphi;
291 ddR_dPsi_dPsi(2, 2) = 0.0;
294 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
301 Matrix4& transformation_matrix)
304 if (indices_src.size() < min_number_correspondences_) {
307 "[pcl::GeneralizedIterativeClosestPoint::estimateRigidTransformationBFGS] Need "
309 << min_number_correspondences_
310 <<
" points to estimate a transform! "
311 "Source and target have "
312 << indices_src.size() <<
" points!");
318 x[0] = transformation_matrix(0, 3);
319 x[1] = transformation_matrix(1, 3);
320 x[2] = transformation_matrix(2, 3);
323 x[3] = std::atan2(transformation_matrix(2, 1), transformation_matrix(2, 2));
324 x[4] = asin(-transformation_matrix(2, 0));
325 x[5] = std::atan2(transformation_matrix(1, 0), transformation_matrix(0, 0));
328 tmp_src_ = &cloud_src;
329 tmp_tgt_ = &cloud_tgt;
330 tmp_idx_src_ = &indices_src;
331 tmp_idx_tgt_ = &indices_tgt;
343 int inner_iterations_ = 0;
355 inner_iterations_ == max_inner_iterations_) {
356 PCL_DEBUG(
"[pcl::registration::TransformationEstimationBFGS::"
357 "estimateRigidTransformation]");
358 PCL_DEBUG(
"BFGS solver finished with exit code %i \n", result);
359 transformation_matrix.setIdentity();
360 applyState(transformation_matrix, x);
365 "[pcl::" << getClassName()
366 <<
"::TransformationEstimationBFGS::estimateRigidTransformation] BFGS "
367 "solver didn't converge!");
370 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
377 Matrix4& transformation_matrix)
380 if (indices_src.size() < min_number_correspondences_) {
382 "[pcl::GeneralizedIterativeClosestPoint::"
383 "estimateRigidTransformationNewton] Need "
385 << min_number_correspondences_
386 <<
" points to estimate a transform! "
387 "Source and target have "
388 << indices_src.size() <<
" points!");
394 x[0] = transformation_matrix(0, 3);
395 x[1] = transformation_matrix(1, 3);
396 x[2] = transformation_matrix(2, 3);
399 x[3] = std::atan2(transformation_matrix(2, 1), transformation_matrix(2, 2));
401 std::min<double>(1.0, std::max<double>(-1.0, -transformation_matrix(2, 0))));
402 x[5] = std::atan2(transformation_matrix(1, 0), transformation_matrix(0, 0));
405 tmp_src_ = &cloud_src;
406 tmp_tgt_ = &cloud_tgt;
407 tmp_idx_src_ = &indices_src;
408 tmp_idx_tgt_ = &indices_tgt;
412 Eigen::Matrix<double, 6, 6> hessian;
413 Eigen::Matrix<double, 6, 1> gradient;
414 double current_x_value = functor(x);
415 functor.
dfddf(x, gradient, hessian);
416 Eigen::Matrix<double, 6, 1> delta;
417 int inner_iterations_ = 0;
422 Eigen::SelfAdjointEigenSolver<Eigen::Matrix<double, 6, 6>> eigensolver(hessian);
423 Eigen::Matrix<double, 6, 6> inverted_eigenvalues =
424 Eigen::Matrix<double, 6, 6>::Zero();
425 for (
int i = 0; i < 6; ++i) {
426 const double ev = eigensolver.eigenvalues()[i];
428 inverted_eigenvalues(i, i) = 1.0 / eigensolver.eigenvalues()[5];
430 inverted_eigenvalues(i, i) = 1.0 / ev;
432 delta.noalias() = eigensolver.eigenvectors() * inverted_eigenvalues *
433 eigensolver.eigenvectors().transpose() * gradient;
437 double candidate_x_value;
438 bool improvement_found =
false;
439 for (
int i = 0; i < 10; ++i, alpha /= 2) {
440 Vector6d candidate_x = x - alpha * delta;
441 candidate_x_value = functor(candidate_x);
442 if (candidate_x_value < current_x_value) {
443 PCL_DEBUG(
"[estimateRigidTransformationNewton] Using stepsize=%g, function "
444 "value previously: %g, now: %g, "
449 current_x_value - candidate_x_value);
451 current_x_value = candidate_x_value;
452 improvement_found =
true;
456 if (!improvement_found) {
457 PCL_DEBUG(
"[estimateRigidTransformationNewton] finishing because no progress\n");
460 functor.
dfddf(x, gradient, hessian);
461 if (gradient.head<3>().norm() < translation_gradient_tolerance_ &&
462 gradient.tail<3>().norm() < rotation_gradient_tolerance_) {
463 PCL_DEBUG(
"[estimateRigidTransformationNewton] finishing because gradient below "
464 "threshold: translation: %g<%g, rotation: %g<%g\n",
465 gradient.head<3>().norm(),
466 translation_gradient_tolerance_,
467 gradient.tail<3>().norm(),
468 rotation_gradient_tolerance_);
471 }
while (inner_iterations_ < max_inner_iterations_);
472 PCL_DEBUG(
"[estimateRigidTransformationNewton] solver finished after %i iterations "
475 max_inner_iterations_);
476 transformation_matrix.setIdentity();
477 applyState(transformation_matrix, x);
480 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
486 gicp_->applyState(transformation_matrix, x);
488 int m =
static_cast<int>(gicp_->tmp_idx_src_->size());
489 for (
int i = 0; i < m; ++i) {
492 (*gicp_->tmp_src_)[(*gicp_->tmp_idx_src_)[i]].getVector4fMap();
495 (*gicp_->tmp_tgt_)[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap();
496 Eigen::Vector4f p_trans_src(transformation_matrix.template cast<float>() * p_src);
500 Eigen::Vector3d d(p_trans_src[0] - p_tgt[0],
501 p_trans_src[1] - p_tgt[1],
502 p_trans_src[2] - p_tgt[2]);
503 Eigen::Vector3d Md(gicp_->mahalanobis((*gicp_->tmp_idx_src_)[i]) * d);
506 f +=
static_cast<double>(d.transpose() * Md);
511 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
517 gicp_->applyState(transformation_matrix, x);
522 Eigen::Matrix3d dCost_dR_T = Eigen::Matrix3d::Zero();
523 int m =
static_cast<int>(gicp_->tmp_idx_src_->size());
524 for (
int i = 0; i < m; ++i) {
527 (*gicp_->tmp_src_)[(*gicp_->tmp_idx_src_)[i]].getVector4fMap();
530 (*gicp_->tmp_tgt_)[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap();
532 Eigen::Vector4f p_trans_src(transformation_matrix.template cast<float>() * p_src);
535 Eigen::Vector3d d(p_trans_src[0] - p_tgt[0],
536 p_trans_src[1] - p_tgt[1],
537 p_trans_src[2] - p_tgt[2]);
539 Eigen::Vector3d Md(gicp_->mahalanobis((*gicp_->tmp_idx_src_)[i]) * d);
545 p_trans_src.noalias() = gicp_->base_transformation_.template cast<float>() * p_src;
546 Eigen::Vector3d p_base_src(p_trans_src[0], p_trans_src[1], p_trans_src[2]);
547 dCost_dR_T.noalias() += p_base_src * Md.transpose();
549 g.head<3>() *= 2.0 / m;
550 dCost_dR_T *= 2.0 / m;
551 gicp_->computeRDerivative(x, dCost_dR_T, g);
554 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
560 gicp_->applyState(transformation_matrix, x);
564 Eigen::Matrix3d dCost_dR_T = Eigen::Matrix3d::Zero();
565 const int m =
static_cast<int>(gicp_->tmp_idx_src_->size());
566 for (
int i = 0; i < m; ++i) {
569 (*gicp_->tmp_src_)[(*gicp_->tmp_idx_src_)[i]].getVector4fMap();
572 (*gicp_->tmp_tgt_)[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap();
573 Eigen::Vector4f p_trans_src(transformation_matrix.template cast<float>() * p_src);
576 Eigen::Vector3d d(p_trans_src[0] - p_tgt[0],
577 p_trans_src[1] - p_tgt[1],
578 p_trans_src[2] - p_tgt[2]);
580 Eigen::Vector3d Md(gicp_->mahalanobis((*gicp_->tmp_idx_src_)[i]) * d);
582 f +=
static_cast<double>(d.transpose() * Md);
587 p_trans_src.noalias() = gicp_->base_transformation_.template cast<float>() * p_src;
588 Eigen::Vector3d p_base_src(p_trans_src[0], p_trans_src[1], p_trans_src[2]);
590 dCost_dR_T.noalias() += p_base_src * Md.transpose();
592 f /=
static_cast<double>(m);
593 g.head<3>() *= (2.0 / m);
594 dCost_dR_T *= 2.0 / m;
595 gicp_->computeRDerivative(x, dCost_dR_T, g);
598 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
606 gicp_->applyState(transformation_matrix, x);
607 const Eigen::Matrix4f transformation_matrix_float =
608 transformation_matrix.template cast<float>();
609 const Eigen::Matrix4f base_transformation_float =
610 gicp_->base_transformation_.template cast<float>();
615 Eigen::Matrix3d dR_dPhi;
616 Eigen::Matrix3d dR_dTheta;
617 Eigen::Matrix3d dR_dPsi;
618 gicp_->getRDerivatives(x[3], x[4], x[5], dR_dPhi, dR_dTheta, dR_dPsi);
619 Eigen::Matrix3d ddR_dPhi_dPhi;
620 Eigen::Matrix3d ddR_dPhi_dTheta;
621 Eigen::Matrix3d ddR_dPhi_dPsi;
622 Eigen::Matrix3d ddR_dTheta_dTheta;
623 Eigen::Matrix3d ddR_dTheta_dPsi;
624 Eigen::Matrix3d ddR_dPsi_dPsi;
625 gicp_->getR2ndDerivatives(x[3],
634 Eigen::Matrix3d dCost_dR_T = Eigen::Matrix3d::Zero();
635 Eigen::Matrix3d dCost_dR_T1 = Eigen::Matrix3d::Zero();
636 Eigen::Matrix3d dCost_dR_T2 = Eigen::Matrix3d::Zero();
637 Eigen::Matrix3d dCost_dR_T3 = Eigen::Matrix3d::Zero();
638 Eigen::Matrix3d dCost_dR_T1b = Eigen::Matrix3d::Zero();
639 Eigen::Matrix3d dCost_dR_T2b = Eigen::Matrix3d::Zero();
640 Eigen::Matrix3d dCost_dR_T3b = Eigen::Matrix3d::Zero();
641 Eigen::Matrix3d hessian_rot_phi = Eigen::Matrix3d::Zero();
642 Eigen::Matrix3d hessian_rot_theta = Eigen::Matrix3d::Zero();
643 Eigen::Matrix3d hessian_rot_psi = Eigen::Matrix3d::Zero();
644 Eigen::Matrix<double, 9, 6> hessian_rot_tmp = Eigen::Matrix<double, 9, 6>::Zero();
646 int m =
static_cast<int>(gicp_->tmp_idx_src_->size());
647 for (
int i = 0; i < m; ++i) {
649 const auto& src_idx = (*gicp_->tmp_idx_src_)[i];
653 (*gicp_->tmp_tgt_)[(*gicp_->tmp_idx_tgt_)[i]].getVector4fMap();
654 Eigen::Vector4f p_trans_src(transformation_matrix_float * p_src);
657 const Eigen::Vector3d d(p_trans_src[0] - p_tgt[0],
658 p_trans_src[1] - p_tgt[1],
659 p_trans_src[2] - p_tgt[2]);
660 const Eigen::Matrix3d& M = gicp_->mahalanobis(src_idx);
661 const Eigen::Vector3d Md(M * d);
662 gradient.head<3>() += Md;
663 hessian.topLeftCorner<3, 3>() += M;
664 p_trans_src.noalias() = base_transformation_float * p_src;
665 const Eigen::Vector3d p_base_src(p_trans_src[0], p_trans_src[1], p_trans_src[2]);
666 dCost_dR_T.noalias() += p_base_src * Md.transpose();
667 dCost_dR_T1b += p_base_src[0] * M;
668 dCost_dR_T2b += p_base_src[1] * M;
669 dCost_dR_T3b += p_base_src[2] * M;
670 hessian_rot_tmp.noalias() +=
671 Eigen::Map<const Eigen::Matrix<double, 9, 1>>{M.data()} *
672 (Eigen::Matrix<double, 1, 6>() << p_base_src[0] * p_base_src[0],
673 p_base_src[0] * p_base_src[1],
674 p_base_src[0] * p_base_src[2],
675 p_base_src[1] * p_base_src[1],
676 p_base_src[1] * p_base_src[2],
677 p_base_src[2] * p_base_src[2])
680 gradient.head<3>() *= 2.0 / m;
681 dCost_dR_T *= 2.0 / m;
682 gicp_->computeRDerivative(x, dCost_dR_T, gradient);
683 hessian.topLeftCorner<3, 3>() *= 2.0 / m;
685 dCost_dR_T1.row(0) = dCost_dR_T1b.col(0);
686 dCost_dR_T1.row(1) = dCost_dR_T2b.col(0);
687 dCost_dR_T1.row(2) = dCost_dR_T3b.col(0);
688 dCost_dR_T2.row(0) = dCost_dR_T1b.col(1);
689 dCost_dR_T2.row(1) = dCost_dR_T2b.col(1);
690 dCost_dR_T2.row(2) = dCost_dR_T3b.col(1);
691 dCost_dR_T3.row(0) = dCost_dR_T1b.col(2);
692 dCost_dR_T3.row(1) = dCost_dR_T2b.col(2);
693 dCost_dR_T3.row(2) = dCost_dR_T3b.col(2);
694 dCost_dR_T1 *= 2.0 / m;
695 dCost_dR_T2 *= 2.0 / m;
696 dCost_dR_T3 *= 2.0 / m;
697 hessian(3, 0) = (dR_dPhi * dCost_dR_T1).trace();
698 hessian(4, 0) = (dR_dTheta * dCost_dR_T1).trace();
699 hessian(5, 0) = (dR_dPsi * dCost_dR_T1).trace();
700 hessian(3, 1) = (dR_dPhi * dCost_dR_T2).trace();
701 hessian(4, 1) = (dR_dTheta * dCost_dR_T2).trace();
702 hessian(5, 1) = (dR_dPsi * dCost_dR_T2).trace();
703 hessian(3, 2) = (dR_dPhi * dCost_dR_T3).trace();
704 hessian(4, 2) = (dR_dTheta * dCost_dR_T3).trace();
705 hessian(5, 2) = (dR_dPsi * dCost_dR_T3).trace();
706 hessian.block<3, 3>(0, 3) = hessian.block<3, 3>(3, 0).transpose();
708 int lookup[3][3] = {{0, 1, 2}, {1, 3, 4}, {2, 4, 5}};
709 for (
int l = 0; l < 3; ++l) {
710 for (
int i = 0; i < 3; ++i) {
711 double phi_tmp = 0.0, theta_tmp = 0.0, psi_tmp = 0.0;
712 for (
int j = 0; j < 3; ++j) {
713 for (
int k = 0; k < 3; ++k) {
714 phi_tmp += hessian_rot_tmp(3 * j + i, lookup[l][k]) * dR_dPhi(j, k);
715 theta_tmp += hessian_rot_tmp(3 * j + i, lookup[l][k]) * dR_dTheta(j, k);
716 psi_tmp += hessian_rot_tmp(3 * j + i, lookup[l][k]) * dR_dPsi(j, k);
719 hessian_rot_phi(i, l) = phi_tmp;
720 hessian_rot_theta(i, l) = theta_tmp;
721 hessian_rot_psi(i, l) = psi_tmp;
724 hessian_rot_phi *= 2.0 / m;
725 hessian_rot_theta *= 2.0 / m;
726 hessian_rot_psi *= 2.0 / m;
727 hessian(3, 3) = (dR_dPhi.transpose() * hessian_rot_phi).trace() +
728 (ddR_dPhi_dPhi * dCost_dR_T).trace();
729 hessian(3, 4) = (dR_dPhi.transpose() * hessian_rot_theta).trace() +
730 (ddR_dPhi_dTheta * dCost_dR_T).trace();
731 hessian(3, 5) = (dR_dPhi.transpose() * hessian_rot_psi).trace() +
732 (ddR_dPhi_dPsi * dCost_dR_T).trace();
733 hessian(4, 4) = (dR_dTheta.transpose() * hessian_rot_theta).trace() +
734 (ddR_dTheta_dTheta * dCost_dR_T).trace();
735 hessian(4, 5) = (dR_dTheta.transpose() * hessian_rot_psi).trace() +
736 (ddR_dTheta_dPsi * dCost_dR_T).trace();
737 hessian(5, 5) = (dR_dPsi.transpose() * hessian_rot_psi).trace() +
738 (ddR_dPsi_dPsi * dCost_dR_T).trace();
739 hessian(4, 3) = hessian(3, 4);
740 hessian(5, 3) = hessian(3, 5);
741 hessian(5, 4) = hessian(4, 5);
744 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
750 auto rotation_epsilon = gicp_->rotation_gradient_tolerance_;
752 if ((translation_epsilon < 0.) || (rotation_epsilon < 0.))
756 auto translation_grad = g.head<3>().norm();
759 auto rotation_grad = g.tail<3>().norm();
761 if ((translation_grad < translation_epsilon) && (rotation_grad < rotation_epsilon))
767 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
776 const std::size_t N = indices_->size();
778 mahalanobis_.resize(N, Eigen::Matrix3d::Identity());
780 if ((!target_covariances_) || (target_covariances_->empty())) {
782 computeCovariances<PointTarget>(target_, tree_, *target_covariances_);
785 if ((!input_covariances_) || (input_covariances_->empty())) {
787 computeCovariances<PointSource>(input_, tree_reciprocal_, *input_covariances_);
790 base_transformation_ = Matrix4::Identity();
794 std::vector<float> nn_dists(1);
804 auto output_transformed = pcl::make_shared<PointCloudSource>();
805 output_transformed->resize(output.
size());
808 while (!converged_) {
814 Eigen::Matrix4d transform_R = Eigen::Matrix4d::Zero();
815 for (std::size_t i = 0; i < 4; i++)
816 for (std::size_t j = 0; j < 4; j++)
817 for (std::size_t k = 0; k < 4; k++)
818 transform_R(i, j) +=
static_cast<double>(transformation_(i, k)) *
819 static_cast<double>(guess(k, j));
821 Eigen::Matrix3d R = transform_R.topLeftCorner<3, 3>();
824 output, *output_transformed, transformation_.template cast<float>(),
false);
828 for (
const auto& corr : correspondences) {
829 source_indices[cnt] = corr.index_query;
830 target_indices[cnt] = corr.index_match;
831 const Eigen::Matrix3d& C1 = (*input_covariances_)[corr.index_query];
832 const Eigen::Matrix3d& C2 = (*target_covariances_)[corr.index_match];
833 pcl::invert3x3SymMatrix<Eigen::Matrix3d>(R * C1 * R.transpose() + C2,
834 mahalanobis_[corr.index_query]);
838 source_indices.resize(cnt);
839 target_indices.resize(cnt);
841 previous_transformation_ = transformation_;
844 rigid_transformation_estimation_(
845 output, source_indices, *target_, target_indices, transformation_);
848 for (
int k = 0; k < 4; k++) {
849 for (
int l = 0; l < 4; l++) {
852 ratio = 1. / rotation_epsilon_;
854 ratio = 1. / transformation_epsilon_;
856 ratio * std::abs(previous_transformation_(k, l) - transformation_(k, l));
862 PCL_DEBUG(
"[pcl::%s::computeTransformation] Optimization issue %s\n",
863 getClassName().c_str(),
869 if (update_visualizer_ !=
nullptr) {
872 update_visualizer_(*input_transformed, source_indices, *target_, target_indices);
876 if (nr_iterations_ >= max_iterations_ || delta < 1) {
878 PCL_DEBUG(
"[pcl::%s::computeTransformation] Convergence reached. Number of "
879 "iterations: %d out of %d. Transformation difference: %f\n",
880 getClassName().c_str(),
883 (transformation_ - previous_transformation_).array().abs().sum());
884 previous_transformation_ = transformation_;
887 PCL_DEBUG(
"[pcl::%s::computeTransformation] Convergence failed\n",
888 getClassName().c_str());
890 final_transformation_.noalias() = previous_transformation_ * guess;
892 PCL_DEBUG(
"Transformation "
893 "is:\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n\t%"
894 "5f\t%5f\t%5f\t%5f\n",
895 final_transformation_(0, 0),
896 final_transformation_(0, 1),
897 final_transformation_(0, 2),
898 final_transformation_(0, 3),
899 final_transformation_(1, 0),
900 final_transformation_(1, 1),
901 final_transformation_(1, 2),
902 final_transformation_(1, 3),
903 final_transformation_(2, 0),
904 final_transformation_(2, 1),
905 final_transformation_(2, 2),
906 final_transformation_(2, 3),
907 final_transformation_(3, 0),
908 final_transformation_(3, 1),
909 final_transformation_(3, 2),
910 final_transformation_(3, 3));
916 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
923 AngleAxis(static_cast<Scalar>(x[4]), Vector3::UnitY()) *
924 AngleAxis(static_cast<Scalar>(x[3]), Vector3::UnitX()))
926 Matrix4 T = Matrix4::Identity();
927 T.template block<3, 3>(0, 0) = R;
928 T.template block<3, 1>(0, 3) =
Vector3(
929 static_cast<Scalar>(x[0]),
static_cast<Scalar
>(x[1]), static_cast<Scalar>(x[2]));
935 #endif // PCL_REGISTRATION_IMPL_GICP_HPP_
shared_ptr< KdTree< PointT, Tree > > Ptr
bool initComputeReciprocal()
Internal computation when reciprocal lookup is needed.
void estimateRigidTransformationBFGS(const PointCloudSource &cloud_src, const pcl::Indices &indices_src, const PointCloudTarget &cloud_tgt, const pcl::Indices &indices_tgt, Matrix4 &transformation_matrix)
Estimate a rigid rotation transformation between a source and a target point cloud using an iterative...
double translation_gradient_tolerance_
minimal translation gradient for early optimization stop
void determineCorrespondences(pcl::Correspondences &correspondences, double max_distance=std::numeric_limits< double >::max()) override
Determine the correspondences between input and target cloud.
std::vector< Eigen::Matrix3d, Eigen::aligned_allocator< Eigen::Matrix3d >> MatricesVector
Matrix4 base_transformation_
base transformation
BFGSSpace::Status testGradient()
typename IterativeClosestPoint< PointSource, PointTarget, Scalar >::Matrix4 Matrix4
const Eigen::Map< const Eigen::Vector4f, Eigen::Aligned > Vector4fMapConst
A base class for all pcl exceptions which inherits from std::runtime_error.
void computeTransformation(PointCloudSource &output, const Matrix4 &guess) override
Rigid transformation computation method with initial guess.
void setNumberOfThreads(unsigned int nr_threads=0)
Initialize the scheduler and set the number of threads to use.
void dfddf(const Vector6d &x, Vector6d &df, Matrix6d &ddf)
typename Eigen::Matrix< Scalar, 3, 3 > Matrix3
void applyState(Matrix4 &t, const Vector6d &x) const
compute transformation matrix from transformation matrix
typename Eigen::Matrix< Scalar, 3, 1 > Vector3
typename PointCloudSource::Ptr PointCloudSourcePtr
Eigen::Matrix< double, 6, 6 > Matrix6d
void setInputSource(const PointCloudSourceConstPtr &cloud)
Provide a pointer to the input source (e.g., the point cloud that we want to align to the target) ...
typename Eigen::AngleAxis< Scalar > AngleAxis
IndicesAllocator<> Indices
Type used for indices in PCL.
void computeCovariances(typename pcl::PointCloud< PointT >::ConstPtr cloud, const typename pcl::search::KdTree< PointT >::Ptr tree, MatricesVector &cloud_covariances)
compute points covariances matrices according to the K nearest neighbors.
Eigen::Matrix< double, 6, 1 > Vector6d
PointCloud represents the base class in PCL for storing collections of 3D points. ...
int nearestKSearch(const PointT &point, int k, Indices &k_indices, std::vector< float > &k_sqr_distances) const override
Search for the k-nearest neighbors for the given query point.
void estimateRigidTransformationNewton(const PointCloudSource &cloud_src, const pcl::Indices &indices_src, const PointCloudTarget &cloud_tgt, const pcl::Indices &indices_tgt, Matrix4 &transformation_matrix)
Estimate a rigid rotation transformation between a source and a target point cloud using an iterative...
An exception that is thrown when the number of correspondents is not equal to the minimum required...
An exception that is thrown when the non linear solver didn't converge.
void setNumberOfThreads(unsigned int nr_threads)
Set the number of threads to use.
void setInputTarget(const PointCloudTargetConstPtr &cloud)
Provide a pointer to the input target (e.g., the point cloud that we want to align the input source t...
shared_ptr< const PointCloud< PointT > > ConstPtr
std::vector< pcl::Correspondence, Eigen::aligned_allocator< pcl::Correspondence > > Correspondences
void setSearchMethodTarget(const KdTreePtr &tree, bool force_no_recompute=false)
Provide a pointer to the search object used to find correspondences in the target cloud...
A point structure representing Euclidean xyz coordinates, and the RGB color.
CorrespondenceEstimation represents a simple class for determining correspondences between target and...
BFGSSpace::Status minimizeOneStep(FVectorType &x)
void computeRDerivative(const Vector6d &x, const Eigen::Matrix3d &dCost_dR_T, Vector6d &g) const
Computes the derivative of the cost function w.r.t rotation angles.
BFGSSpace::Status minimizeInit(FVectorType &x)
optimization functor structure
GeneralizedIterativeClosestPoint is an ICP variant that implements the generalized iterative closest ...
void transformPointCloud(const pcl::PointCloud< PointT > &cloud_in, pcl::PointCloud< PointT > &cloud_out, const Eigen::Matrix< Scalar, 4, 4 > &transform, bool copy_all_fields)
Apply a rigid transform defined by a 4x4 matrix.
BFGS stands for Broyden–Fletcher–Goldfarb–Shanno (BFGS) method for solving unconstrained nonlinear...