47 #include <opencv2/calib3d/calib3d.hpp> 49 #include <pcl/common/io.h> 52 #define ISFINITE(value) _finite(value) 54 #define ISFINITE(value) std::isfinite(value) 61 maximumMapSize_(
Parameters::defaultOdomF2MMaxSize()),
62 keyFrameThr_(
Parameters::defaultOdomKeyFrameThr()),
63 visKeyFrameThr_(
Parameters::defaultOdomVisKeyFrameThr()),
64 maxNewFeatures_(
Parameters::defaultOdomF2MMaxNewFeatures()),
65 scanKeyFrameThr_(
Parameters::defaultOdomScanKeyFrameThr()),
66 scanMaximumMapSize_(
Parameters::defaultOdomF2MScanMaxSize()),
67 scanSubtractRadius_(
Parameters::defaultOdomF2MScanSubtractRadius()),
68 scanSubtractAngle_(
Parameters::defaultOdomF2MScanSubtractAngle()),
69 bundleAdjustment_(
Parameters::defaultOdomF2MBundleAdjustment()),
70 bundleMaxFrames_(
Parameters::defaultOdomF2MBundleAdjustmentMaxFrames()),
73 lastFrameOldestNewId_(0),
104 UWARN(
"Selected bundle adjustment approach (\"%s\"=\"%d\") is not available, " 105 "local bundle adjustment is then disabled.", Parameters::kOdomF2MBundleAdjustment().c_str(),
bundleAdjustment_);
115 int corType = Parameters::defaultVisCorType();
119 UWARN(
"%s=%d is not supported by OdometryF2M, using Features matching approach instead (type=0).",
120 Parameters::kVisCorType().c_str(),
129 UWARN(
"%s=%d cannot be used with registration not done only with images (%s=%s), disabling bundle adjustment.",
130 Parameters::kOdomF2MBundleAdjustment().c_str(),
132 Parameters::kRegStrategy().c_str(),
133 uValue(bundleParameters, Parameters::kRegStrategy(),
uNumber2Str(Parameters::defaultRegStrategy())).c_str());
197 UERROR(
"Odometry bundle adjustment doesn't work with multi-cameras. It is disabled.");
200 bool addKeyFrame =
false;
201 int totalBundleWordReferencesUsed = 0;
202 int totalBundleOutliers = 0;
203 float bundleTime = 0.0f;
216 std::map<int, cv::Point3f> points3DMap;
217 std::map<int, Transform> bundlePoses;
218 std::multimap<int, Link> bundleLinks;
219 std::map<int, CameraModel> bundleModels;
220 std::map<int, StereoCameraModel> bundleStereoModels;
222 for(
int guessIteration=0;
235 bundleModels.clear();
236 bundleStereoModels.clear();
238 float maxCorrespondenceDistance = 0.0f;
239 float pmOutlierRatio = 0.0f;
246 maxCorrespondenceDistance = Parameters::defaultIcpMaxCorrespondenceDistance();
247 pmOutlierRatio = Parameters::defaultIcpPMOutlierRatio();
256 if(guessIteration == 1)
258 UWARN(
"Failed to find a transformation with the provided guess (%s), trying again without a guess.", guess.
prettyPrint().c_str());
268 if(maxCorrespondenceDistance>0.0
f)
280 if(!transform.isNull())
288 UDEBUG(
"Local Bundle Adjustment");
296 UERROR(
"Bundle Adjustment cannot be used with a registration approach recomputing features from the \"from\" signature (e.g., Optical Flow).");
310 uFormat(
"Frame %d already added! Make sure the input frames have unique IDs!",
lastFrame_->
id()).c_str());
315 bundlePoses.insert(std::make_pair(
lastFrame_->
id(), transform));
335 UFATAL(
"no valid camera model to do odometry bundle adjustment!");
337 bundleModels.insert(std::make_pair(
lastFrame_->
id(), model));
341 std::map<int, std::map<int, cv::Point3f> > wordReferences;
342 for(
unsigned int i=0; i<regInfo.
inliersIDs.size(); ++i)
347 std::multimap<int, cv::Point3f>::const_iterator iter3D = tmpMap.
getWords3().find(wordId);
349 points3DMap.insert(*iter3D);
351 std::multimap<int, cv::KeyPoint>::const_iterator iter2D =
lastFrame_->
getWords().find(wordId);
357 std::map<int, cv::Point3f> references;
364 for(std::map<int, cv::Point3f>::iterator jter=refIter->second.begin(); jter!=refIter->second.end(); ++jter)
366 if(oi++ % step == 0 && bundlePoses.find(jter->first)!=bundlePoses.end())
368 references.insert(*jter);
369 ++totalBundleWordReferencesUsed;
373 if(refIter->second.size() > 1)
375 if(references.insert(*refIter->second.rbegin()).second)
377 ++totalBundleWordReferencesUsed;
386 references.insert(std::make_pair(
lastFrame_->
id(), cv::Point3f(iter2D->second.pt.x, iter2D->second.pt.y, pt3d.z)));
388 wordReferences.insert(std::make_pair(wordId, references));
399 std::set<int> sbaOutliers;
401 bundlePoses =
sba_->
optimizeBA(-
lastFrame_->
id(), bundlePoses, bundleLinks, bundleModels, points3DMap, wordReferences, &sbaOutliers);
402 bundleTime = bundleTimer.
ticks();
404 totalBundleOutliers = (int)sbaOutliers.size();
406 UDEBUG(
"bundleTime=%fs (poses=%d wordRef=%d outliers=%d)", bundleTime, (
int)bundlePoses.size(), (int)
bundleWordReferences_.size(), (int)sbaOutliers.size());
413 UDEBUG(
"Local Bundle Adjustment Before: %s", transform.prettyPrint().c_str());
416 if(!bundlePoses.rbegin()->second.isNull())
418 if(sbaOutliers.size())
420 std::vector<int> newInliers(regInfo.
inliersIDs.size());
422 for(
unsigned int i=0; i<regInfo.
inliersIDs.size(); ++i)
424 if(sbaOutliers.find(regInfo.
inliersIDs[i]) == sbaOutliers.end())
429 newInliers.resize(oi);
430 UDEBUG(
"BA outliers ratio %f",
float(sbaOutliers.size())/
float(regInfo.
inliersIDs.size()));
431 regInfo.
inliers = (int)newInliers.size();
441 transform = bundlePoses.rbegin()->second;
442 bundleLinks.find(
bundlePoses_.rbegin()->first)->second.setTransform(
bundlePoses_.rbegin()->second.inverse()*transform);
445 UDEBUG(
"Local Bundle Adjustment After : %s", transform.prettyPrint().c_str());
449 UWARN(
"Local bundle adjustment failed! transform is not refined.");
454 if(!transform.isNull())
461 if(transform.isNull())
463 if(guessIteration == 1)
465 UWARN(
"Trial with no guess still fail.");
473 UWARN(
"Unknown registration error");
476 else if(guessIteration == 1)
478 UWARN(
"Trial with no guess succeeded!");
486 bool modified =
false;
491 std::multimap<int, cv::KeyPoint> mapWords = tmpMap.
getWords();
492 std::multimap<int, cv::Point3f> mapPoints = tmpMap.
getWords3();
503 addKeyFrame = addKeyFrame || addVisualKeyFrame || addGeometricKeyFrame;
513 UDEBUG(
"Update local map");
516 UASSERT(mapWords.size() == mapPoints.size());
517 UASSERT(mapPoints.size() == mapDescriptors.size());
532 for(std::map<int, cv::Point3f>::iterator iter=points3DMap.begin(); iter!=points3DMap.end(); ++iter)
534 UASSERT(mapPoints.count(iter->first) == 1);
536 mapPoints.find(iter->first)->second = iter->second;
541 std::multimap<float, std::pair<int, std::pair<cv::KeyPoint, std::pair<cv::Point3f, cv::Mat> > > > newIds;
543 std::multimap<int, cv::KeyPoint>::const_iterator iter2D =
lastFrame_->
getWords().begin();
546 std::set<int> seenStatusUpdated;
560 UFATAL(
"no valid camera model!");
567 if(mapPoints.find(iter->first) == mapPoints.end())
570 std::make_pair(iter2D->second.response>0?1.0f/iter2D->second.response:0.0f,
571 std::make_pair(iter->first,
572 std::make_pair(iter2D->second,
573 std::make_pair(iter->second, iterDesc->second)))));
579 std::multimap<int, cv::KeyPoint>::iterator iterKpts = mapWords.find(iter->first);
580 if(iterKpts!=mapWords.end())
582 iterKpts->second.octave = iter2D->second.octave;
586 iterBundlePosesRef->second += 1;
592 std::map<int, cv::Point3f> framePt;
593 framePt.insert(std::make_pair(
lastFrame_->
id(), cv::Point3f(iter2D->second.pt.x, iter2D->second.pt.y, pt3d.z)));
604 UDEBUG(
"newIds=%d", (
int)newIds.size());
608 for(std::multimap<
float, std::pair<
int, std::pair<cv::KeyPoint, std::pair<cv::Point3f, cv::Mat> > > >::reverse_iterator iter=newIds.rbegin();
619 iterBundlePosesRef->second += 1;
625 std::map<int, cv::Point3f> framePt;
626 framePt.insert(std::make_pair(
lastFrame_->
id(), cv::Point3f(iter->second.second.first.pt.x, iter->second.second.first.pt.y, pt3d.z)));
631 bundleWordReferences_.find(iter->second.first)->second.insert(std::make_pair(
lastFrame_->
id(), cv::Point3f(iter->second.second.first.pt.x, iter->second.second.first.pt.y, pt3d.z)));
636 mapWords.insert(std::make_pair(iter->second.first, iter->second.second.first));
637 mapPoints.insert(std::make_pair(iter->second.first,
util3d::transformPoint(iter->second.second.second.first, newFramePose)));
638 mapDescriptors.insert(std::make_pair(iter->second.first, iter->second.second.second.second));
657 for(
unsigned int i=0; i<regInfo.
projectedIDs.size(); ++i)
665 UDEBUG(
"projected added=%d/%d minLastFrameId=%d", oi, (
int)regInfo.
projectedIDs.size(), lastFrameOldestNewId);
667 for(
unsigned int i=0; i<ids.size() && (int)mapPoints.size() >
maximumMapSize_ && mapPoints.size() >= newIds.size(); ++i)
670 if(inliers.find(
id) == inliers.end())
675 for(std::map<int, cv::Point3f>::iterator iterFrame = iterRef->second.begin(); iterFrame != iterRef->second.end(); ++iterFrame)
686 mapDescriptors.erase(
id);
693 std::multimap<int, cv::Mat>::iterator iterMapDescriptors = mapDescriptors.begin();
694 std::multimap<int, cv::KeyPoint>::iterator iterMapWords = mapWords.begin();
695 for(std::multimap<int, cv::Point3f>::iterator iter = mapPoints.begin();
696 iter!=mapPoints.end() && (int)mapPoints.size() >
maximumMapSize_ && mapPoints.size() >= newIds.size();)
698 if(inliers.find(iter->first) == inliers.end())
700 std::map<int, std::map<int, cv::Point3f> >::iterator iterRef =
bundleWordReferences_.find(iter->first);
703 for(std::map<int, cv::Point3f>::iterator iterFrame = iterRef->second.begin(); iterFrame != iterRef->second.end(); ++iterFrame)
713 mapPoints.erase(iter++);
714 mapDescriptors.erase(iterMapDescriptors++);
715 mapWords.erase(iterMapWords++);
721 ++iterMapDescriptors;
726 Link * previousLink = 0;
729 if(iter->second <= 0)
735 UASSERT(previousLink->
to() == iter->first);
736 *previousLink = previousLink->
merge(
bundleLinks_.find(iter->first)->second, previousLink->type());
760 UDEBUG(
"Update local features map = %fs", tmpTimer.
ticks());
771 pcl::IndicesPtr frameCloudNormalsIndices(
new std::vector<int>);
777 pcl::IndicesPtr(
new std::vector<int>),
779 pcl::IndicesPtr(
new std::vector<int>),
782 newPoints = frameCloudNormalsIndices->size();
786 newPoints = mapCloudNormals->size();
791 scansBuffer_.push_back(std::make_pair(frameCloudNormals, frameCloudNormalsIndices));
794 UDEBUG(
"scansBuffer=%d, mapSize=%d newPoints=%d maxPoints=%d",
796 int(mapCloudNormals->size()),
804 mapCloudNormals->clear();
805 std::list<int> toRemove;
820 pcl::PointCloud<pcl::PointNormal> tmp;
822 *mapCloudNormals += tmp;
833 std::vector<std::pair<pcl::PointCloud<pcl::PointNormal>::Ptr, pcl::IndicesPtr> > scansTmp(
scansBuffer_.size()-i);
837 UASSERT(oi < (
int)scansTmp.size());
848 pcl::PointCloud<pcl::PointNormal> tmp;
850 *mapCloudNormals += tmp;
859 Transform mapViewpoint(-newFramePose.
x(), -newFramePose.
y(),0,0,0,0);
864 Transform mapViewpoint(-newFramePose.
x(), -newFramePose.
y(), -newFramePose.
z(),0,0,0);
870 UDEBUG(
"Update local scan map = %fs", tmpTimer.
ticks());
931 regInfo.
covariance = cv::Mat::eye(6,6,CV_64FC1)*9999.0;
933 bool frameValid =
false;
944 std::multimap<int, cv::KeyPoint> words;
945 std::multimap<int, cv::Point3f> transformedPoints;
946 std::multimap<int, int> mapPointWeights;
947 std::multimap<int, cv::Mat> descriptors;
949 std::multimap<int, cv::KeyPoint>::const_iterator wordsIter =
lastFrame_->
getWords().begin();
951 for (std::multimap<int, cv::Point3f>::const_iterator iter =
lastFrame_->
getWords3().begin();
953 ++iter, ++descIter, ++wordsIter)
957 words.insert(*wordsIter);
958 transformedPoints.insert(std::make_pair(iter->first,
util3d::transformPoint(iter->second, newFramePose)));
959 mapPointWeights.insert(std::make_pair(iter->first, 0));
960 descriptors.insert(*descIter);
977 UFATAL(
"no valid camera model!");
981 for(std::multimap<int, cv::KeyPoint>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
983 if(words.count(iter->first) == 1)
986 std::map<int, cv::Point3f> framePt;
998 framePt.insert(std::make_pair(
lastFrame_->
id(), cv::Point3f(iter->second.pt.x, iter->second.pt.y, d)));
1023 UFATAL(
"invalid camera model!");
1045 scansBuffer_.push_back(std::make_pair(mapCloudNormals, pcl::IndicesPtr(
new std::vector<int>)));
1048 Transform mapViewpoint(-newFramePose.
x(), -newFramePose.
y(),0,0,0,0);
1059 Transform mapViewpoint(-newFramePose.
x(), -newFramePose.
y(), -newFramePose.
z(),0,0,0);
1072 UWARN(
"Missing scan to initialize odometry.");
1118 info->
reg = regInfo;
1126 UINFO(
"Odom update time = %fs lost=%s features=%d inliers=%d/%d variance:lin=%f, ang=%f local_map=%d local_scan_map=%d",
1128 output.
isNull()?
"true":
"false",
const std::multimap< int, cv::Point3f > & getWords3() const
LaserScan RTABMAP_EXP laserScanFromPointCloud(const pcl::PCLPointCloud2 &cloud, bool filterNaNs=true)
bool RTABMAP_EXP isFinite(const cv::Point3f &pt)
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
int getMinVisualCorrespondences() const
pcl::PointCloud< pcl::PointXYZRGB >::Ptr RTABMAP_EXP subtractFiltering(const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &cloud, const pcl::PointCloud< pcl::PointXYZRGB >::Ptr &substractCloud, float radiusSearch, int minNeighborsInRadius=1)
ParametersMap parameters_
unsigned int framesProcessed() const
std::map< int, CameraModel > localBundleModels
cv::Point3f RTABMAP_EXP transformPoint(const cv::Point3f &pt, const Transform &transform)
const cv::Mat & data() const
OdometryF2M(const rtabmap::ParametersMap ¶meters=rtabmap::ParametersMap())
const std::multimap< int, cv::KeyPoint > & getWords() const
void setWords3(const std::multimap< int, cv::Point3f > &words3)
bool isInfoDataFilled() const
virtual void reset(const Transform &initialPose=Transform::getIdentity())
void setWords(const std::multimap< int, cv::KeyPoint > &words)
Transform computeTransformationMod(Signature &from, Signature &to, Transform guess=Transform::getIdentity(), RegistrationInfo *info=0) const
std::map< int, cv::Point3f > localMap
Registration * regPipeline_
std::pair< std::string, std::string > ParametersPair
const cv::Mat & descriptors() const
std::map< std::string, std::string > ParametersMap
virtual Transform computeTransform(SensorData &data, const Transform &guess=Transform(), OdometryInfo *info=0)
const std::vector< cv::KeyPoint > & keypoints() const
const std::multimap< int, cv::Mat > & getWordsDescriptors() const
const Transform & getPose() const
Basic mathematics functions.
std::vector< int > inliersIDs
Some conversion functions.
const LaserScan & laserScanRaw() const
float scanSubtractRadius_
int localBundleConstraints
static bool isAvailable(Optimizer::Type type)
GLM_FUNC_DECL genType step(genType const &edge, genType const &x)
cv::Mat RTABMAP_EXP laserScan2dFromPointCloud(const pcl::PointCloud< pcl::PointXYZ > &cloud, const Transform &transform=Transform(), bool filterNaNs=true)
#define UASSERT(condition)
bool isValidForProjection() const
const CameraModel & left() const
std::map< int, int > bundlePoseReferences_
int lastFrameOldestNewId_
#define UASSERT_MSG(condition, msg_str)
std::vector< std::pair< pcl::PointCloud< pcl::PointNormal >::Ptr, pcl::IndicesPtr > > scansBuffer_
std::vector< int > projectedIDs
Link merge(const Link &link, Type outputType) const
std::map< K, V > uMultimapToMap(const std::multimap< K, V > &m)
bool isScanRequired() const
std::map< int, Transform > bundlePoses_
virtual void parseParameters(const ParametersMap ¶meters)
std::map< int, Transform > localBundlePoses
void setWordsDescriptors(const std::multimap< int, cv::Mat > &descriptors)
Transform localTransform() const
const std::vector< CameraModel > & cameraModels() const
static Registration * create(const ParametersMap ¶meters)
virtual std::map< int, Transform > optimizeBA(int rootId, const std::map< int, Transform > &poses, const std::multimap< int, Link > &links, const std::map< int, CameraModel > &models, std::map< int, cv::Point3f > &points3DMap, const std::map< int, std::map< int, cv::Point3f > > &wordReferences, std::set< int > *outliers=0)
std::multimap< int, cv::KeyPoint > words
SensorData & sensorData()
std::multimap< int, Link >::iterator RTABMAP_EXP findLink(std::multimap< int, Link > &links, int from, int to, bool checkBothWays=true)
pcl::PointCloud< pcl::PointNormal >::Ptr RTABMAP_EXP laserScanToPointCloudNormal(const LaserScan &laserScan, const Transform &transform=Transform())
ULogger class and convenient macros.
const StereoCameraModel & stereoCameraModel() const
bool isImageRequired() const
std::vector< int > matchesIDs
virtual void reset(const Transform &initialPose=Transform::getIdentity())
std::multimap< int, Link > bundleLinks_
std::string UTILITE_EXP uFormat(const char *fmt,...)
std::string UTILITE_EXP uNumber2Str(unsigned int number)
static Optimizer * create(const ParametersMap ¶meters)
std::map< int, CameraModel > bundleModels_
V uValue(const std::map< K, V > &m, const K &key, const V &defaultValue=V())
std::map< int, std::map< int, cv::Point3f > > bundleWordReferences_
void setFeatures(const std::vector< cv::KeyPoint > &keypoints, const std::vector< cv::Point3f > &keypoints3D, const cv::Mat &descriptors)
const std::vector< cv::Point3f > & keypoints3D() const
RegistrationInfo copyWithoutData() const
void uInsert(std::map< K, V > &map, const std::pair< K, V > &pair)
const Transform & localTransform() const
void setLaserScanRaw(const LaserScan &laserScanRaw)