40 #include <pcl/conversions.h> 41 #include <pcl/common/pca.h> 42 #include <pcl/common/io.h> 43 #include <pcl/io/pcd_io.h> 44 #include <pcl/io/ply_io.h> 45 #include <pcl/io/vtk_io.h> 47 #ifdef RTABMAP_CCCORELIB 51 #ifdef RTABMAP_POINTMATCHER 60 _maxTranslation(
Parameters::defaultIcpMaxTranslation()),
61 _maxRotation(
Parameters::defaultIcpMaxRotation()),
63 _downsamplingStep(
Parameters::defaultIcpDownsamplingStep()),
66 _maxCorrespondenceDistance(
Parameters::defaultIcpMaxCorrespondenceDistance()),
67 _maxIterations(
Parameters::defaultIcpIterations()),
69 _correspondenceRatio(
Parameters::defaultIcpCorrespondenceRatio()),
71 _pointToPlane(
Parameters::defaultIcpPointToPlane()),
72 _pointToPlaneK(
Parameters::defaultIcpPointToPlaneK()),
73 _pointToPlaneRadius(
Parameters::defaultIcpPointToPlaneRadius()),
74 _pointToPlaneGroundNormalsUp(
Parameters::defaultIcpPointToPlaneGroundNormalsUp()),
75 _pointToPlaneMinComplexity(
Parameters::defaultIcpPointToPlaneMinComplexity()),
76 _pointToPlaneLowComplexityStrategy(
Parameters::defaultIcpPointToPlaneLowComplexityStrategy()),
77 _libpointmatcherConfig(
Parameters::defaultIcpPMConfig()),
78 _libpointmatcherKnn(
Parameters::defaultIcpPMMatcherKnn()),
79 _libpointmatcherEpsilon(
Parameters::defaultIcpPMMatcherEpsilon()),
80 _libpointmatcherIntensity(
Parameters::defaultIcpPMMatcherIntensity()),
81 _outlierRatio(
Parameters::defaultIcpOutlierRatio()),
82 _ccSamplingLimit (
Parameters::defaultIcpCCSamplingLimit()),
83 _ccFilterOutFarthestPoints (
Parameters::defaultIcpCCFilterOutFarthestPoints()),
84 _ccMaxFinalRMS (
Parameters::defaultIcpCCMaxFinalRMS()),
85 _debugExportFormat(
Parameters::defaultIcpDebugExportFormat()),
86 _libpointmatcherICP(0),
87 _libpointmatcherICPFilters(0)
94 #ifdef RTABMAP_POINTMATCHER 136 ParametersMap::const_iterator iter;
137 if((iter=parameters.find(Parameters::kRtabmapWorkingDirectory())) != parameters.end())
144 #ifndef RTABMAP_POINTMATCHER 147 UWARN(
"Parameter %s is set to 1 but RTAB-Map has not been built with libpointmatcher support. Setting to 0.", Parameters::kIcpStrategy().c_str());
160 PM::ICP *
icp = (PM::ICP*)_libpointmatcherICP;
162 bool useDefaults =
true;
170 icp->loadFromYaml(ifs);
175 icpFilters->readingDataPointsFilters = icp->readingDataPointsFilters;
176 icpFilters->referenceDataPointsFilters = icp->referenceDataPointsFilters;
178 icp->readingDataPointsFilters.clear();
181 icp->referenceDataPointsFilters.clear();
184 catch (
const std::exception &
e)
200 icp->readingDataPointsFilters.clear();
203 icp->referenceDataPointsFilters.clear();
217 #if POINTMATCHER_VERSION_INT >= 10300 218 icp->matcher =
PM::get().MatcherRegistrar.create(
"KDTreeMatcher", params);
226 icp->outlierFilters.clear();
239 params[
"force4DOF"] =
"1";
241 #if POINTMATCHER_VERSION_INT >= 10300 242 icp->errorMinimizer =
PM::get().ErrorMinimizerRegistrar.create(
"PointToPlaneErrorMinimizer", params);
250 #if POINTMATCHER_VERSION_INT >= 10300 251 icp->errorMinimizer =
PM::get().ErrorMinimizerRegistrar.create(
"PointToPointErrorMinimizer");
257 icp->transformationCheckers.clear();
273 pointToPlane = icp->errorMinimizer->className.compare(
"PointToPlaneErrorMinimizer")==0;
277 #ifndef RTABMAP_CCCORELIB 280 #ifdef RTABMAP_POINTMATCHER 285 UWARN(
"Parameter %s is set to 2 but RTAB-Map has not been built with CCCoreLib support. Setting to %d.", Parameters::kIcpStrategy().c_str(),
_strategy);
290 UWARN(
"%s cannot be used with %s=2 (CCCoreLib), setting %s to false", Parameters::kIcpPointToPlane().c_str(), Parameters::kIcpStrategy().c_str(), Parameters::kIcpPointToPlane().c_str());
297 UWARN(
"%s cannot be used with %s == 0.", Parameters::kIcpForce4DoF().c_str(), Parameters::kIcpStrategy().c_str());
317 #ifdef RTABMAP_POINTMATCHER 321 pointToPlane = icp->errorMinimizer->className.compare(
"PointToPlaneErrorMinimizer")==0;
327 UDEBUG(
"PointToPlane=%d", pointToPlane?1:0);
349 UDEBUG(
"size before filtering, from=%d (format=%s, max pts=%d) to=%d (format=%s, max pts=%d)",
372 #ifdef RTABMAP_POINTMATCHER 376 UDEBUG(
"icp.referenceDataPointsFilters.size()=%d", (
int)filters.referenceDataPointsFilters.size());
377 if(filters.referenceDataPointsFilters.size()>1 ||
378 (filters.referenceDataPointsFilters.size() == 1 && filters.referenceDataPointsFilters[0]->className.compare(
"IdentityDataPointsFilter")!=0))
382 filters.referenceDataPointsFilters.apply(data);
390 catch(
const std::exception &
e)
392 msg =
uFormat(
"libpointmatcher's data filters have failed: %s", e.what());
393 UERROR(
"%s", msg.c_str());
399 float ratio = float(dataFrom.
laserScanRaw().
size()) /
float(pointsBeforeFiltering);
400 maxLaserScansFrom = int(
float(maxLaserScansFrom) * ratio);
413 #ifdef RTABMAP_POINTMATCHER 417 UDEBUG(
"icp.readingDataPointsFilters.size()=%d", (
int)filters.readingDataPointsFilters.size());
418 if(filters.readingDataPointsFilters.size()>1 ||
419 (filters.readingDataPointsFilters.size() == 1 && filters.readingDataPointsFilters[0]->className.compare(
"IdentityDataPointsFilter")!=0))
423 filters.readingDataPointsFilters.apply(data);
431 catch(
const std::exception &
e)
433 msg =
uFormat(
"libpointmatcher's data filters have failed: %s", e.what());
434 UERROR(
"%s", msg.c_str());
440 float ratio = float(dataTo.
laserScanRaw().
size()) /
float(pointsBeforeFiltering);
441 maxLaserScansTo = int(
float(maxLaserScansTo) * ratio);
444 UDEBUG(
"size after filtering, from=%d (format=%s, max pts=%d) to=%d (format=%s, max pts=%d), filtering time=%fs",
460 if(fromScan.
size() && toScan.
size())
462 std::string toPrefix =
"rtabmap_icp_scan";
466 std::string fromPrefix =
"rtabmap_icp_scan";
481 UWARN(
"Saved %s.vtk and %s.vtk (%s=\"%s\") to working directory (%s=%s)", fromPrefix.c_str(), toPrefix.c_str(), Parameters::kIcpDebugExportFormat().c_str(),
_debugExportFormat.c_str(), Parameters::kRtabmapWorkingDirectory().c_str(),
_workingDir.c_str());
487 UWARN(
"Saved %s.ply and %s.ply (%s=\"%s\") to directory (%s=%s)", fromPrefix.c_str(), toPrefix.c_str(), Parameters::kIcpDebugExportFormat().c_str(),
_debugExportFormat.c_str(), Parameters::kRtabmapWorkingDirectory().c_str(),
_workingDir.c_str());
493 UWARN(
"Saved %s.pcd and %s.pcd (%s=\"%s\") to working directory (%s=%s)", fromPrefix.c_str(), toPrefix.c_str(), Parameters::kIcpDebugExportFormat().c_str(),
_debugExportFormat.c_str(), Parameters::kRtabmapWorkingDirectory().c_str(),
_workingDir.c_str());
498 UWARN(
"%s is enabled but %s is not, cannot export debug scans.", Parameters::kIcpDebugExportFormat().c_str(), Parameters::kRtabmapWorkingDirectory().c_str());
501 bool tooLowComplexityForPlaneToPlane =
false;
502 float secondEigenValue = 1.0f;
503 cv::Mat complexityVectors;
507 UWARN(
"ICP PointToPlane ignored for 2d scans with PCL registration " 508 "(some crash issues). Use libpointmatcher (%s=1) or disable %s " 509 "to avoid this warning.",
510 Parameters::kIcpStrategy().c_str(),
511 Parameters::kIcpPointToPlane().c_str());
512 pointToPlane =
false;
521 cv::Mat complexityVectorsFrom, complexityVectorsTo;
522 cv::Mat complexityValuesFrom, complexityValuesTo;
525 float complexity = fromComplexity<toComplexity?fromComplexity:toComplexity;
529 tooLowComplexityForPlaneToPlane =
true;
530 pointToPlane =
false;
531 if(complexity > 0.0
f)
533 complexityVectors = fromComplexity<toComplexity?complexityVectorsFrom:complexityVectorsTo;
535 UASSERT((complexityVectors.rows == 2 && complexityVectors.cols == 2)||
536 (complexityVectors.rows == 3 && complexityVectors.cols == 3));
537 secondEigenValue = complexityValuesFrom.at<
float>(1,0)<complexityValuesTo.at<
float>(1,0)?complexityValuesFrom.at<
float>(1,0):complexityValuesTo.at<
float>(1,0);
538 UWARN(
"ICP PointToPlane ignored as structural complexity is too low (corridor-like environment): (from=%f || to=%f) < %f (%s). Second eigen value=%f. " 539 "PointToPoint is done instead, orientation is still optimized but translation will be limited to " 540 "direction of normals (%s: %s).",
543 fromComplexity<toComplexity?
"From":
"To",
544 complexityVectors.rows==2?
545 uFormat(
"n=%f,%f", complexityVectors.at<
float>(0,0), complexityVectors.at<
float>(0,1)).c_str():
547 uFormat(
"n=%f,%f,%f", complexityVectors.at<
float>(0,0), complexityVectors.at<
float>(0,1), complexityVectors.at<
float>(0,2)).c_str():
548 uFormat(
"n1=%f,%f,%f n2=%f,%f,%f", complexityVectors.at<
float>(0,0), complexityVectors.at<
float>(0,1), complexityVectors.at<
float>(0,2), complexityVectors.at<
float>(1,0), complexityVectors.at<
float>(1,1), complexityVectors.at<
float>(1,2)).c_str());
552 UWARN(
"ICP PointToPlane ignored as structural complexity cannot be computed (from=%f to=%f)!? PointToPoint is done instead.", fromComplexity, toComplexity);
556 std::cout <<
"complexityVectorsFrom = " << std::endl << complexityVectorsFrom << std::endl;
557 std::cout <<
"complexityValuesFrom = " << std::endl << complexityValuesFrom << std::endl;
558 std::cout <<
"complexityVectorsTo = " << std::endl << complexityVectorsTo << std::endl;
559 std::cout <<
"complexityValuesTo = " << std::endl << complexityValuesTo << std::endl;
565 msg =
uFormat(
"Rejecting transform because too low complexity %f (%s=0)",
567 Parameters::kIcpPointToPlaneLowComplexityStrategy().c_str());
576 pointToPlane =
false;
580 bool hasConverged =
false;
581 float correspondencesRatio = 0.0f;
582 int correspondences = 0;
583 double variance = 1.0;
597 pcl::PointCloud<pcl::PointXYZINormal>::Ptr fromCloudNormalsRegistered(
new pcl::PointCloud<pcl::PointXYZINormal>());
598 #ifdef RTABMAP_POINTMATCHER 611 UDEBUG(
"libpointmatcher icp... (if there is a seg fault here, make sure all third party libraries are built with same Eigen version.)");
613 icpT =
Transform::fromEigen3d(Eigen::Affine3d(Eigen::Matrix4d(eigenMatrixToDim<double>(T.template cast<double>(), 4))));
616 float matchRatio = icp.errorMinimizer->getWeightedPointUsedRatio();
617 UDEBUG(
"match ratio: %f", matchRatio);
625 catch(
const std::exception &
e)
627 msg =
uFormat(
"libpointmatcher has failed: %s", e.what());
639 *fromCloudNormalsRegistered,
644 if(!icpT.
isNull() && hasConverged)
647 fromCloudNormalsRegistered,
664 pcl::PointCloud<pcl::PointXYZI>::Ptr fromCloudRegistered(
new pcl::PointCloud<pcl::PointXYZI>());
666 #ifdef RTABMAP_POINTMATCHER 679 UDEBUG(
"libpointmatcher icp... (if there is a seg fault here, make sure all third party libraries are built with same Eigen version.)");
680 if(tooLowComplexityForPlaneToPlane)
683 PM::ICP icpTmp =
icp;
687 UWARN(
"libpointmatcher icp...temporary maxDist=%s (%s=%f, %s=%f)", params[
"maxDist"].c_str(), Parameters::kIcpMaxCorrespondenceDistance().c_str(),
_maxCorrespondenceDistance, Parameters::kIcpVoxelSize().c_str(),
_voxelSize);
696 #if POINTMATCHER_VERSION_INT >= 10300 697 icpTmp.matcher =
PM::get().MatcherRegistrar.create(
"KDTreeMatcher", params);
703 #if POINTMATCHER_VERSION_INT >= 10300 704 icpTmp.errorMinimizer =
PM::get().ErrorMinimizerRegistrar.create(
"PointToPointErrorMinimizer");
708 for(PM::OutlierFilters::iterator iter=icpTmp.outlierFilters.begin(); iter!=icpTmp.outlierFilters.end();)
710 if((*iter)->className.compare(
"SurfaceNormalOutlierFilter") == 0)
712 iter = icpTmp.outlierFilters.erase(iter);
720 T = icpTmp(data, ref);
726 UDEBUG(
"libpointmatcher icp...done!");
727 icpT =
Transform::fromEigen3d(Eigen::Affine3d(Eigen::Matrix4d(eigenMatrixToDim<double>(T.template cast<double>(), 4))));
729 float matchRatio = icp.errorMinimizer->getWeightedPointUsedRatio();
730 UDEBUG(
"match ratio: %f", matchRatio);
737 catch(
const std::exception &
e)
739 msg =
uFormat(
"libpointmatcher has failed: %s", e.what());
745 #ifdef RTABMAP_CCCORELIB 761 hasConverged = !icpT.
isNull();
772 *fromCloudRegistered,
778 if(!icpT.
isNull() && hasConverged)
780 if(tooLowComplexityForPlaneToPlane)
786 Eigen::Vector3f v(t.
x(), t.
y(), t.
z());
787 if(complexityVectors.cols == 2)
790 Eigen::Vector3f n(complexityVectors.at<
float>(0,0), complexityVectors.at<
float>(0,1), 0.0f);
792 Eigen::Vector3f vp = n*a;
793 UWARN(
"Normals low complexity (%f): Limiting translation from (%f,%f) to (%f,%f)",
795 v[0], v[1], vp[0], vp[1]);
798 else if(complexityVectors.rows == 3)
801 Eigen::Vector3f n1(complexityVectors.at<
float>(0,0), complexityVectors.at<
float>(0,1), complexityVectors.at<
float>(0,2));
802 Eigen::Vector3f n2(complexityVectors.at<
float>(1,0), complexityVectors.at<
float>(1,1), complexityVectors.at<
float>(1,2));
805 Eigen::Vector3f vp = n1*a;
810 UWARN(
"Normals low complexity: Limiting translation from (%f,%f,%f) to (%f,%f,%f)",
811 v[0], v[1], v[2], vp[0], vp[1], vp[2]);
816 UWARN(
"not supposed to be here!");
817 v = Eigen::Vector3f(0,0,0);
821 t =
Transform(v[0], v[1], v[2], roll, pitch, yaw);
822 icpT = guess * t.
inverse() * guessInv;
828 UWARN(
"Even if complexity is low (%f), PointToPoint transformation is accepted \"as is\" (%s=2)",
830 Parameters::kIcpPointToPlaneLowComplexityStrategy().c_str());
831 if(fromCloudRegistered->empty())
835 else if(fromCloudRegistered->empty())
848 if(!icpT.
isNull() && hasConverged)
850 float ix,iy,iz, iroll,ipitch,iyaw;
861 msg =
uFormat(
"Cannot compute transform (ICP correction too large -> %f m %f rad, limits=%f m, %f rad)",
871 int maxLaserScans = maxLaserScansTo?maxLaserScansTo:maxLaserScansFrom;
872 UDEBUG(
"Max scans=%d (from=%d, to=%d)", maxLaserScans, maxLaserScansFrom, maxLaserScansTo);
876 correspondencesRatio = float(correspondences)/float(maxLaserScans);
880 static bool warningShown =
false;
883 UWARN(
"Maximum laser scans points not set for signature %d, correspondences ratio set relative instead of absolute! This message will only appear once.",
887 correspondencesRatio = float(correspondences)/float(toScan.
size()>fromScan.
size()?toScan.
size():fromScan.
size());
892 UDEBUG(
"%d->%d hasConverged=%s, variance=%f, correspondences=%d/%d (%f%%), from guess: trans=%f rot=%f",
893 dataTo.
id(), dataFrom.
id(),
894 hasConverged?
"true":
"false",
897 maxLaserScans>0?maxLaserScans:(int)(toScan.
size()>fromScan.
size()?toScan.
size():fromScan.
size()),
898 correspondencesRatio*100.0
f,
902 if(correspondences == 0)
904 UWARN(
"Transform is found (%s) but no correspondences has been found!? Variance is unknown!",
909 info.
covariance = cv::Mat::eye(6,6,CV_64FC1)*variance;
910 info.
covariance(cv::Range(3,6),cv::Range(3,6))/=10.0;
916 info.
covariance(cv::Range(3,5),cv::Range(3,5))/=10.0;
924 msg =
uFormat(
"Cannot compute transform (cor=%d corrRatio=%f/%f maxLaserScans=%d)",
930 transform = icpT.
inverse()*guess;
934 toPrefix+=
"_registered";
958 msg =
uFormat(
"Cannot compute transform (converged=%s var=%f)",
959 hasConverged?
"true":
"false", variance);
966 msg =
"Laser scans empty ?!?";
972 msg =
"RegistrationIcp cannot do registration with a null guess.";
static std::string homeDir()
GLM_FUNC_DECL T roll(detail::tquat< T, P > const &x)
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
void * _libpointmatcherICPFilters
int _pointToPlaneLowComplexityStrategy
pms::Registrar< OutlierFilter > OutlierFilterRegistrar
RegistrationIcp(const ParametersMap ¶meters=ParametersMap(), Registration *child=0)
void * _libpointmatcherICP
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP transformPointCloud(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const Transform &transform)
void setLaserScan(const LaserScan &laserScan, bool clearPreviousData=true)
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)
pcl::PCLPointCloud2::Ptr RTABMAP_EXP laserScanToPointCloud2(const LaserScan &laserScan, const Transform &transform=Transform())
GLM_FUNC_DECL genType e()
float _pointToPlaneGroundNormalsUp
const cv::Mat & data() const
std::map< std::string, std::string > ParametersMap
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.
bool _libpointmatcherIntensity
Some conversion functions.
GLM_FUNC_DECL T pitch(detail::tquat< T, P > const &x)
pms::Registrar< Matcher > MatcherRegistrar
virtual Transform computeTransformationImpl(Signature &from, Signature &to, Transform guess, RegistrationInfo &info) const
Parametrizable::Parameters Parameters
#define UASSERT(condition)
float _maxCorrespondenceDistance
LaserScan RTABMAP_EXP commonFiltering(const LaserScan &scan, int downsamplingStep, float rangeMin=0.0f, float rangeMax=0.0f, float voxelSize=0.0f, int normalK=0, float normalRadius=0.0f, float groundNormalsUp=0.0f)
float _correspondenceRatio
T uMax3(const T &a, const T &b, const T &c)
pms::Registrar< ErrorMinimizer > ErrorMinimizerRegistrar
virtual ~RegistrationIcp()
bool _ccFilterOutFarthestPoints
#define UASSERT_MSG(condition, msg_str)
pcl::PointCloud< pcl::PointXYZINormal >::Ptr RTABMAP_EXP laserScanToPointCloudINormal(const LaserScan &laserScan, const Transform &transform=Transform(), float intensity=0.0f)
static const PointMatcher & get()
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)
unsigned int _ccSamplingLimit
float _pointToPlaneRadius
virtual void parseParameters(const ParametersMap ¶meters)
std::string UTILITE_EXP uReplaceChar(const std::string &str, char before, char after)
static ULogger::Level level()
pms::Registrar< DataPointsFilter > DataPointsFilterRegistrar
float _pointToPlaneMinComplexity
const LaserScan & laserScanRaw() const
GLM_FUNC_DECL genType max(genType const &x, genType const &y)
SensorData & sensorData()
float icpStructuralComplexity
rtabmap::Transform icpCC(const pcl::PointCloud< pcl::PointXYZI >::Ptr &fromCloud, pcl::PointCloud< pcl::PointXYZI >::Ptr &toCloud, int maxIterations=150, double minRMSDecrease=0.00001, bool force3DoF=false, bool force4DoF=false, int samplingLimit=50000, double finalOverlapRatio=0.85, bool filterOutFarthestPoints=false, double maxFinalRMS=0.2, float *finalRMS=0, std::string *errorMsg=0)
ULogger class and convenient macros.
float _libpointmatcherEpsilon
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
pcl::PointCloud< pcl::PointNormal >::Ptr RTABMAP_EXP removeNaNNormalsFromPointCloud(const pcl::PointCloud< pcl::PointNormal >::Ptr &cloud)
static std::string formatName(const Format &format)
pms::Registrar< TransformationChecker > TransformationCheckerRegistrar
rtabmap::LaserScan laserScanFromDP(const DP &cloud, const rtabmap::Transform &localTransform=rtabmap::Transform::getIdentity())
pcl::PointCloud< pcl::PointXYZI >::Ptr RTABMAP_EXP laserScanToPointCloudI(const LaserScan &laserScan, const Transform &transform=Transform(), float intensity=0.0f)
DP laserScanToDP(const rtabmap::LaserScan &scan, bool ignoreLocalTransform=false)
std::string UTILITE_EXP uFormat(const char *fmt,...)
std::string UTILITE_EXP uNumber2Str(unsigned int number)
virtual void parseParameters(const ParametersMap ¶meters)
std::string _debugExportFormat
std::string _libpointmatcherConfig
Transform localTransform() const
Matrix TransformationParameters
float RTABMAP_EXP computeNormalsComplexity(const LaserScan &scan, const Transform &t=Transform::getIdentity(), cv::Mat *pcaEigenVectors=0, cv::Mat *pcaEigenValues=0)