48 time_table.push_back(t);
50 time_indices.push_back(time_table.size() - 1);
53 for (
auto& t : time_table) {
54 t = t / std::max(1e-9, time_table.back());
58 this->target_tree = target_tree;
60 this->target_tree.reset(
new KdTree2<TargetFrame>(target));
64template <
typename TargetFrame,
typename SourceFrame>
66 gtsam::Key source_t0_key,
67 gtsam::Key source_t1_key,
68 const std::shared_ptr<const TargetFrame>& target,
69 const std::shared_ptr<const SourceFrame>& source)
72template <
typename TargetFrame,
typename SourceFrame>
75template <
typename TargetFrame,
typename SourceFrame>
77 std::cout << s <<
"IntegratedCT_ICPFactor";
78 std::cout <<
"(" << keyFormatter(this->keys()[0]) <<
", " << keyFormatter(this->keys()[1]) <<
")" << std::endl;
80 std::cout <<
"|target|=" << frame::size(*target) <<
"pts, |source|=" << frame::size(*source) <<
"pts" << std::endl;
81 std::cout <<
"num_threads=" << num_threads <<
", max_corr_dist=" << std::sqrt(max_correspondence_distance_sq) << std::endl;
84template <
typename TargetFrame,
typename SourceFrame>
86 return sizeof(*this) +
sizeof(double) * time_table.capacity() +
sizeof(gtsam::Pose3) * source_poses.capacity() +
87 sizeof(gtsam::Matrix6) * pose_derivatives_t0.capacity() +
sizeof(gtsam::Matrix6) * pose_derivatives_t1.capacity() +
88 sizeof(long) * correspondences.capacity() +
sizeof(int) * time_indices.capacity();
91template <
typename TargetFrame,
typename SourceFrame>
92double IntegratedCT_ICPFactor_<TargetFrame, SourceFrame>::error(
const gtsam::Values& values)
const {
94 if (correspondences.size() != frame::size(*source)) {
95 update_correspondences();
98 const auto perpoint_task = [&](
100 Eigen::Matrix<double, 6, 6>* H_target,
101 Eigen::Matrix<double, 6, 6>* H_source,
102 Eigen::Matrix<double, 6, 6>* H_target_source,
103 Eigen::Matrix<double, 6, 1>* b_target,
104 Eigen::Matrix<double, 6, 1>* b_source) {
105 const long target_index = correspondences[i];
106 if (target_index < 0) {
110 const int time_index = time_indices[i];
111 const auto& pose = source_poses[time_index];
113 const auto& source_pt = frame::point(*source, i);
114 const auto& target_pt = frame::point(*target, target_index);
115 const auto& target_normal = frame::normal(*target, target_index);
117 gtsam::Point3 transed_source_pt = pose.transformFrom(source_pt.template head<3>().eval());
118 gtsam::Point3 residual = transed_source_pt - target_pt.template head<3>();
119 double error = gtsam::dot(residual, target_normal.template head<3>());
121 return error * error;
124 if (is_omp_default() || num_threads == 1) {
125 return scan_matching_reduce_omp(perpoint_task, frame::size(*this->source), this->num_threads,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
127 return scan_matching_reduce_tbb(perpoint_task, frame::size(*this->source),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
131template <
typename TargetFrame,
typename SourceFrame>
132gtsam::GaussianFactor::shared_ptr IntegratedCT_ICPFactor_<TargetFrame, SourceFrame>::linearize(
const gtsam::Values& values)
const {
133 if (!frame::has_normals(*target)) {
134 std::cerr <<
"error: target cloud doesn't have normals!!" << std::endl;
138 update_poses(values);
139 update_correspondences();
141 const auto perpoint_task = [&](
143 Eigen::Matrix<double, 6, 6>* H_00,
144 Eigen::Matrix<double, 6, 6>* H_11,
145 Eigen::Matrix<double, 6, 6>* H_01,
146 Eigen::Matrix<double, 6, 1>* b_0,
147 Eigen::Matrix<double, 6, 1>* b_1) {
148 const long target_index = correspondences[i];
149 if (target_index < 0) {
153 const int time_index = time_indices[i];
155 const auto& pose = source_poses[time_index];
156 const auto& H_pose_0 = pose_derivatives_t0[time_index];
157 const auto& H_pose_1 = pose_derivatives_t1[time_index];
159 const auto& source_pt = frame::point(*source, i);
160 const auto& target_pt = frame::point(*target, target_index);
161 const auto& target_normal = frame::normal(*target, target_index);
163 gtsam::Matrix36 H_transed_pose;
164 gtsam::Point3 transed_source_pt = pose.transformFrom(source_pt.template head<3>(), H_transed_pose);
166 gtsam::Point3 residual = transed_source_pt - target_pt.template head<3>();
168 gtsam::Matrix13 H_error_transed;
169 double error = gtsam::dot(residual, target_normal.template head<3>(), H_error_transed);
171 gtsam::Matrix16 H_error_pose = H_error_transed * H_transed_pose;
172 gtsam::Matrix16 H_0 = H_error_pose * H_pose_0;
173 gtsam::Matrix16 H_1 = H_error_pose * H_pose_1;
175 *H_00 += H_0.transpose() * H_0;
176 *H_11 += H_1.transpose() * H_1;
177 *H_01 += H_0.transpose() * H_1;
178 *b_0 += H_0.transpose() * error;
179 *b_1 += H_1.transpose() * error;
181 return error * error;
191 if (is_omp_default() || num_threads == 1) {
192 error = scan_matching_reduce_omp(perpoint_task, frame::size(*this->source), this->num_threads, &H_00, &H_11, &H_01, &b_0, &b_1);
194 error = scan_matching_reduce_tbb(perpoint_task, frame::size(*this->source), &H_00, &H_11, &H_01, &b_0, &b_1);
197 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));
201template <
typename TargetFrame,
typename SourceFrame>
202void IntegratedCT_ICPFactor_<TargetFrame, SourceFrame>::update_poses(
const gtsam::Values& values)
const {
203 gtsam::Pose3 pose0 = values.at<gtsam::Pose3>(keys_[0]);
204 gtsam::Pose3 pose1 = values.at<gtsam::Pose3>(keys_[1]);
206 gtsam::Matrix6 H_delta_0, H_delta_1;
207 gtsam::Pose3 delta = pose0.between(pose1, H_delta_0, H_delta_1);
209 gtsam::Matrix6 H_vel_delta;
210 gtsam::Vector6 vel = gtsam::Pose3::Logmap(delta, H_vel_delta);
212 source_poses.resize(time_table.size());
213 pose_derivatives_t0.resize(time_table.size());
214 pose_derivatives_t1.resize(time_table.size());
216 const auto task = [&](
int i) {
217 const double t = time_table[i];
219 gtsam::Matrix6 H_inc_vel;
220 gtsam::Pose3 inc = gtsam::Pose3::Expmap(t * vel, H_inc_vel);
222 gtsam::Matrix6 H_pose_0_a, H_pose_inc;
223 source_poses[i] = pose0.compose(inc, H_pose_0_a, H_pose_inc);
225 gtsam::Matrix6 H_pose_delta = H_pose_inc * H_inc_vel * t * H_vel_delta;
227 pose_derivatives_t0[i] = H_pose_0_a + H_pose_delta * H_delta_0;
228 pose_derivatives_t1[i] = H_pose_delta * H_delta_1;
231 if (is_omp_default() || num_threads == 1) {
232#pragma omp parallel for num_threads(this->num_threads) schedule(guided, 32)
233 for (
int i = 0; i < time_table.size(); i++) {
237#ifdef GTSAM_POINTS_USE_TBB
238 tbb::parallel_for(tbb::blocked_range<int>(0, time_table.size(), 32), [&](
const tbb::blocked_range<int>& range) {
239 for (int i = range.begin(); i < range.end(); i++) {
244 std::cerr <<
"error: TBB is not available" << std::endl;
250template <
typename TargetFrame,
typename SourceFrame>
251void IntegratedCT_ICPFactor_<TargetFrame, SourceFrame>::update_correspondences()
const {
252 correspondences.resize(frame::size(*source));
254 const auto perpoint_task = [&](
int i) {
255 const int time_index = time_indices[i];
257 const auto& pt = frame::point(*source, i);
258 gtsam::Point3 transed_pt = source_poses[time_index] * pt.template head<3>();
261 double k_sq_dist = -1;
262 size_t num_found = target_tree->knn_search(transed_pt.data(), 1, &k_index, &k_sq_dist, max_correspondence_distance_sq);
264 if (num_found == 0 || k_sq_dist > max_correspondence_distance_sq) {
265 correspondences[i] = -1;
267 correspondences[i] = k_index;
271 if (is_omp_default() || num_threads == 1) {
272#pragma omp parallel for num_threads(this->num_threads) schedule(guided, 8)
273 for (
int i = 0; i < frame::size(*this->source); i++) {
277#ifdef GTSAM_POINTS_USE_TBB
278 tbb::parallel_for(tbb::blocked_range<int>(0, frame::size(*this->source), 8), [&](
const tbb::blocked_range<int>& range) {
279 for (
int i = range.begin(); i < range.end(); i++) {
284 std::cerr <<
"error: TBB is not available" << std::endl;
290template <
typename TargetFrame,
typename SourceFrame>
291std::vector<Eigen::Vector4d> IntegratedCT_ICPFactor_<TargetFrame, SourceFrame>::deskewed_source_points(
const gtsam::Values& values,
bool local) {
292 update_poses(values);
295 for (
auto& pose : source_poses) {
296 pose = values.at<gtsam::Pose3>(keys_[0]).inverse() * pose;
300 std::vector<Eigen::Vector4d> deskewed(frame::size(*source));
301 for (
int i = 0; i < frame::size(*source); i++) {
302 const int time_index = time_indices[i];
303 const auto& pose = source_poses[time_index];
304 deskewed[i] = pose.matrix() * (Eigen::Vector4d() << frame::point(*source, i).template head<3>(), 1.0).finished();