39 #ifndef PCL_REGISTRATION_IMPL_JOINT_ICP_HPP_
40 #define PCL_REGISTRATION_IMPL_JOINT_ICP_HPP_
42 #include <pcl/console/print.h>
43 #include <pcl/correspondence.h>
47 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
53 if (sources_.size() != targets_.size() || sources_.empty() || targets_.empty()) {
54 PCL_ERROR(
"[pcl::%s::computeTransformation] Must set InputSources and InputTargets "
55 "to the same, nonzero size!\n",
56 getClassName().c_str());
59 bool manual_correspondence_estimations_set =
true;
60 if (correspondence_estimations_.empty()) {
61 manual_correspondence_estimations_set =
false;
62 correspondence_estimations_.resize(sources_.size());
63 for (std::size_t i = 0; i < sources_.size(); i++) {
64 correspondence_estimations_[i] = correspondence_estimation_->clone();
67 correspondence_estimations_[i]->setSearchMethodTarget(tgt_tree);
68 correspondence_estimations_[i]->setSearchMethodSource(src_tree);
71 if (correspondence_estimations_.size() != sources_.size()) {
72 PCL_ERROR(
"[pcl::%s::computeTransform] Must set CorrespondenceEstimations to be "
73 "the same size as the joint\n",
74 getClassName().c_str());
77 std::vector<PointCloudSourcePtr> inputs_transformed(sources_.size());
78 for (std::size_t i = 0; i < sources_.size(); i++) {
86 final_transformation_ = guess;
89 std::vector<std::size_t> input_offsets(sources_.size());
90 std::vector<std::size_t> target_offsets(targets_.size());
94 std::size_t input_offset = 0;
95 std::size_t target_offset = 0;
96 for (std::size_t i = 0; i < sources_.size(); i++) {
98 if (guess != Matrix4::Identity()) {
100 this->transformCloud(*sources_[i], *inputs_transformed[i], guess);
103 *inputs_transformed[i] = *sources_[i];
105 *sources_combined += *sources_[i];
106 *inputs_transformed_combined += *inputs_transformed[i];
107 *targets_combined += *targets_[i];
108 input_offsets[i] = input_offset;
109 target_offsets[i] = target_offset;
110 input_offset += inputs_transformed[i]->size();
111 target_offset += targets_[i]->size();
114 transformation_ = Matrix4::Identity();
116 determineRequiredBlobData();
118 for (std::size_t i = 0; i < sources_.size(); i++) {
119 correspondence_estimations_[i]->setInputTarget(targets_[i]);
120 if (correspondence_estimations_[i]->requiresTargetNormals()) {
123 correspondence_estimations_[i]->setTargetNormals(target_blob);
128 if (!correspondence_rejectors_.empty() && need_target_blob_)
131 for (std::size_t i = 0; i < correspondence_rejectors_.size(); ++i) {
133 if (rej->requiresTargetPoints())
134 rej->setTargetPoints(targets_combined_blob);
135 if (rej->requiresTargetNormals() && target_has_normals_)
136 rej->setTargetNormals(targets_combined_blob);
139 convergence_criteria_->setMaximumIterations(max_iterations_);
140 convergence_criteria_->setRelativeMSE(euclidean_fitness_epsilon_);
141 convergence_criteria_->setTranslationThreshold(transformation_epsilon_);
142 convergence_criteria_->setRotationThreshold(1.0 - transformation_epsilon_);
145 std::vector<CorrespondencesPtr> partial_correspondences_(sources_.size());
146 for (std::size_t i = 0; i < sources_.size(); i++) {
152 previous_transformation_ = transformation_;
155 correspondences_->clear();
156 for (std::size_t i = 0; i < correspondence_estimations_.size(); i++) {
157 correspondence_estimations_[i]->setInputSource(inputs_transformed[i]);
159 if (correspondence_estimations_[i]->requiresSourceNormals()) {
162 correspondence_estimations_[i]->setSourceNormals(input_transformed_blob);
166 if (use_reciprocal_correspondence_) {
167 correspondence_estimations_[i]->determineReciprocalCorrespondences(
168 *partial_correspondences_[i], corr_dist_threshold_);
171 correspondence_estimations_[i]->determineCorrespondences(
172 *partial_correspondences_[i], corr_dist_threshold_);
174 PCL_DEBUG(
"[pcl::%s::computeTransformation] Found %d partial correspondences for "
176 getClassName().c_str(),
177 partial_correspondences_[i]->size(),
179 for (std::size_t j = 0; j < partial_correspondences_[i]->size(); j++) {
184 correspondences_->push_back(corr);
187 PCL_DEBUG(
"[pcl::%s::computeTransformation] Total correspondences: %d\n",
188 getClassName().c_str(),
189 correspondences_->size());
192 if (need_source_blob_) {
194 toPCLPointCloud2(*inputs_transformed_combined, *inputs_transformed_combined_blob);
197 for (std::size_t i = 0; i < correspondence_rejectors_.size(); ++i) {
198 PCL_DEBUG(
"Applying a correspondence rejector method: %s.\n",
199 correspondence_rejectors_[i]->getClassName().c_str());
201 PCL_DEBUG(
"Applying a correspondence rejector method: %s.\n",
202 rej->getClassName().c_str());
203 if (rej->requiresSourcePoints())
204 rej->setSourcePoints(inputs_transformed_combined_blob);
205 if (rej->requiresSourceNormals() && source_has_normals_)
206 rej->setSourceNormals(inputs_transformed_combined_blob);
207 rej->setInputCorrespondences(temp_correspondences);
208 rej->getCorrespondences(*correspondences_);
210 if (i < correspondence_rejectors_.size() - 1)
211 *temp_correspondences = *correspondences_;
215 if (correspondences_->size() < min_number_correspondences_) {
216 PCL_ERROR(
"[pcl::%s::computeTransformation] Not enough correspondences found. "
217 "Relax your threshold parameters.\n",
218 getClassName().c_str());
219 convergence_criteria_->setConvergenceState(
221 Scalar>::CONVERGENCE_CRITERIA_NO_CORRESPONDENCES);
227 transformation_estimation_->estimateRigidTransformation(
228 *inputs_transformed_combined,
234 this->transformCloud(
235 *inputs_transformed_combined, *inputs_transformed_combined, transformation_);
237 for (std::size_t i = 0; i < sources_.size(); i++) {
238 this->transformCloud(
239 *inputs_transformed[i], *inputs_transformed[i], transformation_);
243 final_transformation_ = transformation_ * final_transformation_;
251 converged_ =
static_cast<bool>((*convergence_criteria_));
252 }
while (!converged_);
254 PCL_DEBUG(
"Transformation "
255 "is:\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n\t%5f\t%5f\t%5f\t%5f\n\t%"
256 "5f\t%5f\t%5f\t%5f\n",
257 final_transformation_(0, 0),
258 final_transformation_(0, 1),
259 final_transformation_(0, 2),
260 final_transformation_(0, 3),
261 final_transformation_(1, 0),
262 final_transformation_(1, 1),
263 final_transformation_(1, 2),
264 final_transformation_(1, 3),
265 final_transformation_(2, 0),
266 final_transformation_(2, 1),
267 final_transformation_(2, 2),
268 final_transformation_(2, 3),
269 final_transformation_(3, 0),
270 final_transformation_(3, 1),
271 final_transformation_(3, 2),
272 final_transformation_(3, 3));
283 if (!manual_correspondence_estimations_set) {
284 correspondence_estimations_.clear();
292 template <
typename Po
intSource,
typename Po
intTarget,
typename Scalar>
297 need_source_blob_ =
false;
298 need_target_blob_ =
false;
300 for (std::size_t i = 0; i < correspondence_estimations_.size(); i++) {
303 need_source_blob_ |= ce->requiresSourceNormals();
304 need_target_blob_ |= ce->requiresTargetNormals();
306 if (ce->requiresSourceNormals() && !source_has_normals_) {
307 PCL_WARN(
"[pcl::%s::determineRequiredBlobData] Estimator expects source normals, "
308 "but we can't provide them.\n",
309 getClassName().c_str());
311 if (ce->requiresTargetNormals() && !target_has_normals_) {
312 PCL_WARN(
"[pcl::%s::determineRequiredBlobData] Estimator expects target normals, "
313 "but we can't provide them.\n",
314 getClassName().c_str());
318 for (std::size_t i = 0; i < correspondence_rejectors_.size(); i++) {
320 need_source_blob_ |= rej->requiresSourcePoints();
321 need_source_blob_ |= rej->requiresSourceNormals();
322 need_target_blob_ |= rej->requiresTargetPoints();
323 need_target_blob_ |= rej->requiresTargetNormals();
324 if (rej->requiresSourceNormals() && !source_has_normals_) {
325 PCL_WARN(
"[pcl::%s::determineRequiredBlobData] Rejector %s expects source "
326 "normals, but we can't provide them.\n",
327 getClassName().c_str(),
328 rej->getClassName().c_str());
330 if (rej->requiresTargetNormals() && !target_has_normals_) {
331 PCL_WARN(
"[pcl::%s::determineRequiredBlobData] Rejector %s expects target "
332 "normals, but we can't provide them.\n",
333 getClassName().c_str(),
334 rej->getClassName().c_str());
void setInputTarget(const PointCloudTargetConstPtr &cloud) override
Provide a pointer to the input target (e.g., the point cloud that we want to align the input source t...
void setInputSource(const PointCloudSourceConstPtr &cloud) override
Provide a pointer to the input source (e.g., the point cloud that we want to align to the target)
typename PointCloudSource::Ptr PointCloudSourcePtr
void determineRequiredBlobData() override
Looks at the Estimators and Rejectors and determines whether their blob-setter methods need to be cal...
typename IterativeClosestPoint< PointSource, PointTarget, Scalar >::PointCloudTarget PointCloudTarget
typename KdTree::Ptr KdTreeReciprocalPtr
void computeTransformation(PointCloudSource &output, const Matrix4 &guess) override
Rigid transformation computation method with initial guess.
typename PointCloudTarget::Ptr PointCloudTargetPtr
typename CorrespondenceEstimation::Ptr CorrespondenceEstimationPtr
typename IterativeClosestPoint< PointSource, PointTarget, Scalar >::PointCloudSource PointCloudSource
typename KdTree::Ptr KdTreePtr
typename IterativeClosestPoint< PointSource, PointTarget, Scalar >::Matrix4 Matrix4
shared_ptr< CorrespondenceRejector > Ptr
DefaultConvergenceCriteria represents an instantiation of ConvergenceCriteria, and implements the fol...
search::KdTree is a wrapper class which inherits the pcl::KdTree class for performing search function...
shared_ptr< Correspondences > CorrespondencesPtr
std::vector< pcl::Correspondence, Eigen::aligned_allocator< pcl::Correspondence > > Correspondences
void toPCLPointCloud2(const pcl::PointCloud< PointT > &cloud, pcl::PCLPointCloud2 &msg, bool padding)
Convert a pcl::PointCloud<T> object to a PCLPointCloud2 binary data blob.
Correspondence represents a match between two entities (e.g., points, descriptors,...
index_t index_query
Index of the query (source) point.
index_t index_match
Index of the matching (target) point.
shared_ptr< ::pcl::PCLPointCloud2 > Ptr