34 #include <pcl/registration/icp.h> 35 #include <pcl/registration/transformation_estimation_2D.h> 36 #include <pcl/registration/transformation_estimation_svd.h> 37 #include <pcl/sample_consensus/sac_model_registration.h> 38 #include <pcl/sample_consensus/ransac.h> 39 #include <pcl/common/common.h> 51 const pcl::PointCloud<pcl::PointXYZ> & cloud1,
52 const pcl::PointCloud<pcl::PointXYZ> & cloud2)
54 pcl::registration::TransformationEstimationSVD<pcl::PointXYZ, pcl::PointXYZ> svd;
57 Eigen::Matrix4f matrix;
58 svd.estimateRigidTransformation(cloud1, cloud2, matrix);
64 const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloud1,
65 const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloud2,
66 double inlierThreshold,
70 std::vector<int> * inliersOut,
79 *covariance = cv::Mat::eye(6,6,CV_64FC1);
82 if(cloud1->size() >=3 && cloud1->size() == cloud2->size())
85 UDEBUG(
"iterations=%d inlierThreshold=%f", iterations, inlierThreshold);
86 std::vector<int> source_indices (cloud2->size());
87 std::vector<int> target_indices (cloud1->size());
90 for (
int i = 0; i < (int)cloud1->size(); ++i)
92 source_indices[i] = i;
93 target_indices[i] = i;
98 pcl::SampleConsensusModelRegistration<pcl::PointXYZ>::Ptr model;
99 model.reset(
new pcl::SampleConsensusModelRegistration<pcl::PointXYZ>(cloud2, source_indices));
101 model->setInputTarget (cloud1, target_indices);
103 pcl::RandomSampleConsensus<pcl::PointXYZ> sac (model, inlierThreshold);
104 sac.setMaxIterations(iterations);
107 if(sac.computeModel())
109 std::vector<int> inliers;
110 Eigen::VectorXf model_coefficients;
112 sac.getInliers(inliers);
113 sac.getModelCoefficients (model_coefficients);
115 if (refineIterations>0)
117 double error_threshold = inlierThreshold;
118 int refine_iterations = 0;
119 bool inlier_changed =
false, oscillating =
false;
120 std::vector<int> new_inliers, prev_inliers = inliers;
121 std::vector<size_t> inliers_sizes;
122 Eigen::VectorXf new_model_coefficients = model_coefficients;
126 model->optimizeModelCoefficients (prev_inliers, new_model_coefficients, new_model_coefficients);
127 inliers_sizes.push_back (prev_inliers.size ());
130 model->selectWithinDistance (new_model_coefficients, error_threshold, new_inliers);
131 UDEBUG(
"RANSAC refineModel: Number of inliers found (before/after): %d/%d, with an error threshold of %f.",
132 (
int)prev_inliers.size (), (int)new_inliers.size (), error_threshold);
134 if (new_inliers.empty ())
137 if (refine_iterations >= refineIterations)
145 double variance = model->computeVariance ();
146 error_threshold =
std::min (inlierThreshold, refineSigma *
sqrt(variance));
148 UDEBUG (
"RANSAC refineModel: New estimated error threshold: %f (variance=%f) on iteration %d out of %d.",
149 error_threshold, variance, refine_iterations, refineIterations);
150 inlier_changed =
false;
151 std::swap (prev_inliers, new_inliers);
154 if (new_inliers.size () != prev_inliers.size ())
157 if (inliers_sizes.size () >= 4)
159 if (inliers_sizes[inliers_sizes.size () - 1] == inliers_sizes[inliers_sizes.size () - 3] &&
160 inliers_sizes[inliers_sizes.size () - 2] == inliers_sizes[inliers_sizes.size () - 4])
166 inlier_changed =
true;
171 for (
size_t i = 0; i < prev_inliers.size (); ++i)
174 if (prev_inliers[i] != new_inliers[i])
176 inlier_changed =
true;
181 while (inlier_changed && ++refine_iterations < refineIterations);
184 if (new_inliers.empty ())
186 UWARN (
"RANSAC refineModel: Refinement failed: got an empty set of inliers!");
191 UDEBUG(
"RANSAC refineModel: Detected oscillations in the model refinement.");
194 std::swap (inliers, new_inliers);
195 model_coefficients = new_model_coefficients;
198 if (inliers.size() >= 3)
202 *inliersOut = inliers;
206 double variance = model->computeVariance();
208 *covariance *= variance;
212 Eigen::Matrix4f bestTransformation;
213 bestTransformation.row (0) = model_coefficients.segment<4>(0);
214 bestTransformation.row (1) = model_coefficients.segment<4>(4);
215 bestTransformation.row (2) = model_coefficients.segment<4>(8);
216 bestTransformation.row (3) = model_coefficients.segment<4>(12);
219 UDEBUG(
"RANSAC inliers=%d/%d tf=%s", (
int)inliers.size(), (int)cloud1->size(), transform.
prettyPrint().c_str());
225 UDEBUG(
"RANSAC: Model with inliers < 3");
230 UDEBUG(
"RANSAC: Failed to find model");
235 UDEBUG(
"Not enough points to compute the transform");
240 template<
typename Po
intNormalT>
242 const typename pcl::PointCloud<PointNormalT>::ConstPtr & cloudA,
243 const typename pcl::PointCloud<PointNormalT>::ConstPtr & cloudB,
244 double maxCorrespondenceDistance,
245 double maxCorrespondenceAngle,
247 int & correspondencesOut)
250 correspondencesOut = 0;
251 typename pcl::registration::CorrespondenceEstimation<PointNormalT, PointNormalT>::Ptr est;
252 est.reset(
new pcl::registration::CorrespondenceEstimation<PointNormalT, PointNormalT>);
253 const typename pcl::PointCloud<PointNormalT>::ConstPtr & target = cloudA->size()>cloudB->size()?cloudA:cloudB;
254 const typename pcl::PointCloud<PointNormalT>::ConstPtr &
source = cloudA->size()>cloudB->size()?cloudB:cloudA;
255 est->setInputTarget(target);
256 est->setInputSource(source);
257 pcl::Correspondences correspondences;
258 est->determineCorrespondences(correspondences, maxCorrespondenceDistance);
260 if(correspondences.size())
262 std::vector<double> distances(correspondences.size());
263 correspondencesOut = 0;
264 for(
unsigned int i=0; i<correspondences.size(); ++i)
266 distances[i] = correspondences[i].distance;
267 if(maxCorrespondenceAngle <= 0.0)
269 ++correspondencesOut;
274 target->at(correspondences[i].index_match).normal_x,
275 target->at(correspondences[i].index_match).normal_y,
276 target->at(correspondences[i].index_match).normal_z,
279 source->at(correspondences[i].index_query).normal_x,
280 source->at(correspondences[i].index_query).normal_y,
281 source->at(correspondences[i].index_query).normal_z,
283 float angle = pcl::getAngle3D(v1, v2);
284 if(angle < maxCorrespondenceAngle)
286 ++correspondencesOut;
290 if(correspondencesOut)
292 distances.resize(correspondencesOut);
295 std::sort(distances.begin (), distances.end ());
296 double median_error_sqr = distances[distances.size () >> 1];
297 variance = (2.1981 * median_error_sqr);
303 const pcl::PointCloud<pcl::PointNormal>::ConstPtr & cloudA,
304 const pcl::PointCloud<pcl::PointNormal>::ConstPtr & cloudB,
305 double maxCorrespondenceDistance,
306 double maxCorrespondenceAngle,
308 int & correspondencesOut)
310 computeVarianceAndCorrespondencesImpl<pcl::PointNormal>(cloudA, cloudB, maxCorrespondenceDistance, maxCorrespondenceAngle, variance, correspondencesOut);
314 const pcl::PointCloud<pcl::PointXYZINormal>::ConstPtr & cloudA,
315 const pcl::PointCloud<pcl::PointXYZINormal>::ConstPtr & cloudB,
316 double maxCorrespondenceDistance,
317 double maxCorrespondenceAngle,
319 int & correspondencesOut)
321 computeVarianceAndCorrespondencesImpl<pcl::PointXYZINormal>(cloudA, cloudB, maxCorrespondenceDistance, maxCorrespondenceAngle, variance, correspondencesOut);
324 template<
typename Po
intT>
326 const typename pcl::PointCloud<PointT>::ConstPtr & cloudA,
327 const typename pcl::PointCloud<PointT>::ConstPtr & cloudB,
328 double maxCorrespondenceDistance,
330 int & correspondencesOut)
333 correspondencesOut = 0;
334 typename pcl::registration::CorrespondenceEstimation<PointT, PointT>::Ptr est;
335 est.reset(
new pcl::registration::CorrespondenceEstimation<PointT, PointT>);
336 est->setInputTarget(cloudA->size()>cloudB->size()?cloudA:cloudB);
337 est->setInputSource(cloudA->size()>cloudB->size()?cloudB:cloudA);
338 pcl::Correspondences correspondences;
339 est->determineCorrespondences(correspondences, maxCorrespondenceDistance);
341 if(correspondences.size()>=3)
343 std::vector<double> distances(correspondences.size());
344 for(
unsigned int i=0; i<correspondences.size(); ++i)
346 distances[i] = correspondences[i].distance;
350 std::sort(distances.begin (), distances.end ());
351 double median_error_sqr = distances[distances.size () >> 1];
352 variance = (2.1981 * median_error_sqr);
355 correspondencesOut = (int)correspondences.size();
359 const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloudA,
360 const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloudB,
361 double maxCorrespondenceDistance,
363 int & correspondencesOut)
365 computeVarianceAndCorrespondencesImpl<pcl::PointXYZ>(cloudA, cloudB, maxCorrespondenceDistance, variance, correspondencesOut);
369 const pcl::PointCloud<pcl::PointXYZI>::ConstPtr & cloudA,
370 const pcl::PointCloud<pcl::PointXYZI>::ConstPtr & cloudB,
371 double maxCorrespondenceDistance,
373 int & correspondencesOut)
375 computeVarianceAndCorrespondencesImpl<pcl::PointXYZI>(cloudA, cloudB, maxCorrespondenceDistance, variance, correspondencesOut);
379 template<
typename Po
intT>
381 const typename pcl::PointCloud<PointT>::ConstPtr & cloud_target,
382 double maxCorrespondenceDistance,
383 int maximumIterations,
385 pcl::PointCloud<PointT> & cloud_source_registered,
389 pcl::IterativeClosestPoint<PointT, PointT>
icp;
391 icp.setInputTarget (cloud_target);
392 icp.setInputSource (cloud_source);
396 typename pcl::registration::TransformationEstimation2D<PointT, PointT>::Ptr est;
397 est.reset(
new pcl::registration::TransformationEstimation2D<PointT, PointT>);
398 icp.setTransformationEstimation(est);
402 icp.setMaxCorrespondenceDistance (maxCorrespondenceDistance);
404 icp.setMaximumIterations (maximumIterations);
406 icp.setTransformationEpsilon (epsilon*epsilon);
412 icp.align (cloud_source_registered);
413 hasConverged = icp.hasConverged();
418 Transform icp(
const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloud_source,
419 const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloud_target,
420 double maxCorrespondenceDistance,
421 int maximumIterations,
423 pcl::PointCloud<pcl::PointXYZ> & cloud_source_registered,
427 return icpImpl(cloud_source, cloud_target, maxCorrespondenceDistance, maximumIterations, hasConverged, cloud_source_registered, epsilon, icp2D);
431 Transform icp(
const pcl::PointCloud<pcl::PointXYZI>::ConstPtr & cloud_source,
432 const pcl::PointCloud<pcl::PointXYZI>::ConstPtr & cloud_target,
433 double maxCorrespondenceDistance,
434 int maximumIterations,
436 pcl::PointCloud<pcl::PointXYZI> & cloud_source_registered,
440 return icpImpl(cloud_source, cloud_target, maxCorrespondenceDistance, maximumIterations, hasConverged, cloud_source_registered, epsilon, icp2D);
444 template<
typename Po
intNormalT>
446 const typename pcl::PointCloud<PointNormalT>::ConstPtr & cloud_source,
447 const typename pcl::PointCloud<PointNormalT>::ConstPtr & cloud_target,
448 double maxCorrespondenceDistance,
449 int maximumIterations,
451 pcl::PointCloud<PointNormalT> & cloud_source_registered,
455 pcl::IterativeClosestPoint<PointNormalT, PointNormalT>
icp;
457 icp.setInputTarget (cloud_target);
458 icp.setInputSource (cloud_source);
460 typename pcl::registration::TransformationEstimationPointToPlaneLLS<PointNormalT, PointNormalT>::Ptr est;
461 est.reset(
new pcl::registration::TransformationEstimationPointToPlaneLLS<PointNormalT, PointNormalT>);
462 icp.setTransformationEstimation(est);
465 icp.setMaxCorrespondenceDistance (maxCorrespondenceDistance);
467 icp.setMaximumIterations (maximumIterations);
469 icp.setTransformationEpsilon (epsilon*epsilon);
475 icp.align (cloud_source_registered);
476 hasConverged = icp.hasConverged();
490 const pcl::PointCloud<pcl::PointNormal>::ConstPtr & cloud_source,
491 const pcl::PointCloud<pcl::PointNormal>::ConstPtr & cloud_target,
492 double maxCorrespondenceDistance,
493 int maximumIterations,
495 pcl::PointCloud<pcl::PointNormal> & cloud_source_registered,
499 return icpPointToPlaneImpl(cloud_source, cloud_target, maxCorrespondenceDistance, maximumIterations, hasConverged, cloud_source_registered, epsilon, icp2D);
503 const pcl::PointCloud<pcl::PointXYZINormal>::ConstPtr & cloud_source,
504 const pcl::PointCloud<pcl::PointXYZINormal>::ConstPtr & cloud_target,
505 double maxCorrespondenceDistance,
506 int maximumIterations,
508 pcl::PointCloud<pcl::PointXYZINormal> & cloud_source_registered,
512 return icpPointToPlaneImpl(cloud_source, cloud_target, maxCorrespondenceDistance, maximumIterations, hasConverged, cloud_source_registered, epsilon, icp2D);
Transform RTABMAP_EXP transformFromXYZCorrespondencesSVD(const pcl::PointCloud< pcl::PointXYZ > &cloud1, const pcl::PointCloud< pcl::PointXYZ > &cloud2)
GLM_FUNC_DECL genType min(genType const &x, genType const &y)
Transform icpPointToPlaneImpl(const typename pcl::PointCloud< PointNormalT >::ConstPtr &cloud_source, const typename pcl::PointCloud< PointNormalT >::ConstPtr &cloud_target, double maxCorrespondenceDistance, int maximumIterations, bool &hasConverged, pcl::PointCloud< PointNormalT > &cloud_source_registered, float epsilon, bool icp2D)
GLM_FUNC_DECL vecType< T, P > sqrt(vecType< T, P > const &x)
Transform RTABMAP_EXP icpPointToPlane(const pcl::PointCloud< pcl::PointNormal >::ConstPtr &cloud_source, const pcl::PointCloud< pcl::PointNormal >::ConstPtr &cloud_target, double maxCorrespondenceDistance, int maximumIterations, bool &hasConverged, pcl::PointCloud< pcl::PointNormal > &cloud_source_registered, float epsilon=0.0f, bool icp2D=false)
void RTABMAP_EXP computeVarianceAndCorrespondences(const pcl::PointCloud< pcl::PointNormal >::ConstPtr &cloudA, const pcl::PointCloud< pcl::PointNormal >::ConstPtr &cloudB, double maxCorrespondenceDistance, double maxCorrespondenceAngle, double &variance, int &correspondencesOut)
Basic mathematics functions.
GLM_FUNC_DECL T angle(detail::tquat< T, P > const &x)
Transform RTABMAP_EXP transformFromXYZCorrespondences(const pcl::PointCloud< pcl::PointXYZ >::ConstPtr &cloud1, const pcl::PointCloud< pcl::PointXYZ >::ConstPtr &cloud2, double inlierThreshold=0.02, int iterations=100, int refineModelIterations=10, double refineModelSigma=3.0, std::vector< int > *inliers=0, cv::Mat *variance=0)
bool uIsFinite(const T &value)
#define UASSERT(condition)
Transform icpImpl(const typename pcl::PointCloud< PointT >::ConstPtr &cloud_source, const typename pcl::PointCloud< PointT >::ConstPtr &cloud_target, double maxCorrespondenceDistance, int maximumIterations, bool &hasConverged, pcl::PointCloud< PointT > &cloud_source_registered, float epsilon, bool icp2D)
Transform RTABMAP_EXP icp(const pcl::PointCloud< pcl::PointXYZ >::ConstPtr &cloud_source, const pcl::PointCloud< pcl::PointXYZ >::ConstPtr &cloud_target, double maxCorrespondenceDistance, int maximumIterations, bool &hasConverged, pcl::PointCloud< pcl::PointXYZ > &cloud_source_registered, float epsilon=0.0f, bool icp2D=false)
void computeVarianceAndCorrespondencesImpl(const typename pcl::PointCloud< PointNormalT >::ConstPtr &cloudA, const typename pcl::PointCloud< PointNormalT >::ConstPtr &cloudB, double maxCorrespondenceDistance, double maxCorrespondenceAngle, double &variance, int &correspondencesOut)
ULogger class and convenient macros.