80 if (!frame::has_points(*target) || (use_point_to_plane && !frame::has_normals(*target))) {
81 std::cerr <<
"error: target frame doesn't have required attributes for icp" << std::endl;
85 if (!frame::has_points(*source)) {
86 std::cerr <<
"error: source frame doesn't have required attributes for icp" << std::endl;
91 this->target_tree = target_tree;
93 this->target_tree.reset(
new KdTree2<TargetFrame>(target));
97template <
typename TargetFrame,
typename SourceFrame>
99 const gtsam::Pose3& fixed_target_pose,
100 gtsam::Key source_key,
101 const std::shared_ptr<const TargetFrame>& target,
102 const std::shared_ptr<const SourceFrame>& source,
103 bool use_point_to_plane)
104: gtsam_points::
IntegratedICPFactor_<TargetFrame, SourceFrame>(fixed_target_pose, source_key, target, source, nullptr, use_point_to_plane) {}
106template <
typename TargetFrame,
typename SourceFrame>
109template <
typename TargetFrame,
typename SourceFrame>
111 std::cout << s <<
"IntegratedICPFactor";
113 std::cout <<
"(" << keyFormatter(this->keys()[0]) <<
", " << keyFormatter(this->keys()[1]) <<
")" << std::endl;
115 std::cout <<
"(fixed, " << keyFormatter(this->keys()[0]) <<
")" << std::endl;
118 std::cout <<
"|target|=" << frame::size(*target) <<
"pts, |source|=" << frame::size(*source) <<
"pts" << std::endl;
119 std::cout <<
"num_threads=" << num_threads <<
", max_corr_dist=" << std::sqrt(max_correspondence_distance_sq) << std::endl;
122template <
typename TargetFrame,
typename SourceFrame>
124 return sizeof(*this) +
sizeof(long) * correspondences.capacity();
127template <
typename TargetFrame,
typename SourceFrame>
129 bool do_update =
true;
130 if (correspondences.size() == frame::size(*source) && (correspondence_update_tolerance_trans > 0.0 || correspondence_update_tolerance_rot > 0.0)) {
131 Eigen::Isometry3d diff = delta.inverse() * last_correspondence_point;
132 double diff_rot = Eigen::AngleAxisd(diff.linear()).angle();
133 double diff_trans = diff.translation().norm();
134 if (diff_rot < correspondence_update_tolerance_rot && diff_trans < correspondence_update_tolerance_trans) {
143 last_correspondence_point = delta;
144 correspondences.resize(frame::size(*source));
146 const auto perpoint_task = [&](
int i) {
147 Eigen::Vector4d pt = delta * frame::point(*source, i);
150 double k_sq_dist = -1;
151 size_t num_found = target_tree->knn_search(pt.data(), 1, &k_index, &k_sq_dist, max_correspondence_distance_sq);
153 if (num_found == 0 || k_sq_dist > max_correspondence_distance_sq) {
154 correspondences[i] = -1;
156 correspondences[i] = k_index;
160 if (is_omp_default() || num_threads == 1) {
161#pragma omp parallel for num_threads(num_threads) schedule(guided, 8)
162 for (
int i = 0; i < frame::size(*source); i++) {
166#ifdef GTSAM_POINTS_USE_TBB
167 tbb::parallel_for(tbb::blocked_range<int>(0, frame::size(*source), 8), [&](
const tbb::blocked_range<int>& range) {
168 for (
int i = range.begin(); i < range.end(); i++) {
173 std::cerr <<
"error: TBB is not available" << std::endl;
179template <
typename TargetFrame,
typename SourceFrame>
180double IntegratedICPFactor_<TargetFrame, SourceFrame>::evaluate(
181 const Eigen::Isometry3d& delta,
182 Eigen::Matrix<double, 6, 6>* H_target,
183 Eigen::Matrix<double, 6, 6>* H_source,
184 Eigen::Matrix<double, 6, 6>* H_target_source,
185 Eigen::Matrix<double, 6, 1>* b_target,
186 Eigen::Matrix<double, 6, 1>* b_source)
const {
188 if (correspondences.size() != frame::size(*source)) {
189 update_correspondences(delta);
192 const auto perpoint_task = [&](
194 Eigen::Matrix<double, 6, 6>* H_target,
195 Eigen::Matrix<double, 6, 6>* H_source,
196 Eigen::Matrix<double, 6, 6>* H_target_source,
197 Eigen::Matrix<double, 6, 1>* b_target,
198 Eigen::Matrix<double, 6, 1>* b_source) {
199 long target_index = correspondences[i];
200 if (target_index < 0) {
204 const auto& mean_A = frame::point(*source, i);
205 const auto& mean_B = frame::point(*target, target_index);
207 const Eigen::Vector4d transed_mean_A = delta * mean_A;
208 Eigen::Vector4d residual = mean_B - transed_mean_A;
210 if (use_point_to_plane) {
211 const auto& normal_B = frame::normal(*target, target_index);
212 residual = normal_B.array() * residual.array();
215 const double error = residual.transpose() * residual;
216 if (H_target ==
nullptr) {
220 Eigen::Matrix<double, 4, 6> J_target = Eigen::Matrix<double, 4, 6>::Zero();
221 J_target.block<3, 3>(0, 0) = -gtsam::SO3::Hat(transed_mean_A.head<3>());
222 J_target.block<3, 3>(0, 3) = Eigen::Matrix3d::Identity();
224 Eigen::Matrix<double, 4, 6> J_source = Eigen::Matrix<double, 4, 6>::Zero();
225 J_source.block<3, 3>(0, 0) = delta.linear() * gtsam::SO3::Hat(mean_A.template head<3>());
226 J_source.block<3, 3>(0, 3) = -delta.linear();
228 if (use_point_to_plane) {
229 const auto& normal_B = frame::normal(*target, target_index);
230 J_target = normal_B.asDiagonal() * J_target;
231 J_source = normal_B.asDiagonal() * J_source;
234 *H_target += J_target.transpose() * J_target;
235 *H_source += J_source.transpose() * J_source;
236 *H_target_source += J_target.transpose() * J_source;
237 *b_target += J_target.transpose() * residual;
238 *b_source += J_source.transpose() * residual;
243 if (is_omp_default() || num_threads == 1) {
244 return scan_matching_reduce_omp(perpoint_task, frame::size(*source), num_threads, H_target, H_source, H_target_source, b_target, b_source);
246 return scan_matching_reduce_tbb(perpoint_task, frame::size(*source), H_target, H_source, H_target_source, b_target, b_source);