4#include <gtsam_points/factors/integrated_ct_gicp_factor.hpp>
6#include <gtsam/linear/HessianFactor.h>
7#include <gtsam_points/config.hpp>
8#include <gtsam_points/ann/nearest_neighbor_search.hpp>
9#include <gtsam_points/util/parallelism.hpp>
10#include <gtsam_points/factors/impl/scan_matching_reduction.hpp>
12#ifdef GTSAM_POINTS_USE_TBB
13#include <tbb/parallel_for.h>
16namespace gtsam_points {
18template <
typename TargetFrame,
typename SourceFrame>
20 gtsam::Key source_t0_key,
21 gtsam::Key source_t1_key,
22 const std::shared_ptr<const TargetFrame>& target,
23 const std::shared_ptr<const SourceFrame>& source,
24 const std::shared_ptr<const NearestNeighborSearch>& target_tree)
27 if (!frame::has_points(*target) || !frame::has_covs(*target)) {
28 std::cerr <<
"error: target frame doesn't have required attributes for ct_gicp" << std::endl;
32 if (!frame::has_points(*source) || !frame::has_covs(*source)) {
33 std::cerr <<
"error: source frame doesn't have required attributes for ct_gicp" << std::endl;
38template <
typename TargetFrame,
typename SourceFrame>
40 gtsam::Key source_t0_key,
41 gtsam::Key source_t1_key,
42 const std::shared_ptr<const TargetFrame>& target,
43 const std::shared_ptr<const SourceFrame>& source)
46template <
typename TargetFrame,
typename SourceFrame>
49template <
typename TargetFrame,
typename SourceFrame>
51 std::cout << s <<
"IntegratedCT_GICPFactor";
52 std::cout <<
"(" << keyFormatter(this->keys()[0]) <<
", " << keyFormatter(this->keys()[1]) <<
")" << std::endl;
54 std::cout <<
"|target|=" << frame::size(*this->target) <<
"pts, |source|=" << frame::size(*this->source) <<
"pts" << std::endl;
55 std::cout <<
"num_threads=" << this->num_threads <<
", max_corr_dist=" << std::sqrt(this->max_correspondence_distance_sq) << std::endl;
58template <
typename TargetFrame,
typename SourceFrame>
63template <
typename TargetFrame,
typename SourceFrame>
64double IntegratedCT_GICPFactor_<TargetFrame, SourceFrame>::error(
const gtsam::Values& values)
const {
65 this->update_poses(values);
66 if (this->correspondences.size() != frame::size(*this->source)) {
67 this->update_correspondences();
70 const auto perpoint_task = [&](
72 Eigen::Matrix<double, 6, 6>* H_target,
73 Eigen::Matrix<double, 6, 6>* H_source,
74 Eigen::Matrix<double, 6, 6>* H_target_source,
75 Eigen::Matrix<double, 6, 1>* b_target,
76 Eigen::Matrix<double, 6, 1>* b_source) {
77 const long target_index = this->correspondences[i];
78 if (target_index < 0) {
82 const int time_index = this->time_indices[i];
83 const Eigen::Isometry3d pose(this->source_poses[time_index].matrix());
85 const auto& source_pt = frame::point(*this->source, i);
86 const auto& target_pt = frame::point(*this->target, target_index);
88 const Eigen::Vector4d transed_source_pt = pose * source_pt;
89 const Eigen::Vector4d residual = transed_source_pt - target_pt;
90 const double error = residual.transpose() * mahalanobis[i] * residual;
95 if (is_omp_default() || this->num_threads == 1) {
96 return scan_matching_reduce_omp(perpoint_task, frame::size(*this->source), this->num_threads,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
98 return scan_matching_reduce_tbb(perpoint_task, frame::size(*this->source),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
102template <
typename TargetFrame,
typename SourceFrame>
103gtsam::GaussianFactor::shared_ptr IntegratedCT_GICPFactor_<TargetFrame, SourceFrame>::linearize(
const gtsam::Values& values)
const {
104 this->update_poses(values);
105 this->update_correspondences();
107 const auto perpoint_task = [&](
109 Eigen::Matrix<double, 6, 6>* H_00,
110 Eigen::Matrix<double, 6, 6>* H_11,
111 Eigen::Matrix<double, 6, 6>* H_01,
112 Eigen::Matrix<double, 6, 1>* b_0,
113 Eigen::Matrix<double, 6, 1>* b_1) {
114 const long target_index = this->correspondences[i];
115 if (target_index < 0) {
119 const int time_index = this->time_indices[i];
121 const Eigen::Isometry3d pose(this->source_poses[time_index].matrix());
122 const auto& H_pose_0 = this->pose_derivatives_t0[time_index];
123 const auto& H_pose_1 = this->pose_derivatives_t1[time_index];
125 const auto& source_pt = frame::point(*this->source, i);
126 const auto& target_pt = frame::point(*this->target, target_index);
128 gtsam::Matrix46 H_transed_pose = gtsam::Matrix46::Zero();
129 H_transed_pose.block<3, 3>(0, 0) = pose.linear() * -gtsam::SO3::Hat(source_pt.template head<3>());
130 H_transed_pose.block<3, 3>(0, 3) = pose.linear();
131 const Eigen::Vector4d transed_source_pt = pose * source_pt;
133 const auto& H_residual_pose = H_transed_pose;
134 const Eigen::Vector4d residual = transed_source_pt - target_pt;
136 const gtsam::Matrix46 H_0 = H_residual_pose * H_pose_0;
137 const gtsam::Matrix46 H_1 = H_residual_pose * H_pose_1;
139 const gtsam::Vector4 mahalanobis_residual = mahalanobis[i] * residual;
140 const gtsam::Matrix64 H_0_mahalanobis = H_0.transpose() * mahalanobis[i];
141 const gtsam::Matrix64 H_1_mahalanobis = H_1.transpose() * mahalanobis[i];
143 const double error = residual.transpose() * mahalanobis_residual;
144 *H_00 += H_0_mahalanobis * H_0;
145 *H_11 += H_1_mahalanobis * H_1;
146 *H_01 += H_0_mahalanobis * H_1;
147 *b_0 += H_0.transpose() * mahalanobis_residual;
148 *b_1 += H_1.transpose() * mahalanobis_residual;
160 if (is_omp_default() || this->num_threads == 1) {
161 error = scan_matching_reduce_omp(perpoint_task, frame::size(*this->source), this->num_threads, &H_00, &H_11, &H_01, &b_0, &b_1);
163 error = scan_matching_reduce_tbb(perpoint_task, frame::size(*this->source), &H_00, &H_11, &H_01, &b_0, &b_1);
166 auto factor = gtsam::HessianFactor::shared_ptr(
new gtsam::HessianFactor(this->keys_[0], this->keys_[1], H_00, H_01, -b_0, H_11, -b_1, error));
170template <
typename TargetFrame,
typename SourceFrame>
171void IntegratedCT_GICPFactor_<TargetFrame, SourceFrame>::update_correspondences()
const {
172 this->correspondences.resize(frame::size(*this->source));
173 this->mahalanobis.resize(frame::size(*this->source));
175 const auto perpoint_task = [&](
int i) {
176 const int time_index = this->time_indices[i];
177 const Eigen::Matrix4d pose = this->source_poses[time_index].matrix();
179 const auto& pt = frame::point(*this->source, i);
180 const Eigen::Vector4d transed_pt = pose * pt;
183 double k_sq_dist = std::numeric_limits<double>::max();
184 size_t num_found = this->target_tree->knn_search(transed_pt.data(), 1, &k_index, &k_sq_dist, this->max_correspondence_distance_sq);
186 if (num_found == 0 || k_sq_dist > this->max_correspondence_distance_sq) {
187 this->correspondences[i] = -1;
188 this->mahalanobis[i].setZero();
190 this->correspondences[i] = k_index;
192 const long target_index = this->correspondences[i];
193 const auto& cov_A = frame::cov(*this->source, i);
194 const auto& cov_B = frame::cov(*this->target, target_index);
195 const Eigen::Matrix4d RCR = (cov_B + pose * cov_A * pose.transpose());
197 mahalanobis[i].setZero();
198 mahalanobis[i].template block<3, 3>(0, 0) = RCR.block<3, 3>(0, 0).inverse();
202 if (is_omp_default() || this->num_threads == 1) {
203#pragma omp parallel for num_threads(this->num_threads) schedule(guided, 8)
204 for (
int i = 0; i < frame::size(*this->source); i++) {
208#ifdef GTSAM_POINTS_USE_TBB
209 tbb::parallel_for(tbb::blocked_range<int>(0, frame::size(*this->source), 8), [&](
const tbb::blocked_range<int>& range) {
210 for (
int i = range.begin(); i < range.end(); i++) {
215 std::cerr <<
"error: TBB is not available" << std::endl;
Continuous Time ICP with GICP's D2D cost Bellenbach et al., "CT-ICP: Real-time Elastic LiDAR Odometry...
Definition integrated_ct_gicp_factor.hpp:17
IntegratedCT_GICPFactor_(gtsam::Key source_t0_key, gtsam::Key source_t1_key, const std::shared_ptr< const TargetFrame > &target, const std::shared_ptr< const SourceFrame > &source, const std::shared_ptr< const NearestNeighborSearch > &target_tree)
Constructor.
Definition integrated_ct_gicp_factor_impl.hpp:19
virtual void print(const std::string &s="", const gtsam::KeyFormatter &keyFormatter=gtsam::DefaultKeyFormatter) const override
Print the factor information.
Definition integrated_ct_gicp_factor_impl.hpp:50
Continuous Time ICP Factor Bellenbach et al., "CT-ICP: Real-time Elastic LiDAR Odometry with Loop Clo...
Definition integrated_ct_icp_factor.hpp:21