86 if (target_cells_.getCentroids()->empty()) {
87 PCL_ERROR(
"[%s::computeTransformation] Voxel grid is not searchable!\n",
88 getClassName().c_str());
93 const double gauss_c1 = 10 * (1 - outlier_ratio_);
94 const double gauss_c2 = outlier_ratio_ / pow(resolution_, 3);
95 const double gauss_d3 = -std::log(gauss_c2);
96 gauss_d1_ = -std::log(gauss_c1 + gauss_c2) - gauss_d3;
98 -2 * std::log((-std::log(gauss_c1 * std::exp(-0.5) + gauss_c2) - gauss_d3) /
101 if (guess != Matrix4::Identity()) {
103 final_transformation_ = guess;
109 point_jacobian_.setZero();
110 point_jacobian_.block<3, 3>(0, 0).setIdentity();
111 point_hessian_.setZero();
113 Eigen::Transform<Scalar, 3, Eigen::Affine, Eigen::ColMajor> eig_transformation;
114 eig_transformation.matrix() = final_transformation_;
117 Eigen::Matrix<double, 6, 1> transform, score_gradient;
118 Vector3 init_translation = eig_transformation.translation();
119#if EIGEN_VERSION_AT_LEAST(5, 0, 0)
120 Vector3 init_rotation = eig_transformation.rotation().canonicalEulerAngles(0, 1, 2);
122 Vector3 init_rotation = eig_transformation.rotation().eulerAngles(0, 1, 2);
124 transform << init_translation.template cast<double>(),
125 init_rotation.template cast<double>();
127 Eigen::Matrix<double, 6, 6> hessian;
131 double score = computeDerivatives(score_gradient, hessian, output, transform);
133 while (!converged_) {
135 previous_transformation_ = transformation_;
139 Eigen::JacobiSVD<Eigen::Matrix<double, 6, 6>> sv(
140 hessian, Eigen::ComputeFullU | Eigen::ComputeFullV);
141#if EIGEN_VERSION_AT_LEAST(3, 4, 0)
142 if (sv.info() != Eigen::ComputationInfo::Success) {
143 trans_likelihood_ = score /
static_cast<double>(input_->size());
145 PCL_ERROR(
"[%s::computeTransformation] JacobiSVD on hessian failed!\n",
146 getClassName().c_str());
151 Eigen::Matrix<double, 6, 1> delta = sv.solve(-score_gradient);
154 double delta_norm = delta.norm();
156 if (delta_norm == 0 || std::isnan(delta_norm)) {
157 trans_likelihood_ = score /
static_cast<double>(input_->size());
158 converged_ = delta_norm == 0;
163 delta_norm = computeStepLengthMT(transform,
167 transformation_epsilon_ / 2,
175 convertTransform(delta, transformation_);
180 if (update_visualizer_)
183 const double cos_angle =
184 0.5 * (transformation_.template block<3, 3>(0, 0).trace() - 1);
185 const double translation_sqr =
186 transformation_.template block<3, 1>(0, 3).squaredNorm();
190 if (nr_iterations_ >= max_iterations_ ||
191 ((transformation_epsilon_ > 0 && translation_sqr <= transformation_epsilon_) &&
192 (transformation_rotation_epsilon_ > 0 &&
193 cos_angle >= transformation_rotation_epsilon_)) ||
194 ((transformation_epsilon_ <= 0) &&
195 (transformation_rotation_epsilon_ > 0 &&
196 cos_angle >= transformation_rotation_epsilon_)) ||
197 ((transformation_epsilon_ > 0 && translation_sqr <= transformation_epsilon_) &&
198 (transformation_rotation_epsilon_ <= 0))) {
206 trans_likelihood_ = score /
static_cast<double>(input_->size());
212 Eigen::Matrix<double, 6, 1>& score_gradient,
213 Eigen::Matrix<double, 6, 6>& hessian,
215 const Eigen::Matrix<double, 6, 1>& transform,
216 bool compute_hessian)
218 score_gradient.setZero();
223 computeAngleDerivatives(transform);
225 std::vector<TargetGridLeafConstPtr> neighborhood;
226 std::vector<float> distances;
228 Eigen::Matrix<double, 3, 6> point_jacobian = Eigen::Matrix<double, 3, 6>::Zero();
229 point_jacobian.block<3, 3>(0, 0).setIdentity();
230 Eigen::Matrix<double, 18, 6> point_hessian = Eigen::Matrix<double, 18, 6>::Zero();
232#pragma omp parallel num_threads(threads_) default(none) shared(score_gradient, hessian, trans_cloud, compute_hessian) firstprivate(neighborhood, distances, point_jacobian, point_hessian) reduction(+: score)
236 Eigen::Matrix<double, 6, 1> score_gradient_private =
237 Eigen::Matrix<double, 6, 1>::Zero();
238 Eigen::Matrix<double, 6, 6> hessian_private = Eigen::Matrix<double, 6, 6>::Zero();
239#pragma omp for schedule(dynamic, 32)
242 for (std::ptrdiff_t idx = 0; idx < static_cast<std::ptrdiff_t>(input_->size());
245 const auto& x_trans_pt = trans_cloud[idx];
248 neighborhood.clear();
249 switch (search_method_) {
252 target_cells_.radiusSearch(x_trans_pt, resolution_, neighborhood, distances);
255 target_cells_.getAllNeighborsAtPoint(x_trans_pt, neighborhood);
258 target_cells_.getNeighborhoodAtPoint(x_trans_pt, neighborhood);
261 target_cells_.getFaceNeighborsAtPoint(x_trans_pt, neighborhood);
264 target_cells_.getVoxelAtPoint(x_trans_pt, neighborhood);
269 const Eigen::Vector3d x = (*input_)[idx].getVector3fMap().template cast<double>();
270 const Eigen::Vector3d x_trans_position =
271 x_trans_pt.getVector3fMap().template cast<double>();
273 for (
const auto& cell : neighborhood) {
275 const Eigen::Vector3d x_trans = x_trans_position - cell->getMean();
278 const Eigen::Matrix3d c_inv = cell->getInverseCov();
282 computePointDerivatives(
283 x, point_jacobian, compute_hessian ? &point_hessian :
nullptr);
286 score += updateDerivatives(score_gradient_private,
291 compute_hessian ? &point_hessian :
nullptr);
294#pragma omp critical(accum_score_gradient)
296 score_gradient += score_gradient_private;
298#pragma omp critical(accum_hessian)
300 hessian += hessian_private;
309 const Eigen::Matrix<double, 6, 1>& transform,
bool compute_hessian)
312 const auto calculate_cos_sin = [](
double angle,
double& c,
double& s) {
313 if (std::abs(angle) < 10e-5) {
323 double cx, cy, cz, sx, sy, sz;
324 calculate_cos_sin(transform(3), cx, sx);
325 calculate_cos_sin(transform(4), cy, sy);
326 calculate_cos_sin(transform(5), cz, sz);
330 angular_jacobian_.setZero();
331 angular_jacobian_.row(0).noalias() = Eigen::Vector4d(
332 (-sx * sz + cx * sy * cz), (-sx * cz - cx * sy * sz), (-cx * cy), 1.0);
333 angular_jacobian_.row(1).noalias() = Eigen::Vector4d(
334 (cx * sz + sx * sy * cz), (cx * cz - sx * sy * sz), (-sx * cy), 1.0);
335 angular_jacobian_.row(2).noalias() =
336 Eigen::Vector4d((-sy * cz), sy * sz, cy, 1.0);
337 angular_jacobian_.row(3).noalias() =
338 Eigen::Vector4d(sx * cy * cz, (-sx * cy * sz), sx * sy, 1.0);
339 angular_jacobian_.row(4).noalias() =
340 Eigen::Vector4d((-cx * cy * cz), cx * cy * sz, (-cx * sy), 1.0);
341 angular_jacobian_.row(5).noalias() =
342 Eigen::Vector4d((-cy * sz), (-cy * cz), 0, 1.0);
343 angular_jacobian_.row(6).noalias() =
344 Eigen::Vector4d((cx * cz - sx * sy * sz), (-cx * sz - sx * sy * cz), 0, 1.0);
345 angular_jacobian_.row(7).noalias() =
346 Eigen::Vector4d((sx * cz + cx * sy * sz), (cx * sy * cz - sx * sz), 0, 1.0);
348 if (compute_hessian) {
351 angular_hessian_.setZero();
352 angular_hessian_.row(0).noalias() = Eigen::Vector4d(
353 (-cx * sz - sx * sy * cz), (-cx * cz + sx * sy * sz), sx * cy, 0.0f);
354 angular_hessian_.row(1).noalias() = Eigen::Vector4d(
355 (-sx * sz + cx * sy * cz), (-cx * sy * sz - sx * cz), (-cx * cy), 0.0f);
357 angular_hessian_.row(2).noalias() =
358 Eigen::Vector4d((cx * cy * cz), (-cx * cy * sz), (cx * sy), 0.0f);
359 angular_hessian_.row(3).noalias() =
360 Eigen::Vector4d((sx * cy * cz), (-sx * cy * sz), (sx * sy), 0.0f);
363 angular_hessian_.row(4).noalias() = Eigen::Vector4d(
364 (-sx * cz - cx * sy * sz), (sx * sz - cx * sy * cz), 0, 0.0f);
365 angular_hessian_.row(5).noalias() = Eigen::Vector4d(
366 (cx * cz - sx * sy * sz), (-sx * sy * cz - cx * sz), 0, 0.0f);
368 angular_hessian_.row(6).noalias() =
369 Eigen::Vector4d((-cy * cz), (cy * sz), (-sy), 0.0f);
370 angular_hessian_.row(7).noalias() =
371 Eigen::Vector4d((-sx * sy * cz), (sx * sy * sz), (sx * cy), 0.0f);
372 angular_hessian_.row(8).noalias() =
373 Eigen::Vector4d((cx * sy * cz), (-cx * sy * sz), (-cx * cy), 0.0f);
375 angular_hessian_.row(9).noalias() =
376 Eigen::Vector4d((sy * sz), (sy * cz), 0, 0.0f);
377 angular_hessian_.row(10).noalias() =
378 Eigen::Vector4d((-sx * cy * sz), (-sx * cy * cz), 0, 0.0f);
379 angular_hessian_.row(11).noalias() =
380 Eigen::Vector4d((cx * cy * sz), (cx * cy * cz), 0, 0.0f);
382 angular_hessian_.row(12).noalias() =
383 Eigen::Vector4d((-cy * cz), (cy * sz), 0, 0.0f);
384 angular_hessian_.row(13).noalias() = Eigen::Vector4d(
385 (-cx * sz - sx * sy * cz), (-cx * cz + sx * sy * sz), 0, 0.0f);
386 angular_hessian_.row(14).noalias() = Eigen::Vector4d(
387 (-sx * sz + cx * sy * cz), (-cx * sy * sz - sx * cz), 0, 0.0f);
394 const Eigen::Vector3d& x,
395 Eigen::Matrix<double, 3, 6>& point_jacobian,
396 Eigen::Matrix<double, 18, 6>* point_hessian)
const
401 Eigen::Matrix<double, 8, 1> point_angular_jacobian =
402 angular_jacobian_ * Eigen::Vector4d(x[0], x[1], x[2], 0.0);
403 point_jacobian(1, 3) = point_angular_jacobian[0];
404 point_jacobian(2, 3) = point_angular_jacobian[1];
405 point_jacobian(0, 4) = point_angular_jacobian[2];
406 point_jacobian(1, 4) = point_angular_jacobian[3];
407 point_jacobian(2, 4) = point_angular_jacobian[4];
408 point_jacobian(0, 5) = point_angular_jacobian[5];
409 point_jacobian(1, 5) = point_angular_jacobian[6];
410 point_jacobian(2, 5) = point_angular_jacobian[7];
413 Eigen::Matrix<double, 15, 1> point_angular_hessian =
414 angular_hessian_ * Eigen::Vector4d(x[0], x[1], x[2], 0.0);
417 const Eigen::Vector3d a(0, point_angular_hessian[0], point_angular_hessian[1]);
418 const Eigen::Vector3d b(0, point_angular_hessian[2], point_angular_hessian[3]);
419 const Eigen::Vector3d c(0, point_angular_hessian[4], point_angular_hessian[5]);
420 const Eigen::Vector3d d = point_angular_hessian.block<3, 1>(6, 0);
421 const Eigen::Vector3d e = point_angular_hessian.block<3, 1>(9, 0);
422 const Eigen::Vector3d f = point_angular_hessian.block<3, 1>(12, 0);
427 point_hessian->block<3, 1>(9, 3) = a;
428 point_hessian->block<3, 1>(12, 3) = b;
429 point_hessian->block<3, 1>(15, 3) = c;
430 point_hessian->block<3, 1>(9, 4) = b;
431 point_hessian->block<3, 1>(12, 4) = d;
432 point_hessian->block<3, 1>(15, 4) = e;
433 point_hessian->block<3, 1>(9, 5) = c;
434 point_hessian->block<3, 1>(12, 5) = e;
435 point_hessian->block<3, 1>(15, 5) = f;
451 Eigen::Matrix<double, 6, 1>& score_gradient,
452 Eigen::Matrix<double, 6, 6>& hessian,
453 const Eigen::Vector3d& x_trans,
454 const Eigen::Matrix3d& c_inv,
455 const Eigen::Matrix<double, 3, 6>& point_jacobian,
456 const Eigen::Matrix<double, 18, 6>* point_hessian)
const
459 double e_x_cov_x = std::exp(-gauss_d2_ * x_trans.dot(c_inv * x_trans) / 2);
462 const double score_inc = -gauss_d1_ * e_x_cov_x;
464 e_x_cov_x = gauss_d2_ * e_x_cov_x;
467 if (e_x_cov_x > 1 || e_x_cov_x < 0 || std::isnan(e_x_cov_x)) {
472 e_x_cov_x *= gauss_d1_;
474 for (
int i = 0; i < 6; i++) {
477 const Eigen::Vector3d cov_dxd_pi = c_inv * point_jacobian.col(i);
480 score_gradient(i) += x_trans.dot(cov_dxd_pi) * e_x_cov_x;
483 for (Eigen::Index j = 0; j < hessian.cols(); j++) {
486 e_x_cov_x * (-gauss_d2_ * x_trans.dot(cov_dxd_pi) *
487 x_trans.dot(c_inv * point_jacobian.col(j)) +
488 x_trans.dot(c_inv * point_hessian->block<3, 1>(3 * i, j)) +
489 point_jacobian.col(j).dot(cov_dxd_pi));
524 for (std::size_t idx = 0; idx < input_->size(); idx++) {
526 const auto& x_trans_pt = trans_cloud[idx];
528 std::vector<TargetGridLeafConstPtr> neighborhood;
529 std::vector<float> distances;
532 switch (search_method_) {
535 target_cells_.radiusSearch(x_trans_pt, resolution_, neighborhood, distances);
538 target_cells_.getAllNeighborsAtPoint(x_trans_pt, neighborhood);
541 target_cells_.getNeighborhoodAtPoint(x_trans_pt, neighborhood);
544 target_cells_.getFaceNeighborsAtPoint(x_trans_pt, neighborhood);
547 target_cells_.getVoxelAtPoint(x_trans_pt, neighborhood);
551 for (
const auto& cell : neighborhood) {
553 const auto& x_pt = (*input_)[idx];
554 const Eigen::Vector3d x = x_pt.getVector3fMap().template cast<double>();
557 const Eigen::Vector3d x_trans =
558 x_trans_pt.getVector3fMap().template cast<double>() - cell->getMean();
561 const Eigen::Matrix3d c_inv = cell->getInverseCov();
565 computePointDerivatives(x);
568 updateHessian(hessian, x_trans, c_inv);
576 Eigen::Matrix<double, 6, 6>& hessian,
577 const Eigen::Vector3d& x_trans,
578 const Eigen::Matrix3d& c_inv,
579 const Eigen::Matrix<double, 3, 6>& point_jacobian,
580 const Eigen::Matrix<double, 18, 6>& point_hessian)
const
584 gauss_d2_ * std::exp(-gauss_d2_ * x_trans.dot(c_inv * x_trans) / 2);
587 if (e_x_cov_x > 1 || e_x_cov_x < 0 || std::isnan(e_x_cov_x)) {
592 e_x_cov_x *= gauss_d1_;
594 for (
int i = 0; i < 6; i++) {
597 const Eigen::Vector3d cov_dxd_pi = c_inv * point_jacobian.col(i);
599 for (Eigen::Index j = 0; j < hessian.cols(); j++) {
602 e_x_cov_x * (-gauss_d2_ * x_trans.dot(cov_dxd_pi) *
603 x_trans.dot(c_inv * point_jacobian.col(j)) +
604 x_trans.dot(c_inv * point_hessian.block<3, 1>(3 * i, j)) +
605 point_jacobian.col(j).dot(cov_dxd_pi));
678 if (a_t == a_l && a_t == a_u) {
683 enum class EndpointsCondition { Case1, Case2, Case3, Case4 };
684 EndpointsCondition condition;
687 condition = EndpointsCondition::Case4;
689 else if (f_t > f_l) {
690 condition = EndpointsCondition::Case1;
692 else if (g_t * g_l < 0) {
693 condition = EndpointsCondition::Case2;
695 else if (std::fabs(g_t) <= std::fabs(g_l)) {
696 condition = EndpointsCondition::Case3;
699 condition = EndpointsCondition::Case4;
703 case EndpointsCondition::Case1: {
706 const double z = 3 * (f_t - f_l) / (a_t - a_l) - g_t - g_l;
707 const double w = std::sqrt(z * z - g_t * g_l);
709 const double a_c = a_l + (a_t - a_l) * (w - g_l - z) / (g_t - g_l + 2 * w);
714 a_l - 0.5 * (a_l - a_t) * g_l / (g_l - (f_l - f_t) / (a_l - a_t));
716 if (std::fabs(a_c - a_l) < std::fabs(a_q - a_l)) {
719 return 0.5 * (a_q + a_c);
722 case EndpointsCondition::Case2: {
725 const double z = 3 * (f_t - f_l) / (a_t - a_l) - g_t - g_l;
726 const double w = std::sqrt(z * z - g_t * g_l);
728 const double a_c = a_l + (a_t - a_l) * (w - g_l - z) / (g_t - g_l + 2 * w);
732 const double a_s = a_l - (a_l - a_t) / (g_l - g_t) * g_l;
734 if (std::fabs(a_c - a_t) >= std::fabs(a_s - a_t)) {
740 case EndpointsCondition::Case3: {
743 const double z = 3 * (f_t - f_l) / (a_t - a_l) - g_t - g_l;
744 const double w = std::sqrt(z * z - g_t * g_l);
745 const double a_c = a_l + (a_t - a_l) * (w - g_l - z) / (g_t - g_l + 2 * w);
749 const double a_s = a_l - (a_l - a_t) / (g_l - g_t) * g_l;
753 if (std::fabs(a_c - a_t) < std::fabs(a_s - a_t)) {
761 return std::min(a_t + 0.66 * (a_u - a_t), a_t_next);
763 return std::max(a_t + 0.66 * (a_u - a_t), a_t_next);
767 case EndpointsCondition::Case4: {
770 const double z = 3 * (f_t - f_u) / (a_t - a_u) - g_t - g_u;
771 const double w = std::sqrt(z * z - g_t * g_u);
773 return a_u + (a_t - a_u) * (w - g_u - z) / (g_t - g_u + 2 * w);
781 const Eigen::Matrix<double, 6, 1>& x,
782 Eigen::Matrix<double, 6, 1>& step_dir,
787 Eigen::Matrix<double, 6, 1>& score_gradient,
788 Eigen::Matrix<double, 6, 6>& hessian,
792 const double phi_0 = -score;
794 double d_phi_0 = -(score_gradient.dot(step_dir));
808 constexpr int max_step_iterations = 10;
809 int step_iterations = 0;
812 constexpr double mu = 1.e-4;
814 constexpr double nu = 0.9;
817 double a_l = 0, a_u = 0;
821 double f_l = auxilaryFunction_PsiMT(a_l, phi_0, phi_0, d_phi_0, mu);
822 double g_l = auxilaryFunction_dPsiMT(d_phi_0, d_phi_0, mu);
824 double f_u = auxilaryFunction_PsiMT(a_u, phi_0, phi_0, d_phi_0, mu);
825 double g_u = auxilaryFunction_dPsiMT(d_phi_0, d_phi_0, mu);
829 bool interval_converged = (step_max - step_min) < 0, open_interval =
true;
831 double a_t = step_init;
832 a_t = std::min(a_t, step_max);
833 a_t = std::max(a_t, step_min);
835 Eigen::Matrix<double, 6, 1> x_t = x + step_dir * a_t;
838 convertTransform(x_t, final_transformation_);
847 score = computeDerivatives(score_gradient, hessian, trans_cloud, x_t,
true);
850 double phi_t = -score;
852 double d_phi_t = -(score_gradient.dot(step_dir));
855 double psi_t = auxilaryFunction_PsiMT(a_t, phi_t, phi_0, d_phi_0, mu);
857 double d_psi_t = auxilaryFunction_dPsiMT(d_phi_t, d_phi_0, mu);
862 while (!interval_converged && step_iterations < max_step_iterations &&
864 d_phi_t > -nu * d_phi_0 )) {
867 a_t = trialValueSelectionMT(a_l, f_l, g_l, a_u, f_u, g_u, a_t, psi_t, d_psi_t);
870 a_t = trialValueSelectionMT(a_l, f_l, g_l, a_u, f_u, g_u, a_t, phi_t, d_phi_t);
873 a_t = std::min(a_t, step_max);
874 a_t = std::max(a_t, step_min);
876 x_t = x + step_dir * a_t;
879 convertTransform(x_t, final_transformation_);
886 score = computeDerivatives(score_gradient, hessian, trans_cloud, x_t,
false);
891 d_phi_t = -(score_gradient.dot(step_dir));
894 psi_t = auxilaryFunction_PsiMT(a_t, phi_t, phi_0, d_phi_0, mu);
896 d_psi_t = auxilaryFunction_dPsiMT(d_phi_t, d_phi_0, mu);
899 if (open_interval && (psi_t <= 0 && d_psi_t >= 0)) {
900 open_interval =
false;
903 f_l += phi_0 - mu * d_phi_0 * a_l;
907 f_u += phi_0 - mu * d_phi_0 * a_u;
914 updateIntervalMT(a_l, f_l, g_l, a_u, f_u, g_u, a_t, psi_t, d_psi_t);
920 updateIntervalMT(a_l, f_l, g_l, a_u, f_u, g_u, a_t, phi_t, d_phi_t);
929 if (step_iterations) {
930 computeHessian(hessian, trans_cloud);