45 #include <opencv2/calib3d/calib3d.hpp>
47 #include <pcl/common/io.h>
50 #define ISFINITE(value) _finite(value)
52 #define ISFINITE(value) std::isfinite(value)
59 maximumMapSize_(
Parameters::defaultOdomF2MMaxSize()),
60 keyFrameThr_(
Parameters::defaultOdomKeyFrameThr()),
61 visKeyFrameThr_(
Parameters::defaultOdomVisKeyFrameThr()),
62 maxNewFeatures_(
Parameters::defaultOdomF2MMaxNewFeatures()),
63 scanKeyFrameThr_(
Parameters::defaultOdomScanKeyFrameThr()),
64 scanMaximumMapSize_(
Parameters::defaultOdomF2MScanMaxSize()),
65 scanSubtractRadius_(
Parameters::defaultOdomF2MScanSubtractRadius()),
66 scanSubtractAngle_(
Parameters::defaultOdomF2MScanSubtractAngle()),
67 scanMapMaxRange_(
Parameters::defaultOdomF2MScanRange()),
68 bundleAdjustment_(
Parameters::defaultOdomF2MBundleAdjustment()),
69 bundleMaxFrames_(
Parameters::defaultOdomF2MBundleAdjustmentMaxFrames()),
70 validDepthRatio_(
Parameters::defaultOdomF2MValidDepthRatio()),
71 pointToPlaneK_(
Parameters::defaultIcpPointToPlaneK()),
72 pointToPlaneRadius_(
Parameters::defaultIcpPointToPlaneRadius()),
75 lastFrameOldestNewId_(0),
113 UWARN(
"Selected bundle adjustment approach (\"%s\"=\"%d\") is not available, "
114 "local bundle adjustment is then disabled.", Parameters::kOdomF2MBundleAdjustment().
c_str(),
bundleAdjustment_);
124 int corType = Parameters::defaultVisCorType();
128 UWARN(
"%s=%d is not supported by OdometryF2M, using Features matching approach instead (type=0).",
129 Parameters::kVisCorType().
c_str(),
135 int estType = Parameters::defaultVisEstimationType();
139 UWARN(
"%s=%d is not supported by OdometryF2M, using 2D->3D approach instead (type=1).",
140 Parameters::kVisEstimationType().
c_str(),
146 bool forwardEst = Parameters::defaultVisForwardEstOnly();
150 UWARN(
"%s=false is not supported by OdometryF2M, setting to true.",
151 Parameters::kVisForwardEstOnly().
c_str());
161 UWARN(
"%s=%d cannot be used with registration not done only with images (%s=%s), disabling bundle adjustment.",
162 Parameters::kOdomF2MBundleAdjustment().
c_str(),
164 Parameters::kRegStrategy().
c_str(),
165 uValue(bundleParameters, Parameters::kRegStrategy(),
uNumber2Str(Parameters::defaultRegStrategy())).
c_str());
220 if(
data.imu().empty())
223 data.setIMU(
IMU(cv::Vec4d(
q.x(),
q.y(),
q.z(),
q.w()), cv::Mat(), cv::Vec3d(), cv::Mat(), cv::Vec3d(), cv::Mat()));
236 bool addKeyFrame =
false;
237 int totalBundleWordReferencesUsed = 0;
238 int totalBundleOutliers = 0;
239 float bundleTime = 0.0f;
240 bool visDepthAsMask = Parameters::defaultVisDepthAsMask();
243 std::vector<CameraModel> lastFrameModels;
260 model.localTransform(),
263 lastFrameModels.push_back(
model);
266 UDEBUG(
"lastFrameModels=%ld", lastFrameModels.size());
279 std::map<int, cv::Point3f> points3DMap;
280 std::map<int, Transform> bundlePoses;
281 std::multimap<int, Link> bundleLinks;
282 std::map<int, std::vector<CameraModel> > bundleModels;
284 for(
int guessIteration=0;
295 bundleModels.clear();
297 float maxCorrespondenceDistance = 0.0f;
298 float outlierRatio = 0.0f;
305 maxCorrespondenceDistance = Parameters::defaultIcpMaxCorrespondenceDistance();
306 outlierRatio = Parameters::defaultIcpOutlierRatio();
315 if(guessIteration == 1)
317 UWARN(
"Failed to find a transformation with the provided guess (%s), trying again without a guess.", guess.
prettyPrint().c_str());
327 if(maxCorrespondenceDistance>0.0
f)
345 !lastFrameModels.empty() &&
348 UDEBUG(
"Local Bundle Adjustment");
356 UERROR(
"Bundle Adjustment cannot be used with a registration approach recomputing "
357 "features from the \"from\" signature (e.g., Optical Flow) that would change "
358 "their ids (size=old=%ld new=%ld first/last: old=%d->%d new=%d->%d).",
376 uFormat(
"Frame %d already added! Make sure the input frames have unique IDs!",
lastFrame_->
id()).c_str());
385 bundleModels.insert(std::make_pair(
lastFrame_->
id(), lastFrameModels));
388 std::map<int, std::map<int, FeatureBA> > wordReferences;
394 std::multimap<int, int>::const_iterator iter3D = tmpMap.
getWords().find(wordId);
396 points3DMap.insert(std::make_pair(wordId, tmpMap.
getWords3()[iter3D->second]));
402 std::map<int, FeatureBA> references;
409 for(std::map<int, FeatureBA>::iterator jter=refIter->second.begin(); jter!=refIter->second.end(); ++jter)
411 if(oi++ %
step == 0 && bundlePoses.find(jter->first)!=bundlePoses.end())
413 references.insert(*jter);
414 ++totalBundleWordReferencesUsed;
418 if(refIter->second.size() > 1)
420 if(references.insert(*refIter->second.rbegin()).second)
422 ++totalBundleWordReferencesUsed;
433 if(lastFrameModels.size()>1)
435 UASSERT(lastFrameModels[0].imageWidth()>0);
436 float subImageWidth = lastFrameModels[0].imageWidth();
437 cameraIndex =
int(kpt.pt.x / subImageWidth);
438 UASSERT(cameraIndex < (
int)lastFrameModels.size());
439 kpt.pt.x = kpt.pt.x - (subImageWidth*
float(cameraIndex));
452 wordReferences.insert(std::make_pair(wordId, references));
463 std::set<int> sbaOutliers;
465 bundlePoses =
sba_->
optimizeBA(-
lastFrame_->
id(), bundlePoses, bundleLinks, bundleModels, points3DMap, wordReferences, &sbaOutliers);
466 bundleTime = bundleTimer.
ticks();
468 totalBundleOutliers = (
int)sbaOutliers.size();
470 UDEBUG(
"bundleTime=%fs (poses=%d wordRef=%d outliers=%d)", bundleTime, (
int)bundlePoses.size(), (
int)
bundleWordReferences_.size(), (
int)sbaOutliers.size());
473 info->localBundlePoses = bundlePoses;
474 info->localBundleModels = bundleModels;
477 UDEBUG(
"Local Bundle Adjustment Before: %s",
transform.prettyPrint().c_str());
480 if(!bundlePoses.rbegin()->second.isNull())
482 if(sbaOutliers.size())
484 std::vector<int> newInliers(regInfo.
inliersIDs.size());
488 if(sbaOutliers.find(regInfo.
inliersIDs[
i]) == sbaOutliers.end())
493 newInliers.resize(oi);
494 UDEBUG(
"BA outliers ratio %f",
float(sbaOutliers.size())/
float(regInfo.
inliersIDs.size()));
505 transform = bundlePoses.rbegin()->second;
513 float rollImu,pitchImu,
yaw;
514 iter->second.transform().getEulerAngles(rollImu, pitchImu,
yaw);
539 UDEBUG(
"Local Bundle Adjustment After : %s",
transform.prettyPrint().c_str());
543 UWARN(
"Local bundle adjustment failed! transform is not refined.");
557 if(guessIteration == 1)
559 UWARN(
"Trial with no guess still fail.");
574 UWARN(
"Unknown registration error");
577 else if(guessIteration == 1)
579 UWARN(
"Trial with no guess succeeded!");
587 bool modified =
false;
592 std::multimap<int, int> mapWords = tmpMap.
getWords();
593 std::vector<cv::KeyPoint> mapWordsKpts = tmpMap.
getWordsKpts();
594 std::vector<cv::Point3f> mapPoints = tmpMap.
getWords3();
607 addKeyFrame = addKeyFrame || addVisualKeyFrame || addGeometricKeyFrame;
617 UDEBUG(
"Update local map");
620 UASSERT(mapWords.size() == mapPoints.size());
621 UASSERT(mapWords.size() == mapWordsKpts.size());
622 UASSERT((
int)mapPoints.size() == mapDescriptors.rows);
633 if(
iter != bundleLinks.end())
643 for(std::map<int, cv::Point3f>::iterator
iter=points3DMap.begin();
iter!=points3DMap.end(); ++
iter)
647 mapPoints[mapWords.find(
iter->first)->second] =
iter->second;
652 std::multimap<float, std::pair<int, std::pair<cv::KeyPoint, std::pair<cv::Point3f, std::pair<cv::Mat, int> > > > > newIds;
655 std::set<int> seenStatusUpdated;
658 bool addPointsWithoutDepth =
false;
659 if(!visDepthAsMask && validDepthRatio_ < 1.0f && !lastFrame_->getWords3().
empty())
661 int ptsWithDepth = 0;
673 if(!addPointsWithoutDepth)
675 UWARN(
"Not enough points with valid depth in current frame (%d/%d=%f < %s=%f), points without depth are not added to map.",
680 if(!lastFrameModels.empty())
688 if(lastFrameModels.size()>1)
690 UASSERT(lastFrameModels[0].imageWidth()>0);
691 float subImageWidth = lastFrameModels[0].imageWidth();
692 cameraIndex =
int(kpt.pt.x / subImageWidth);
693 UASSERT(cameraIndex < (
int)lastFrameModels.size());
694 kpt.pt.x = kpt.pt.x - (subImageWidth*
float(cameraIndex));
697 if(mapWords.find(
iter->first) == mapWords.end())
702 std::make_pair(kpt.response>0?1.0f/kpt.response:0.0f,
703 std::make_pair(
iter->first,
713 std::multimap<int, int>::iterator iterKpts = mapWords.find(
iter->first);
714 if(iterKpts!=mapWords.end() && !mapWordsKpts.empty())
716 mapWordsKpts[iterKpts->second].octave = kpt.octave;
720 iterBundlePosesRef->second += 1;
730 std::map<int, FeatureBA> framePt;
741 UDEBUG(
"newIds=%d", (
int)newIds.size());
746 for(std::multimap<
float, std::pair<
int, std::pair<cv::KeyPoint, std::pair<cv::Point3f, std::pair<cv::Mat, int> > > > >::reverse_iterator
iter=newIds.rbegin();
752 int cameraIndex =
iter->second.second.second.second.second;
758 iterBundlePosesRef->second += 1;
768 std::map<int, FeatureBA> framePt;
779 mapWords.insert(mapWords.end(), std::make_pair(
iter->second.first, mapWords.size()));
780 mapWordsKpts.push_back(
iter->second.second.first);
781 cv::Point3f pt =
iter->second.second.second.first;
785 float x =
iter->second.second.first.pt.x;
786 float y =
iter->second.second.first.pt.y;
788 lastFrameModels[cameraIndex].imageSize(),
791 lastFrameModels[cameraIndex].
cx(),
792 lastFrameModels[cameraIndex].
cy(),
793 lastFrameModels[cameraIndex].
fx(),
794 lastFrameModels[cameraIndex].
fy());
795 float scaleInf = (0.05 * lastFrameModels[cameraIndex].fx()) / 0.01;
796 pt =
util3d::transformPoint(cv::Point3f(ray[0]*scaleInf, ray[1]*scaleInf, ray[2]*scaleInf), lastFrameModels[cameraIndex].localTransform());
799 mapDescriptors.push_back(
iter->second.second.second.second.first);
827 UDEBUG(
"projected added=%d/%d minLastFrameId=%d", oi, (
int)regInfo.
projectedIDs.size(), lastFrameOldestNewId);
829 for(
unsigned int i=0;
i<ids.size() && (
int)mapWords.size() >
maximumMapSize_ && mapWords.size() >= newIds.size(); ++
i)
832 if(inliers.find(
id) == inliers.end())
837 for(std::map<int, FeatureBA>::iterator iterFrame = iterRef->second.begin(); iterFrame != iterRef->second.end(); ++iterFrame)
853 for(std::multimap<int, int>::iterator
iter = mapWords.begin();
854 iter!=mapWords.end() && (
int)mapWords.size() >
maximumMapSize_ && mapWords.size() >= newIds.size();)
856 if(inliers.find(
iter->first) == inliers.end())
861 for(std::map<int, FeatureBA>::iterator iterFrame = iterRef->second.begin(); iterFrame != iterRef->second.end(); ++iterFrame)
871 mapWords.erase(
iter++);
880 if(mapWords.size() != mapPoints.size())
883 std::vector<cv::KeyPoint> mapWordsKptsClean(mapWords.size());
884 std::vector<cv::Point3f> mapPointsClean(mapWords.size());
885 cv::Mat mapDescriptorsClean(mapWords.size(), mapDescriptors.cols, mapDescriptors.type());
887 for(std::multimap<int, int>::iterator
iter = mapWords.begin();
iter!=mapWords.end(); ++
iter, ++index)
889 mapWordsKptsClean[index] = mapWordsKpts[
iter->second];
890 mapPointsClean[index] = mapPoints[
iter->second];
891 mapDescriptors.row(
iter->second).copyTo(mapDescriptorsClean.row(index));
892 iter->second = index;
894 mapWordsKpts = mapWordsKptsClean;
895 mapWordsKptsClean.clear();
896 mapPoints = mapPointsClean;
897 mapPointsClean.clear();
898 mapDescriptors = mapDescriptorsClean;
901 Link * previousLink = 0;
904 if(
iter->second <= 0)
936 UDEBUG(
"Update local features map = %fs", tmpTimer.
ticks());
946 pcl::PointCloud<pcl::PointXYZINormal>::Ptr frameCloudNormals (
new pcl::PointCloud<pcl::PointXYZINormal>());
961 pcl::IndicesPtr frameCloudNormalsIndices(
new std::vector<int>);
968 pcl::IndicesPtr(
new std::vector<int>),
970 pcl::IndicesPtr(
new std::vector<int>),
973 newPoints = frameCloudNormalsIndices->size();
977 newPoints = frameCloudNormals->size();
985 pcl::PointCloud<pcl::PointXYZINormal> tmp;
986 pcl::copyPointCloud(*frameCloudNormals, *frameCloudNormalsIndices, tmp);
991 UINFO(
"mapSize=%d newPoints=%d maxPoints=%d",
992 int(mapCloudNormals->size()),
996 *mapCloudNormals += tmp;
1006 *mapCloudNormals += tmp;
1010 pcl::PointCloud<pcl::PointXYZI>::Ptr mapCloud (
new pcl::PointCloud<pcl::PointXYZI> ());
1011 copyPointCloud(*mapCloudNormals, *mapCloud);
1013 copyPointCloud(*normals, *mapCloudNormals);
1016 scansBuffer_.push_back(std::make_pair(frameCloudNormals, frameCloudNormalsIndices));
1019 UDEBUG(
"scansBuffer=%d, mapSize=%d newPoints=%d maxPoints=%d",
1021 int(mapCloudNormals->size()),
1029 mapCloudNormals->clear();
1030 std::list<int> toRemove;
1045 pcl::PointCloud<pcl::PointXYZINormal> tmp;
1047 *mapCloudNormals += tmp;
1058 std::vector<std::pair<pcl::PointCloud<pcl::PointXYZINormal>::Ptr, pcl::IndicesPtr> > scansTmp(
scansBuffer_.size()-
i);
1062 UASSERT(oi < (
int)scansTmp.size());
1073 pcl::PointCloud<pcl::PointXYZINormal> tmp;
1075 *mapCloudNormals += tmp;
1086 Transform mapViewpoint(-newFramePose.
x(), -newFramePose.
y(),0,0,0,0);
1091 Transform mapViewpoint(-newFramePose.
x(), -newFramePose.
y(), -newFramePose.
z(),0,0,0);
1097 UDEBUG(
"Update local scan map = %fs", tmpTimer.
ticks());
1126 map_->
setWords(mapWords, mapWordsKpts, mapPoints, mapDescriptors);
1165 regInfo.
covariance = cv::Mat::eye(6,6,CV_64FC1)*9999.0;
1167 bool frameValid =
false;
1172 int ptsWithDepth = 0;
1191 std::multimap<int, int> words;
1192 std::vector<cv::KeyPoint> wordsKpts;
1193 std::vector<cv::Point3f> transformedPoints;
1194 std::multimap<int, int> mapPointWeights;
1195 cv::Mat descriptors;
1205 words.insert(words.end(), std::make_pair(
iter->first, words.size()));
1208 mapPointWeights.insert(std::make_pair(
iter->first, 0));
1217 if(!wordsKpts.empty())
1219 for(std::multimap<int, int>::const_iterator
iter=words.begin();
iter!=words.end(); ++
iter)
1221 if(words.count(
iter->first) == 1)
1224 std::map<int, FeatureBA> framePt;
1226 cv::KeyPoint kpt = wordsKpts[
iter->second];
1228 int cameraIndex = 0;
1229 if(lastFrameModels.size()>1)
1231 UASSERT(lastFrameModels[0].imageWidth()>0);
1232 float subImageWidth = lastFrameModels[0].imageWidth();
1233 cameraIndex =
int(kpt.pt.x / subImageWidth);
1234 kpt.pt.x = kpt.pt.x - (subImageWidth*
float(cameraIndex));
1264 map_->
setWords(words, wordsKpts, transformedPoints, descriptors);
1278 double complexity = 0.0;;
1281 float minComplexity = Parameters::defaultIcpPointToPlaneMinComplexity();
1282 bool p2n = Parameters::defaultIcpPointToPlane();
1285 if(p2n && minComplexity>0.0
f)
1290 if(complexity > minComplexity)
1296 UWARN(
"Scan complexity too low (%f) to init robustly the first "
1297 "keyframe. Make sure the lidar is seeing enough "
1298 "geometry in all axes for good initialization. "
1299 "Accepting as an initial guess (%s) is provided.",
1307 UWARN(
"Input raw scan doesn't have normals, complexity check on first frame is not done.");
1320 UINFO(
"Local map will be updated using range instead of time with range threshold set at %f",
scanMapMaxRange_);
1322 scansBuffer_.push_back(std::make_pair(mapCloudNormals, pcl::IndicesPtr(
new std::vector<int>)));
1326 Transform mapViewpoint(-newFramePose.
x(), -newFramePose.
y(),0,0,0,0);
1336 Transform mapViewpoint(-newFramePose.
x(), -newFramePose.
y(), -newFramePose.
z(),0,0,0);
1349 UWARN(
"Scan complexity too low (%f) to init first keyframe.", complexity);
1354 UWARN(
"Missing scan to initialize odometry.");
1391 info->words.clear();
1404 UERROR(
"SensorData not valid!");
1409 info->features = nFeatures;
1411 info->keyFrameAdded = addKeyFrame;
1412 info->localBundleOutliers = totalBundleOutliers;
1413 info->localBundleConstraints = totalBundleWordReferencesUsed;
1414 info->localBundleTime = bundleTime;
1418 info->
reg = regInfo;
1426 UINFO(
"Odom update time = %fs lost=%s features=%d inliers=%d/%d variance:lin=%f, ang=%f local_map=%d local_scan_map=%d",
1428 output.
isNull()?
"true":
"false",