18 #ifndef POINT_CLOUD_COMMON_POINT_TO_PLANE_ICP_H_
19 #define POINT_CLOUD_COMMON_POINT_TO_PLANE_ICP_H_
29 #include <boost/optional.hpp>
36 #include <pcl/point_cloud.h>
37 #include <pcl/point_types.h>
38 #include <pcl/registration/correspondence_rejection_median_distance.h>
39 #include <pcl/registration/icp.h>
44 template <
typename Po
intType>
49 const typename pcl::PointCloud<PointType>::Ptr source_cloud_with_normals,
50 const typename pcl::PointCloud<PointType>::Ptr target_cloud_with_normals,
51 const Eigen::Isometry3d& initial_target_T_source_estimate = Eigen::Isometry3d::Identity());
55 boost::optional<localization_common::PoseWithCovariance> RunPointToPlaneICP(
56 const typename pcl::PointCloud<PointType>::Ptr source_cloud_with_normals,
57 const typename pcl::PointCloud<PointType>::Ptr target_cloud_with_normals,
58 const Eigen::Isometry3d& initial_target_T_source_estimate = Eigen::Isometry3d::Identity());
59 boost::optional<localization_common::PoseWithCovariance> RunCoarseToFinePointToPlaneICP(
60 const typename pcl::PointCloud<PointType>::Ptr source_cloud_with_normals,
61 const typename pcl::PointCloud<PointType>::Ptr target_cloud_with_normals,
62 const Eigen::Isometry3d& initial_target_T_source_estimate = Eigen::Isometry3d::Identity());
63 boost::optional<localization_common::PoseWithCovariance> RunDownsampledPointToPlaneICP(
64 const typename pcl::PointCloud<PointType>::Ptr source_cloud_with_normals,
65 const typename pcl::PointCloud<PointType>::Ptr target_cloud_with_normals,
const double leaf_size,
66 const Eigen::Isometry3d& initial_target_T_source_estimate = Eigen::Isometry3d::Identity());
67 void SaveCorrespondences(
const pcl::IterativeClosestPointWithNormals<PointType, PointType>& icp,
68 const typename pcl::PointCloud<PointType>::Ptr source_cloud,
69 const typename pcl::PointCloud<PointType>::Ptr source_cloud_transformed);
70 boost::optional<ICPCorrespondences> correspondences_;
75 template <
typename Po
intType>
78 template <
typename Po
intType>
80 const typename pcl::PointCloud<PointType>::Ptr source_cloud_with_normals,
81 const typename pcl::PointCloud<PointType>::Ptr target_cloud_with_normals,
83 if (params_.coarse_to_fine) {
84 return RunCoarseToFinePointToPlaneICP(source_cloud_with_normals, target_cloud_with_normals,
85 initial_target_T_source_estimate);
87 return RunPointToPlaneICP(source_cloud_with_normals, target_cloud_with_normals, initial_target_T_source_estimate);
91 template <
typename Po
intType>
93 const typename pcl::PointCloud<PointType>::Ptr source_cloud_with_normals,
94 const typename pcl::PointCloud<PointType>::Ptr target_cloud_with_normals,
96 pcl::IterativeClosestPointWithNormals<PointType, PointType> icp;
98 if (params_.symmetric_objective) {
99 auto symmetric_transformation_estimation =
100 boost::make_shared<pcl::registration::TransformationEstimationSymmetricPointToPlaneLLS2<PointType, PointType>>();
101 symmetric_transformation_estimation->setEnforceSameDirectionNormals(params_.enforce_same_direction_normals);
102 icp.transformation_estimation_ = symmetric_transformation_estimation;
105 if (params_.correspondence_rejector_surface_normal) {
108 correspondence_rejector_surface_normal->initializeDataContainer();
109 correspondence_rejector_surface_normal->setThreshold(params_.correspondence_rejector_surface_normal_threshold);
110 correspondence_rejector_surface_normal->setInputNormals(source_cloud_with_normals);
111 correspondence_rejector_surface_normal->setTargetNormals(target_cloud_with_normals);
112 icp.addCorrespondenceRejector(correspondence_rejector_surface_normal);
115 if (params_.correspondence_rejector_median_distance) {
116 pcl::registration::CorrespondenceRejectorMedianDistance::Ptr correspondence_rejector_median_distance(
117 new pcl::registration::CorrespondenceRejectorMedianDistance());
118 correspondence_rejector_median_distance->setMedianFactor(params_.correspondence_rejector_median_distance_factor);
119 icp.addCorrespondenceRejector(correspondence_rejector_median_distance);
122 icp.setInputSource(source_cloud_with_normals);
123 icp.setInputTarget(target_cloud_with_normals);
124 icp.setMaximumIterations(params_.max_iterations);
125 typename pcl::PointCloud<PointType>::Ptr result(
new pcl::PointCloud<PointType>);
126 icp.align(*result, initial_target_T_source_estimate.matrix().cast<
float>());
128 if (!icp.hasConverged()) {
129 LogError(
"Icp: Failed to converge.");
133 if (params_.use_fitness_threshold_rejection) {
134 const double fitness_score = icp.getFitnessScore();
135 if (fitness_score > params_.fitness_threshold) {
136 LogError(
"Icp: Fitness score too large: " << fitness_score <<
".");
142 Eigen::Isometry3f(icp.getFinalTransformation().matrix()).cast<
double>());
143 SaveCorrespondences(icp, source_cloud_with_normals, result);
144 const auto covariance =
PointToPlaneCovariance(correspondences_->source_points, correspondences_->target_normals,
145 estimated_target_T_source);
147 LogError(
"Icp: Failed to get covariance.");
153 template <
typename Po
intType>
154 boost::optional<localization_common::PoseWithCovariance> PointToPlaneICP<PointType>::RunDownsampledPointToPlaneICP(
155 const typename pcl::PointCloud<PointType>::Ptr source_cloud_with_normals,
156 const typename pcl::PointCloud<PointType>::Ptr target_cloud_with_normals,
const double leaf_size,
158 typename pcl::PointCloud<PointType>::Ptr downsampled_source_cloud_with_normals =
159 DownsamplePointCloud<PointType>(source_cloud_with_normals, leaf_size);
160 typename pcl::PointCloud<PointType>::Ptr downsampled_target_cloud_with_normals =
161 DownsamplePointCloud<PointType>(target_cloud_with_normals, leaf_size);
162 return RunPointToPlaneICP(downsampled_source_cloud_with_normals, downsampled_target_cloud_with_normals,
163 initial_target_T_source_estimate);
166 template <
typename Po
intType>
167 boost::optional<localization_common::PoseWithCovariance> PointToPlaneICP<PointType>::RunCoarseToFinePointToPlaneICP(
168 const typename pcl::PointCloud<PointType>::Ptr source_cloud_with_normals,
169 const typename pcl::PointCloud<PointType>::Ptr target_cloud_with_normals,
171 boost::optional<localization_common::PoseWithCovariance> estimated_target_T_source =
173 for (
int i = 0; i < params_.num_coarse_to_fine_levels; ++i) {
175 if (i == params_.num_coarse_to_fine_levels - 1 && !params_.downsample_last_coarse_to_fine_iteration) {
176 estimated_target_T_source =
177 RunPointToPlaneICP(source_cloud_with_normals, target_cloud_with_normals, estimated_target_T_source->pose);
179 const double leaf_size =
180 static_cast<double>(params_.num_coarse_to_fine_levels - i) * params_.coarse_to_fine_final_leaf_size;
181 estimated_target_T_source = RunDownsampledPointToPlaneICP(source_cloud_with_normals, target_cloud_with_normals,
182 leaf_size, estimated_target_T_source->pose);
184 if (!estimated_target_T_source) {
185 LogWarning(
"RunCoarseToFinePointToPlaneICP: Failed to get relative transform.");
189 return estimated_target_T_source;
192 template <
typename Po
intType>
193 void PointToPlaneICP<PointType>::SaveCorrespondences(
194 const pcl::IterativeClosestPointWithNormals<PointType, PointType>& icp,
195 const typename pcl::PointCloud<PointType>::Ptr source_cloud,
196 const typename pcl::PointCloud<PointType>::Ptr source_cloud_transformed) {
197 icp.correspondence_estimation_->setInputSource(source_cloud_transformed);
198 pcl::Correspondences pcl_correspondences;
200 icp.correspondence_estimation_->determineCorrespondences(pcl_correspondences, icp.corr_dist_threshold_);
201 const auto& target_cloud = icp.target_;
203 std::vector<Eigen::Vector3d> source_points;
204 std::vector<Eigen::Vector3d> target_points;
205 std::vector<Eigen::Vector3d> target_normals;
206 for (
const auto& correspondence : pcl_correspondences) {
207 const auto& pcl_source_point = (*source_cloud)[correspondence.index_query];
208 const auto& pcl_target_point = (*target_cloud)[correspondence.index_match];
209 source_points.emplace_back(
Vector3d(pcl_source_point));
210 target_points.emplace_back(
Vector3d(pcl_target_point));
213 correspondences_ = ICPCorrespondences(source_points, target_points, target_normals);
216 template <
typename Po
intType>
218 return correspondences_;
222 #endif // POINT_CLOUD_COMMON_POINT_TO_PLANE_ICP_H_