62 #include <pcl/io/pcd_io.h>
63 #include <pcl/common/common.h>
65 #include <opencv2/imgproc/types_c.h>
76 _similarityThreshold(
Parameters::defaultMemRehearsalSimilarity()),
77 _binDataKept(
Parameters::defaultMemBinDataKept()),
78 _rawDescriptorsKept(
Parameters::defaultMemRawDescriptorsKept()),
79 _saveDepth16Format(
Parameters::defaultMemSaveDepth16Format()),
80 _notLinkedNodesKeptInDb(
Parameters::defaultMemNotLinkedNodesKept()),
81 _saveIntermediateNodeData(
Parameters::defaultMemIntermediateNodeDataKept()),
82 _rgbCompressionFormat(
Parameters::defaultMemImageCompressionFormat()),
83 _depthCompressionFormat(
Parameters::defaultMemDepthCompressionFormat()),
84 _incrementalMemory(
Parameters::defaultMemIncrementalMemory()),
85 _localizationDataSaved(
Parameters::defaultMemLocalizationDataSaved()),
86 _reduceGraph(
Parameters::defaultMemReduceGraph()),
87 _maxStMemSize(
Parameters::defaultMemSTMSize()),
88 _recentWmRatio(
Parameters::defaultMemRecentWmRatio()),
89 _transferSortingByWeightId(
Parameters::defaultMemTransferSortingByWeightId()),
90 _idUpdatedToNewOneRehearsal(
Parameters::defaultMemRehearsalIdUpdatedToNewOne()),
91 _generateIds(
Parameters::defaultMemGenerateIds()),
92 _badSignaturesIgnored(
Parameters::defaultMemBadSignaturesIgnored()),
93 _mapLabelsAdded(
Parameters::defaultMemMapLabelsAdded()),
94 _depthAsMask(
Parameters::defaultMemDepthAsMask()),
95 _maskFloorThreshold(
Parameters::defaultMemDepthMaskFloorThr()),
96 _stereoFromMotion(
Parameters::defaultMemStereoFromMotion()),
97 _imagePreDecimation(
Parameters::defaultMemImagePreDecimation()),
98 _imagePostDecimation(
Parameters::defaultMemImagePostDecimation()),
99 _compressionParallelized(
Parameters::defaultMemCompressionParallelized()),
100 _laserScanDownsampleStepSize(
Parameters::defaultMemLaserScanDownsampleStepSize()),
101 _laserScanVoxelSize(
Parameters::defaultMemLaserScanVoxelSize()),
102 _laserScanNormalK(
Parameters::defaultMemLaserScanNormalK()),
103 _laserScanNormalRadius(
Parameters::defaultMemLaserScanNormalRadius()),
104 _laserScanGroundNormalsUp(
Parameters::defaultIcpPointToPlaneGroundNormalsUp()),
105 _reextractLoopClosureFeatures(
Parameters::defaultRGBDLoopClosureReextractFeatures()),
106 _localBundleOnLoopClosure(
Parameters::defaultRGBDLocalBundleOnLoopClosure()),
107 _invertedReg(
Parameters::defaultRGBDInvertedReg()),
108 _rehearsalMaxDistance(
Parameters::defaultRGBDLinearUpdate()),
109 _rehearsalMaxAngle(
Parameters::defaultRGBDAngularUpdate()),
110 _rehearsalWeightIgnoredWhileMoving(
Parameters::defaultMemRehearsalWeightIgnoredWhileMoving()),
111 _useOdometryFeatures(
Parameters::defaultMemUseOdomFeatures()),
112 _useOdometryGravity(
Parameters::defaultMemUseOdomGravity()),
113 _rotateImagesUpsideUp(
Parameters::defaultMemRotateImagesUpsideUp()),
114 _createOccupancyGrid(
Parameters::defaultRGBDCreateOccupancyGrid()),
115 _visMaxFeatures(
Parameters::defaultVisMaxFeatures()),
117 _imagesAlreadyRectified(
Parameters::defaultRtabmapImagesAlreadyRectified()),
118 _rectifyOnlyFeatures(
Parameters::defaultRtabmapRectifyOnlyFeatures()),
119 _covOffDiagonalIgnored(
Parameters::defaultMemCovOffDiagIgnored()),
120 _detectMarkers(
Parameters::defaultRGBDMarkerDetection()),
121 _markerLinVariance(
Parameters::defaultMarkerVarianceLinear()),
122 _markerAngVariance(
Parameters::defaultMarkerVarianceAngular()),
123 _markerOrientationIgnored(
Parameters::defaultMarkerVarianceOrientationIgnored()),
125 _idMapCount(kIdStart),
127 _lastGlobalLoopClosureId(0),
128 _memoryChanged(
false),
129 _linksChanged(
false),
132 _badSignRatio(
Parameters::defaultKpBadSignRatio()),
133 _tfIdfLikelihoodUsed(
Parameters::defaultKpTfIdfLikelihoodUsed()),
134 _parallelized(
Parameters::defaultKpParallelized()),
151 float corRatio = Parameters::defaultIcpCorrespondenceRatio();
157 UWARN(
"%s is >=0.5, which sets correspondence ratio for proximity detection using "
158 "laser scans to 100% (2 x Ratio). You may lower the ratio to accept proximity "
159 "detection with not full scans overlapping.", Parameters::kIcpCorrespondenceRatio().
c_str());
237 bool loadAllNodesInWM = Parameters::defaultMemInitWMWithAllNodes();
241 std::list<Signature*> dbSignatures;
256 for(std::list<Signature*>::reverse_iterator
iter=dbSignatures.rbegin();
iter!=dbSignatures.rend(); ++
iter)
268 if(!(*iter)->getGroundTruthPose().isNull()) {
269 _groundTruths.insert(std::make_pair((*iter)->id(), (*iter)->getGroundTruthPose()));
272 if(!(*iter)->getLandmarks().empty())
275 for(std::map<int, Link>::const_iterator jter = (*iter)->getLandmarks().begin(); jter!=(*iter)->getLandmarks().end(); ++jter)
277 int landmarkId = jter->first;
280 cv::Mat landmarkSize = jter->second.uncompressUserDataConst();
281 if(!landmarkSize.empty() && landmarkSize.type() == CV_32FC1 && landmarkSize.total()==1)
283 std::pair<std::map<int, float>::iterator,
bool> inserted=
_landmarksSize.insert(std::make_pair(-landmarkId, landmarkSize.at<
float>(0,0)));
286 if(inserted.first->second != landmarkSize.at<
float>(0,0))
288 UWARN(
"Trying to update landmark size buffer for landmark %d with size=%f but "
289 "it has already a different size set. Keeping old size (%f).",
290 -landmarkId, inserted.first->second, landmarkSize.at<
float>(0,0));
295 UDEBUG(
"Caching landmark size %f for %d", landmarkSize.at<
float>(0,0), -landmarkId);
302 nter->second.insert((*iter)->id());
307 tmp.insert((*iter)->id());
323 UDEBUG(
"Check if all nodes are in Working Memory");
326 for(std::map<int, Link>::const_iterator jter =
iter->second->getLinks().begin(); jter!=
iter->second->getLinks().end(); ++jter)
337 UDEBUG(
"update odomMaxInf vector");
338 std::multimap<int, Link> links = this->
getAllLinks(
true,
true);
339 for(std::multimap<int, Link>::iterator
iter=links.begin();
iter!=links.end(); ++
iter)
342 iter->second.infMatrix().cols == 6 &&
343 iter->second.infMatrix().rows == 6)
349 for(
int i=0;
i<6; ++
i)
351 const double &
v =
iter->second.infMatrix().at<
double>(
i,
i);
359 UDEBUG(
"update odomMaxInf vector, done!");
381 UDEBUG(
"Loading dictionary...");
384 UDEBUG(
"load all referenced words in working memory");
386 std::set<int> wordIds;
387 const std::map<int, Signature *> & signatures = this->
getSignatures();
388 for(std::map<int, Signature *>::const_iterator
i=signatures.begin();
i!=signatures.end(); ++
i)
390 const std::multimap<int, int> & words =
i->second->getWords();
396 wordIds.insert(*
iter);
401 UDEBUG(
"load words %d", (
int)wordIds.size());
406 std::list<VisualWord*> words;
408 for(std::list<VisualWord*>::iterator
iter = words.begin();
iter!=words.end(); ++
iter)
435 const std::map<int, Signature *> & signatures = this->
getSignatures();
436 for(std::map<int, Signature *>::const_iterator
i=signatures.begin();
i!=signatures.end(); ++
i)
441 const std::multimap<int, int> & words =
s->getWords();
444 UDEBUG(
"node=%d, word references=%d",
s->id(), words.size());
445 for(std::multimap<int, int>::const_iterator
iter = words.begin();
iter!=words.end(); ++
iter)
468 parameters.erase(Parameters::kRtabmapWorkingDirectory());
485 void Memory::close(
bool databaseSaved,
bool postInitClosingEvents,
const std::string & ouputDatabasePath)
487 UINFO(
"databaseSaved=%d, postInitClosingEvents=%d", databaseSaved?1:0, postInitClosingEvents?1:0);
490 bool databaseNameChanged =
false;
500 UINFO(
"No changes added to database.");
515 UINFO(
"Saving memory...");
548 UWARN(
"Please call Memory::close() before");
564 ParametersMap::const_iterator
iter;
598 UWARN(
"%s and %s cannot be used at the same time, disabling %s...",
599 Parameters::kRGBDLocalBundleOnLoopClosure().
c_str(),
600 Parameters::kRGBDInvertedReg().
c_str(),
601 Parameters::kRGBDLocalBundleOnLoopClosure().
c_str());
624 UWARN(
"Using directly %s>=9999 to ignore marker orientation is deprecated. Use %s instead and "
625 "read correctly the description of the new parameter. We will enable %s and set %s to "
626 "same value than %s (%f) for backward compatibility.",
627 Parameters::kMarkerVarianceAngular().
c_str(),
628 Parameters::kMarkerVarianceOrientationIgnored().
c_str(),
629 Parameters::kMarkerVarianceOrientationIgnored().
c_str(),
630 Parameters::kMarkerVarianceAngular().
c_str(),
631 Parameters::kMarkerVarianceLinear().
c_str(),
677 UWARN(
"new detector strategy %d while the vocabulary is already created. This may give problems if feature descriptors are not the same type than the one used in the current vocabulary (a memory reset would be required if so).",
int(detectorStrategy));
681 UINFO(
"new detector strategy %d.",
int(detectorStrategy));
723 UDEBUG(
"new registration strategy %d",
int(regStrategy));
761 float corRatio = Parameters::defaultIcpCorrespondenceRatio();
767 UWARN(
"%s is >=0.5, which sets correspondence ratio for proximity detection using "
768 "laser scans to 100% (2 x Ratio). You may lower the ratio to accept proximity "
769 "detection with not full scans overlapping.", Parameters::kIcpCorrespondenceRatio().
c_str());
789 int globalDescriptorStrategy = -1;
791 if(globalDescriptorStrategy != -1 &&
807 iter =
params.find(Parameters::kMemIncrementalMemory());
820 UWARN(
"Switching from Mapping to Localization mode, the database will be saved and reloaded.");
827 UWARN(
"Switching from Mapping to Localization mode, the database is reloaded!");
835 int visFeatureType = Parameters::defaultVisFeatureType();
836 int kpDetectorStrategy = Parameters::defaultKpDetectorStrategy();
839 if(visFeatureType != kpDetectorStrategy)
841 UWARN(
"%s is enabled, but %s and %s parameters are not the same! Disabling %s...",
842 Parameters::kMemUseOdomFeatures().
c_str(),
843 Parameters::kVisFeatureType().
c_str(),
844 Parameters::kKpDetectorStrategy().
c_str(),
845 Parameters::kMemUseOdomFeatures().
c_str());
876 const cv::Mat & covariance,
877 const std::vector<float> & velocity,
889 UDEBUG(
"pre-updating...");
891 t=
timer.ticks()*1000;
892 if(
stats)
stats->addStatistic(Statistics::kTimingMemPre_update(),
t);
893 UDEBUG(
"time preUpdate=%f ms",
t);
901 UERROR(
"Failed to create a signature...");
910 if(
stats)
stats->addStatistic(Statistics::kTimingMemSignature_creation(),
t);
911 UDEBUG(
"time creating signature=%f ms",
t);
931 if(
stats)
stats->addStatistic(Statistics::kTimingMemRehearsal(),
t);
932 UDEBUG(
"time rehearsal=%f ms",
t);
938 UWARN(
"The working memory is empty and the memory is not "
939 "incremental (Mem/IncrementalMemory=False), no loop closure "
940 "can be detected! Please set Mem/IncrementalMemory=true to increase "
941 "the memory with new images or decrease the STM size (which is %d "
942 "including the new one added).", (
int)
_stMem.size());
949 int notIntermediateNodesCount = 0;
954 if(
s->getWeight() >= 0)
956 ++notIntermediateNodesCount;
959 std::map<int, int> reducedIds;
965 if(
s->getWeight() >= 0)
967 --notIntermediateNodesCount;
975 reducedIds.insert(std::make_pair(
id, reducedTo));
1006 UASSERT(covariance.cols == 6 && covariance.rows == 6 && covariance.type() == CV_64FC1);
1007 double maxAngVar = 0.0;
1010 maxAngVar = covariance.at<
double>(5,5);
1014 maxAngVar =
uMax3(covariance.at<
double>(3,3), covariance.at<
double>(4,4), covariance.at<
double>(5,5));
1017 if(maxAngVar != 1.0 && maxAngVar > 0.1)
1019 static bool warned =
false;
1022 UWARN(
"Very large angular variance (%f) detected! Please fix odometry "
1023 "covariance, otherwise poor graph optimizations are "
1024 "expected and wrong loop closure detections creating a lot "
1025 "of errors in the map could be accepted. This message is only "
1026 "printed once.", maxAngVar);
1034 infMatrix = cv::Mat::zeros(6,6,CV_64FC1);
1035 infMatrix.at<
double>(0,0) = 1.0 / covariance.at<
double>(0,0);
1036 infMatrix.at<
double>(1,1) = 1.0 / covariance.at<
double>(1,1);
1037 infMatrix.at<
double>(2,2) = 1.0 / covariance.at<
double>(2,2);
1038 infMatrix.at<
double>(3,3) = 1.0 / covariance.at<
double>(3,3);
1039 infMatrix.at<
double>(4,4) = 1.0 / covariance.at<
double>(4,4);
1040 infMatrix.at<
double>(5,5) = 1.0 / covariance.at<
double>(5,5);
1044 infMatrix = covariance.inv();
1046 if((
uIsFinite(covariance.at<
double>(0,0)) && covariance.at<
double>(0,0)>0.0) &&
1047 !(
uIsFinite(infMatrix.at<
double>(0,0)) && infMatrix.at<
double>(0,0)>0.0))
1049 UERROR(
"Failed to invert the covariance matrix! Covariance matrix should be invertible!");
1050 std::cout <<
"Covariance: " << covariance << std::endl;
1051 infMatrix = cv::Mat::eye(6,6,CV_64FC1);
1054 UASSERT(infMatrix.rows == 6 && infMatrix.cols == 6);
1059 for(
int i=0;
i<6; ++
i)
1061 const double &
v = infMatrix.at<
double>(
i,
i);
1081 UDEBUG(
"Ignoring neighbor link between %d and %d because they are not in the same map! (%d vs %d)",
1088 std::string tag =
uFormat(
"map%d", signature->
mapId());
1091 UINFO(
"Tagging node %d with label \"%s\"", signature->
id(), tag.c_str());
1093 _labels.insert(std::make_pair(signature->
id(), tag));
1101 std::string tag =
uFormat(
"map%d", signature->
mapId());
1104 UINFO(
"Tagging node %d with label \"%s\"", signature->
id(), tag.c_str());
1106 _labels.insert(std::make_pair(signature->
id(), tag));
1119 UDEBUG(
"%d words ref for the signature %d (weight=%d)", signature->
getWords().size(), signature->
id(), signature->
getWeight());
1134 UDEBUG(
"Inserting node %d in WM...", signature->
id());
1136 _signatures.insert(std::pair<int, Signature*>(signature->
id(), signature));
1144 UERROR(
"Signature is null ?!?");
1150 UDEBUG(
"Inserting node %d from STM in WM...",
id);
1158 const std::multimap<int, Link> & links =
s->getLinks();
1159 std::map<int, Link> neighbors;
1160 for(std::multimap<int, Link>::const_iterator
iter=links.begin();
iter!=links.end(); ++
iter)
1164 merge =
iter->second.to() <
s->id() &&
1165 iter->second.to() !=
iter->second.from() &&
1168 iter->second.userDataCompressed().empty() &&
1173 UDEBUG(
"Reduce %d to %d",
s->id(),
iter->second.to());
1176 *reducedTo =
iter->second.to();
1183 neighbors.insert(*
iter);
1188 if(
s->getLabel().empty())
1190 for(std::multimap<int, Link>::const_iterator
iter=links.begin();
iter!=links.end(); ++
iter)
1193 if(sTo->
id()!=
s->id())
1202 for(std::map<int, Link>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter)
1204 if(!sTo->
hasLink(jter->second.to()))
1206 UDEBUG(
"Merging link %d->%d (type=%d) to link %d->%d (type %d)",
1207 iter->second.from(),
iter->second.to(),
iter->second.type(),
1208 jter->second.from(), jter->second.to(), jter->second.type());
1209 Link l =
iter->second.inverse().merge(
1224 std::multimap<int, Link> linksCopy = links;
1225 for(std::multimap<int, Link>::iterator
iter=linksCopy.begin();
iter!=linksCopy.end(); ++
iter)
1230 s->removeLink(
iter->first);
1274 bool lookInDatabase)
const
1276 std::multimap<int, Link> links;
1280 const std::multimap<int, Link> & allLinks =
s->getLinks();
1281 for(std::multimap<int, Link>::const_iterator
iter = allLinks.begin();
iter!=allLinks.end(); ++
iter)
1286 links.insert(*
iter);
1293 for(std::multimap<int, Link>::iterator
iter=links.begin();
iter!=links.end();)
1298 links.erase(
iter++);
1308 UWARN(
"Cannot find signature %d in memory", signatureId);
1315 bool lookInDatabase)
const
1318 std::multimap<int, Link> loopClosures;
1321 const std::multimap<int, Link> & allLinks =
s->getLinks();
1322 for(std::multimap<int, Link>::const_iterator
iter = allLinks.begin();
iter!=allLinks.end(); ++
iter)
1326 iter->second.from() !=
iter->second.to() &&
1329 loopClosures.insert(*
iter);
1336 for(std::multimap<int, Link>::iterator
iter=loopClosures.begin();
iter!=loopClosures.end();)
1342 loopClosures.erase(
iter++);
1350 return loopClosures;
1355 bool lookInDatabase,
1356 bool withLandmarks)
const
1358 std::multimap<int, Link> links;
1364 links =
s->getLinks();
1367 links.insert(
s->getLandmarks().begin(),
s->getLandmarks().end());
1376 UWARN(
"Cannot find signature %d in memory", signatureId);
1379 else if(signatureId < 0)
1381 int landmarkId = signatureId;
1385 for(std::set<int>::const_iterator jter=
iter->second.begin(); jter!=
iter->second.end(); ++jter)
1390 std::map<int, Link>::const_iterator kter =
s->getLandmarks().find(landmarkId);
1391 if(kter !=
s->getLandmarks().end())
1394 links.insert(std::make_pair(
s->id(), kter->second.inverse()));
1401 std::map<int, Link>
nodes;
1403 for(std::map<int, Link>::iterator kter=
nodes.begin(); kter!=
nodes.end(); ++kter)
1405 links.insert(std::make_pair(kter->first, kter->second.inverse()));
1412 std::multimap<int, Link>
Memory::getAllLinks(
bool lookInDatabase,
bool ignoreNullLinks,
bool withLandmarks)
const
1414 std::multimap<int, Link> links;
1423 links.erase(
iter->first);
1424 for(std::map<int, Link>::const_iterator jter=
iter->second->getLinks().begin();
1425 jter!=
iter->second->getLinks().end();
1428 if(!ignoreNullLinks || jter->second.isValid())
1430 links.insert(std::make_pair(
iter->first, jter->second));
1435 for(std::map<int, Link>::const_iterator jter=
iter->second->getLandmarks().begin();
1436 jter!=
iter->second->getLandmarks().end();
1439 if(!ignoreNullLinks || jter->second.isValid())
1441 links.insert(std::make_pair(
iter->first, jter->second));
1457 int maxCheckedInDatabase,
1458 bool incrementMarginOnLoop,
1460 bool ignoreIntermediateNodes,
1461 bool ignoreLocalSpaceLoopIds,
1462 const std::set<int> & nodesSet,
1463 double * dbAccessTime
1475 std::map<int, int> ids;
1480 int nbLoadedFromDb = 0;
1481 std::list<int> curentMarginList;
1482 std::set<int> currentMargin;
1483 std::set<int> nextMargin;
1484 nextMargin.insert(signatureId);
1486 std::set<int> ignoredIds;
1487 while((maxGraphDepth == 0 ||
m < maxGraphDepth) && nextMargin.size())
1490 curentMarginList = std::list<int>(nextMargin.rbegin(), nextMargin.rend());
1493 for(std::list<int>::iterator jter = curentMarginList.begin(); jter!=curentMarginList.end(); ++jter)
1495 if(ids.find(*jter) == ids.end() && (nodesSet.empty() || nodesSet.find(*jter) != nodesSet.end()))
1500 std::multimap<int, Link> tmpLinks;
1501 std::map<int, Link> tmpLandmarks;
1502 const std::multimap<int, Link> * links = &tmpLinks;
1503 const std::map<int, Link> * landmarks = &tmpLandmarks;
1506 if(!ignoreIntermediateNodes ||
s->getWeight() != -1)
1508 ids.insert(std::pair<int, int>(*jter,
m));
1512 ignoredIds.insert(*jter);
1515 links = &
s->getLinks();
1518 landmarks = &
s->getLandmarks();
1521 else if(maxCheckedInDatabase == -1 || (maxCheckedInDatabase > 0 &&
_dbDriver && nbLoadedFromDb < maxCheckedInDatabase))
1524 ids.insert(std::pair<int, int>(*jter,
m));
1528 if(tmpLinks.empty())
1530 UWARN(
"No links loaded for %d?!", *jter);
1534 for(std::multimap<int, Link>::iterator kter=tmpLinks.begin(); kter!=tmpLinks.end();)
1538 tmpLandmarks.insert(*kter);
1539 tmpLinks.erase(kter++);
1541 else if(kter->second.from() == kter->second.to())
1544 tmpLinks.erase(kter++);
1554 *dbAccessTime +=
timer.getElapsedTime();
1559 for(std::multimap<int, Link>::const_iterator
iter=links->begin();
iter!=links->end(); ++
iter)
1562 ignoredIds.find(
iter->first) == ignoredIds.end())
1568 if(ignoreIntermediateNodes &&
s->getWeight()==-1)
1571 if(currentMargin.insert(
iter->first).second)
1573 curentMarginList.push_back(
iter->first);
1578 nextMargin.insert(
iter->first);
1583 if(incrementMarginOnLoop)
1585 nextMargin.insert(
iter->first);
1589 if(currentMargin.insert(
iter->first).second)
1591 curentMarginList.push_back(
iter->first);
1599 for(std::map<int, Link>::const_iterator
iter=landmarks->begin();
iter!=landmarks->end(); ++
iter)
1601 const std::map<int, std::set<int> >::const_iterator kter =
_landmarksIndex.find(
iter->first);
1604 for(std::set<int>::const_iterator nter=kter->second.begin(); nter!=kter->second.end(); ++nter)
1606 if( !
uContains(ids, *nter) && ignoredIds.find(*nter) == ignoredIds.end())
1608 if(incrementMarginOnLoop)
1610 nextMargin.insert(*nter);
1614 if(currentMargin.insert(*nter).second)
1616 curentMarginList.push_back(*nter);
1634 const std::map<int, Transform> & optimizedPoses,
1641 std::map<int, float> ids;
1642 std::map<int, float> checkedIds;
1643 std::list<int> curentMarginList;
1644 std::set<int> currentMargin;
1645 std::set<int> nextMargin;
1646 nextMargin.insert(signatureId);
1648 Transform referential = optimizedPoses.at(signatureId);
1650 float radiusSqrd = radius*radius;
1651 while((maxGraphDepth == 0 ||
m < maxGraphDepth) && nextMargin.size())
1653 curentMarginList = std::list<int>(nextMargin.begin(), nextMargin.end());
1656 for(std::list<int>::iterator jter = curentMarginList.begin(); jter!=curentMarginList.end(); ++jter)
1658 if(checkedIds.find(*jter) == checkedIds.end())
1665 const Transform &
t = optimizedPoses.at(*jter);
1668 if(radiusSqrd == 0 || distanceSqrd<radiusSqrd)
1670 ids.insert(std::pair<int, float>(*jter,distanceSqrd));
1674 for(std::multimap<int, Link>::const_iterator
iter=
s->getLinks().begin();
iter!=
s->getLinks().end(); ++
iter)
1680 nextMargin.insert(
iter->first);
1706 int id = *
_stMem.begin();
1708 if(reducedIds && reducedId > 0)
1710 reducedIds->insert(std::make_pair(
id, reducedId));
1741 std::string
version =
"0.0.0";
1751 std::string
url =
"";
1773 ids.insert(
iter->first);
1818 uFormat(
"The number of signatures don't match! _workingMem=%d, _stMem=%d, _signatures=%d",
1821 UDEBUG(
"Adding statistics after run...");
1826 parameters.erase(Parameters::kRtabmapWorkingDirectory());
1840 for(std::map<int, Signature *>::iterator
i=mem.begin();
i!=mem.end(); ++
i)
1844 UDEBUG(
"deleting from the working and the short-term memory: %d",
i->first);
1911 std::map<int, float> likelihood;
1918 else if(ids.empty())
1920 UWARN(
"ids list is empty");
1924 for(std::list<int>::const_iterator
iter = ids.begin();
iter!=ids.end(); ++
iter)
1932 UFATAL(
"Signature %d not found in WM ?!?", *
iter);
1937 likelihood.insert(likelihood.end(), std::pair<int, float>(*
iter, sim));
1940 UDEBUG(
"compute likelihood (similarity)... %f s",
timer.ticks());
1947 std::map<int, float> likelihood;
1948 std::map<int, float> calculatedWordsRatio;
1955 else if(ids.empty())
1957 UWARN(
"ids list is empty");
1961 for(std::list<int>::const_iterator
iter = ids.begin();
iter!=ids.end(); ++
iter)
1963 likelihood.insert(likelihood.end(), std::pair<int, float>(*
iter, 0.0f));
1980 UDEBUG(
"processing... ");
1982 for(std::list<int>::const_iterator
i=wordIds.begin();
i!=wordIds.end(); ++
i)
1997 for(std::map<int, int>::const_iterator
j=refs.begin();
j!=refs.end(); ++
j)
1999 std::map<int, float>::iterator
iter = likelihood.find(
j->first);
2000 if(
iter != likelihood.end())
2003 ni = this->
getNi(
j->first);
2007 iter->second += ( nwi * logNnw ) / ni;
2017 UDEBUG(
"compute likelihood (tf-idf) %f s",
timer.ticks());
2025 std::map<int, int> weights;
2033 UFATAL(
"Location %d must exist in memory",
iter->first);
2035 weights.insert(weights.end(), std::make_pair(
iter->first,
s->getWeight()));
2039 weights.insert(weights.end(), std::make_pair(
iter->first, -1));
2048 std::list<int> signaturesRemoved;
2059 int wordsRemoved = 0;
2066 while(wordsRemoved < newWords)
2069 if(signatures.size())
2074 signaturesRemoved.push_back(
s->id());
2088 UDEBUG(
"newWords=%d, wordsRemoved=%d", newWords, wordsRemoved);
2096 for(std::list<Signature *>::iterator
iter=signatures.begin();
iter!=signatures.end(); ++
iter)
2098 signaturesRemoved.push_back((*iter)->id());
2103 if((
int)signatures.size() < signaturesAdded)
2105 UWARN(
"Less signatures transferred (%d) than added (%d)! The working memory cannot decrease in size.",
2106 (
int)signatures.size(), signaturesAdded);
2110 UDEBUG(
"signaturesRemoved=%d, _signaturesAdded=%d", (
int)signatures.size(), signaturesAdded);
2113 return signaturesRemoved;
2120 int signatureRemoved = 0;
2133 return signatureRemoved;
2175 for(std::map<int, Transform>::iterator
iter=poses.lower_bound(1);
iter!=poses.end() && ok; ++
iter)
2179 UWARN(
"Node %d not found in working memory",
iter->first);
2185 UWARN(
"Optimized poses (%d) and working memory "
2186 "size (%d) don't match. Returning empty optimized "
2187 "poses to force re-update. If you want to use the "
2188 "saved optimized poses, set %s to true",
2191 Parameters::kMemInitWMWithAllNodes().c_str());
2192 return std::map<int, Transform>();
2197 return std::map<int, Transform>();
2218 const cv::Mat & cloud,
2219 const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
2220 #
if PCL_VERSION_COMPARE(>=, 1, 8, 0)
2223 const std::vector<std::vector<Eigen::Vector2f> > & texCoords,
2225 const cv::Mat & textures)
const
2234 std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons,
2235 #
if PCL_VERSION_COMPARE(>=, 1, 8, 0)
2238 std::vector<std::vector<Eigen::Vector2f> > * texCoords,
2240 cv::Mat * textures)
const
2301 std::list<Signature *> removableSignatures;
2302 std::map<WeightAgeIdKey, Signature *> weightAgeIdMap;
2305 UDEBUG(
"mem.size()=%d, ignoredIds.size()=%d", (
int)
_workingMem.size(), (
int)ignoredIds.size());
2310 bool recentWmImmunized =
false;
2312 int currentRecentWmSize = 0;
2319 ++currentRecentWmSize;
2322 if(currentRecentWmSize>1 && currentRecentWmSize < recentWmMaxSize)
2324 recentWmImmunized =
true;
2326 else if(currentRecentWmSize == 0 &&
_workingMem.size() > 1)
2340 for(std::map<int, double>::const_iterator memIter =
_workingMem.begin(); memIter !=
_workingMem.end(); ++memIter)
2347 else if(memIter->first > 0 && ignoredIds.find(memIter->first) == ignoredIds.end() && (!lastInSTM || !lastInSTM->
hasLink(memIter->first)))
2353 bool foundInSTM =
false;
2354 for(std::map<int, Link>::const_iterator
iter =
s->getLinks().begin();
iter!=
s->getLinks().end(); ++
iter)
2358 UDEBUG(
"Ignored %d because it has a link (%d) to STM",
s->id(),
iter->first);
2380 int recentWmCount = 0;
2383 UDEBUG(
"signatureMap.size()=%d _lastGlobalLoopClosureId=%d currentRecentWmSize=%d recentWmMaxSize=%d",
2385 for(std::map<WeightAgeIdKey, Signature*>::iterator
iter=weightAgeIdMap.begin();
2386 iter!=weightAgeIdMap.end();
2389 if(!recentWmImmunized)
2391 UDEBUG(
"weight=%d, id=%d",
2392 iter->second->getWeight(),
2393 iter->second->id());
2394 removableSignatures.push_back(
iter->second);
2399 if(currentRecentWmSize - recentWmCount < recentWmMaxSize)
2401 UDEBUG(
"switched recentWmImmunized");
2402 recentWmImmunized =
true;
2408 UDEBUG(
"weight=%d, id=%d",
2409 iter->second->getWeight(),
2410 iter->second->id());
2411 removableSignatures.push_back(
iter->second);
2413 if(removableSignatures.size() >= (
unsigned int)
count)
2421 ULOGGER_WARN(
"not enough signatures to get an old one...");
2423 return removableSignatures;
2435 if(!
s->getLandmarks().empty())
2437 for(std::map<int, Link>::const_iterator
iter=
s->getLandmarks().begin();
iter!=
s->getLandmarks().end(); ++
iter)
2439 int landmarkId =
iter->first;
2443 nter->second.erase(
s->id());
2444 if(nter->second.empty())
2455 keepLinkedToGraph =
false;
2459 if(!keepLinkedToGraph)
2462 uFormat(
"Deleting location (%d) outside the "
2463 "STM is not implemented!",
s->id()).c_str());
2464 const std::multimap<int, Link> & links =
s->getLinks();
2465 for(std::multimap<int, Link>::const_iterator
iter=links.begin();
iter!=links.end(); ++
iter)
2467 if(
iter->second.from() !=
iter->second.to() &&
iter->first > 0)
2472 uFormat(
"A neighbor (%d) of the deleted location %d is "
2473 "not found in WM/STM! Are you deleting a location "
2474 "outside the STM?",
iter->first,
s->id()).c_str());
2476 if(
iter->first >
s->id() && links.size()>1 && sTo->
hasLink(
s->id()))
2478 UWARN(
"Link %d of %d is newer, removing neighbor link "
2479 "may split the map!",
2480 iter->first,
s->id());
2493 s->removeLinks(
true);
2494 s->removeLandmarks();
2510 for(std::list<int>::const_iterator
i=
keys.begin();
i!=
keys.end(); ++
i)
2516 std::vector<VisualWord*> wordToDelete;
2517 wordToDelete.push_back(
w);
2521 deletedWords->push_back(
w->id());
2560 if(keepLinkedToGraph)
2586 UDEBUG(
"landmarkId=%d", landmarkId);
2587 std::map<int, Link>
nodes;
2593 for(std::set<int>::const_iterator jter=
iter->second.begin(); jter!=
iter->second.end(); ++jter)
2598 std::map<int, Link>::const_iterator kter =
s->getLandmarks().find(landmarkId);
2599 if(kter !=
s->getLandmarks().end())
2601 nodes.insert(std::make_pair(
s->id(), kter->second));
2616 UDEBUG(
"label=%s", label.c_str());
2623 if(
iter->second->getLabel().compare(label) == 0)
2625 id =
iter->second->id();
2629 if(
id == 0 &&
_dbDriver && lookInDatabase)
2649 if(idFound == 0 && label.empty() &&
_labels.find(
id)==
_labels.end())
2651 UWARN(
"Trying to remove label from node %d but it has already no label",
id);
2654 if(idFound == 0 || idFound ==
id)
2661 UWARN(
"Label \"%s\" removed from node %d",
_labels.at(
id).c_str(),
id);
2668 UWARN(
"Label \"%s\" set to node %d (previously labeled \"%s\")", label.c_str(),
id,
_labels.at(
id).c_str());
2672 UWARN(
"Label \"%s\" set to node %d", label.c_str(),
id);
2684 std::list<Signature *> signatures;
2686 if(signatures.size())
2690 UWARN(
"Label \"%s\" removed from node %d",
_labels.at(
id).c_str(),
id);
2697 UWARN(
"Label \"%s\" set to node %d (previously labeled \"%s\")", label.c_str(),
id,
_labels.at(
id).c_str());
2701 UWARN(
"Label \"%s\" set to node %d", label.c_str(),
id);
2706 signatures.front()->setLabel(label);
2713 UERROR(
"Node %d not found, failed to set label \"%s\"!",
id, label.c_str());
2718 UWARN(
"Another node %d has already label \"%s\", cannot set it to node %d", idFound, label.c_str(),
id);
2728 s->sensorData().setUserData(
data);
2733 UERROR(
"Node %d not found in RAM, failed to set user data (size=%d)!",
id,
data.total());
2740 UDEBUG(
"Deleting location %d", locationId);
2750 UDEBUG(
"Saving location data %d", locationId);
2774 UINFO(
"removing link between location %d and %d", oldS->
id(), newS->
id());
2795 bool noChildrenAnymore =
true;
2800 iter->second.from() !=
iter->second.to() &&
2801 iter->first < newS->
id())
2803 noChildrenAnymore =
false;
2814 UERROR(
"Signatures %d and %d don't have bidirectional link!", oldS->
id(), newS->
id());
2819 int landmarkId = newId<0?newId:oldId;
2821 s->removeLandmark(newId<0?newId:oldId);
2827 nter->second.erase(
s->id());
2834 UERROR(
"Signature %d is not in working memory... cannot remove link.", newS->
id());
2838 UERROR(
"Signature %d is not in working memory... cannot remove link.", oldS->
id());
2845 UDEBUG(
"id=%d image=%d scan=%d userData=%d",
id, image?1:0, scan?1:0, userData?1:0);
2849 s->sensorData().clearRawData(
2862 bool useKnownCorrespondencesIfPossible)
2875 std::string
msg =
uFormat(
"Did not find nodes %d and/or %d", fromId, toId);
2891 bool useKnownCorrespondencesIfPossible)
const
2911 cv::Mat imgBuf, depthBuf, userBuf;
2926 std::vector<int> inliersV;
2951 tmpFrom.
sensorData().
setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
2955 else if(useKnownCorrespondencesIfPossible)
2975 else if(!isNeighborRefining &&
2988 std::multimap<int, int> words;
2989 std::vector<cv::Point3f> words3DMap;
2990 std::vector<cv::KeyPoint> wordsMap;
2991 cv::Mat wordsDescriptorsMap;
2993 const std::multimap<int, Link> & links = fromS.
getLinks();
2997 UDEBUG(
"fromS.getWords()=%d uniques=%d", (
int)fromS.
getWords().size(), (
int)wordsFrom.size());
2998 for(std::map<int, int>::const_iterator jter=wordsFrom.begin(); jter!=wordsFrom.end(); ++jter)
3000 const cv::Point3f & pt = fromS.
getWords3()[jter->second];
3003 words.insert(std::make_pair(jter->first, words.size()));
3004 words3DMap.push_back(pt);
3005 wordsMap.push_back(fromS.
getWordsKpts()[jter->second]);
3010 UDEBUG(
"words3DMap=%d", (
int)words3DMap.size());
3012 for(std::multimap<int, Link>::const_iterator
iter=links.begin();
iter!=links.end(); ++
iter)
3014 int id =
iter->first;
3018 if(s && !
s->getWords3().empty())
3021 for(std::map<int, int>::const_iterator jter=wordsTo.begin(); jter!=wordsTo.end(); ++jter)
3023 const cv::Point3f & pt =
s->getWords3()[jter->second];
3024 if( jter->first > 0 &&
3026 words.find(jter->first) == words.end())
3028 words.insert(words.end(), std::make_pair(jter->first, words.size()));
3030 wordsMap.push_back(
s->getWordsKpts()[jter->second]);
3031 wordsDescriptorsMap.push_back(
s->getWordsDescriptors().row(jter->second));
3037 UDEBUG(
"words3DMap=%d", (
int)words3DMap.size());
3039 tmpFrom2.
setWords(words, wordsMap, words3DMap, wordsDescriptorsMap);
3045 std::map<int, cv::Point3f> points3DMap;
3047 for(std::map<int, int>::iterator
iter=wordsMap.begin();
iter!=wordsMap.end(); ++
iter)
3049 points3DMap.insert(std::make_pair(
iter->first, tmpFrom2.
getWords3()[
iter->second]));
3051 std::map<int, Transform> bundlePoses;
3052 std::multimap<int, Link> bundleLinks;
3053 std::map<int, std::vector<CameraModel> > bundleModels;
3054 std::map<int, std::map<int, FeatureBA> > wordReferences;
3056 std::multimap<int, Link> links = fromS.
getLinks();
3059 links.insert(std::make_pair(fromS.
id(),
Link()));
3061 int totalWordReferences = 0;
3062 for(std::multimap<int, Link>::iterator
iter=links.begin();
iter!=links.end(); ++
iter)
3064 int id =
iter->first;
3065 if(
id != fromS.
id() ||
iter->second.transform().isNull())
3069 if(
id == tmpTo.
id())
3079 std::vector<CameraModel> models;
3080 if(
s->sensorData().cameraModels().size() >= 1 &&
s->sensorData().cameraModels().at(0).isValidForProjection())
3082 models =
s->sensorData().cameraModels();
3084 else if(
s->sensorData().stereoCameraModels().size() >= 1 &&
s->sensorData().stereoCameraModels().at(0).isValidForProjection())
3086 for(
size_t i=0;
i<
s->sensorData().stereoCameraModels().
size(); ++
i)
3094 model.localTransform(),
3095 -
s->sensorData().stereoCameraModels()[
i].baseline()*
model.fx(),
3097 models.push_back(
model);
3102 UFATAL(
"no valid camera model to use local bundle adjustment on loop closure!");
3104 bundleModels.insert(std::make_pair(
id, models));
3107 if(
iter->second.transform().isNull())
3114 bundleLinks.insert(std::make_pair(
iter->second.from(),
iter->second));
3115 bundlePoses.insert(std::make_pair(
id,
iter->second.transform()));
3119 for(std::map<int, int>::const_iterator jter=words.begin(); jter!=words.end(); ++jter)
3121 if(points3DMap.find(jter->first)!=points3DMap.end() &&
3122 (
id == tmpTo.
id() || jter->first > 0))
3124 cv::KeyPoint kpts =
s->getWordsKpts()[jter->second];
3125 int cameraIndex = 0;
3128 UASSERT(models[0].imageWidth()>0);
3129 float subImageWidth = models[0].imageWidth();
3130 cameraIndex =
int(kpts.pt.x / subImageWidth);
3131 kpts.pt.x = kpts.pt.x - (subImageWidth*
float(cameraIndex));
3136 if( !
s->getWords3().empty() &&
3140 Transform invLocalTransform = models[cameraIndex].localTransform().
inverse();
3143 wordReferences.insert(std::make_pair(jter->first, std::map<int, FeatureBA>()));
3144 wordReferences.at(jter->first).insert(std::make_pair(
id,
FeatureBA(kpts,
d, cv::Mat(), cameraIndex)));
3145 ++totalWordReferences;
3155 std::set<int> sbaOutliers;
3160 bundlePoses = sba.
optimizeBA(-toS.
id(), bundlePoses, bundleLinks, bundleModels, points3DMap, wordReferences, &sbaOutliers);
3163 UDEBUG(
"bundleTime=%fs (poses=%d wordRef=%d outliers=%d)", bundleTime.
ticks(), (
int)bundlePoses.size(), totalWordReferences, (
int)sbaOutliers.size());
3165 UDEBUG(
"Local Bundle Adjustment Before: %s",
transform.prettyPrint().c_str());
3166 if(!bundlePoses.rbegin()->second.isNull())
3168 if(sbaOutliers.size())
3170 std::vector<int> newInliers(
info->inliersIDs.size());
3172 for(
unsigned int i=0;
i<
info->inliersIDs.size(); ++
i)
3174 if(sbaOutliers.find(
info->inliersIDs[
i]) == sbaOutliers.end())
3176 newInliers[oi++] =
info->inliersIDs[
i];
3179 newInliers.resize(oi);
3180 UDEBUG(
"BA outliers ratio %f",
float(sbaOutliers.size())/
float(
info->inliersIDs.size()));
3181 info->inliers = (
int)newInliers.size();
3182 info->inliersIDs = newInliers;
3191 transform = bundlePoses.rbegin()->second;
3198 UDEBUG(
"Local Bundle Adjustment After : %s",
transform.prettyPrint().c_str());
3212 std::string
msg =
uFormat(
"Missing visual features or missing raw data to compute them. Transform cannot be estimated.");
3239 const std::map<int, Transform> & poses,
3245 UDEBUG(
"%d -> %d, Guess=%s", fromId, toId, (poses.at(fromId).inverse() * poses.at(toId)).prettyPrint().c_str());
3249 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
3251 if(
iter->first != fromId)
3256 UDEBUG(
"%d vs %s", fromId, ids.c_str());
3260 std::list<Signature*> scansToLoad;
3261 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
3266 if(
s->sensorData().imageCompressed().empty() &&
3267 s->sensorData().laserScanCompressed().isEmpty())
3269 scansToLoad.push_back(
s);
3289 float guessNorm = guess.
getNorm();
3294 UINFO(
"Too far scans between %d and %d to compute transformation: guessNorm=%f, scan range from=%f to=%f", fromId, toId, guessNorm, fromScan.
rangeMax(), toScan.
rangeMax());
3301 int maxPoints = fromScan.
size();
3302 pcl::PointCloud<pcl::PointXYZ>::Ptr assembledToClouds(
new pcl::PointCloud<pcl::PointXYZ>);
3303 pcl::PointCloud<pcl::PointNormal>::Ptr assembledToNormalClouds(
new pcl::PointCloud<pcl::PointNormal>);
3304 pcl::PointCloud<pcl::PointXYZI>::Ptr assembledToIClouds(
new pcl::PointCloud<pcl::PointXYZI>);
3305 pcl::PointCloud<pcl::PointXYZINormal>::Ptr assembledToNormalIClouds(
new pcl::PointCloud<pcl::PointXYZINormal>);
3306 pcl::PointCloud<pcl::PointXYZRGB>::Ptr assembledToRGBClouds(
new pcl::PointCloud<pcl::PointXYZRGB>);
3307 pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr assembledToNormalRGBClouds(
new pcl::PointCloud<pcl::PointXYZRGBNormal>);
3308 UDEBUG(
"maxPoints from(%d) = %d", fromId, maxPoints);
3309 for(std::map<int, Transform>::const_iterator
iter = poses.begin();
iter!=poses.end(); ++
iter)
3311 if(
iter->first != fromId)
3317 s->sensorData().uncompressData(0, 0, &scan);
3360 if(scan.
size() > maxPoints)
3362 UDEBUG(
"maxPoints scan(%d) = %d",
iter->first, (
int)scan.
size());
3363 maxPoints = scan.
size();
3373 UWARN(
"Depth2D not found for signature %d",
iter->first);
3379 if(assembledToNormalClouds->size())
3383 else if(assembledToClouds->size())
3387 else if(assembledToNormalIClouds->size())
3391 else if(assembledToIClouds->size())
3395 else if(assembledToNormalRGBClouds->size())
3399 UERROR(
"Cannot handle 2d scan with RGB format.");
3406 else if(assembledToRGBClouds->size())
3410 UERROR(
"Cannot handle 2d scan with RGB format.");
3417 UDEBUG(
"assembledScan=%d points", assembledScan.
size());
3449 UINFO(
"already linked! to=%d, from=%d", link.
to(), link.
from());
3453 UDEBUG(
"Add link between %d and %d", toS->
id(), fromS->
id());
3489 else if(!addInDatabase)
3493 UERROR(
"from=%d, to=%d, Signature %d not found in working/st memories", link.
from(), link.
to(), link.
from());
3497 UERROR(
"from=%d, to=%d, Signature %d not found in working/st memories", link.
from(), link.
to(), link.
to());
3503 UDEBUG(
"Add link between %d and %d (db)", link.
from(), link.
to());
3509 UDEBUG(
"Add link between %d (db) and %d", link.
from(), link.
to());
3515 UDEBUG(
"Add link between %d (db) and %d (db)", link.
from(), link.
to());
3546 UERROR(
"fromId=%d and toId=%d are not linked!", link.
from(), link.
to());
3549 else if(!updateInDatabase)
3553 UERROR(
"from=%d, to=%d, Signature %d not found in working/st memories", link.
from(), link.
to(), link.
from());
3557 UERROR(
"from=%d, to=%d, Signature %d not found in working/st memories", link.
from(), link.
to(), link.
to());
3562 UDEBUG(
"Update link between %d and %d (db)", link.
from(), link.
to());
3569 UDEBUG(
"Update link between %d (db) and %d", link.
from(), link.
to());
3576 UDEBUG(
"Update link between %d (db) and %d (db)", link.
from(), link.
to());
3587 iter->second->removeVirtualLinks();
3597 const std::multimap<int, Link> & links =
s->getLinks();
3598 for(std::multimap<int, Link>::const_iterator
iter=links.begin();
iter!=links.end(); ++
iter)
3609 UERROR(
"Link %d of %d not in WM/STM?!?",
iter->first,
s->id());
3613 s->removeVirtualLinks();
3617 UERROR(
"Signature %d not in WM/STM?!?", signatureId);
3623 UINFO(
"Dumping memory to directory \"%s\"", directory.c_str());
3643 fopen_s(&foutSign, fileNameSign,
"w");
3645 foutSign = fopen(fileNameSign,
"w");
3650 fprintf(foutSign,
"SignatureID WordsID...\n");
3651 const std::map<int, Signature *> & signatures = this->
getSignatures();
3652 for(std::map<int, Signature *>::const_iterator
iter=signatures.begin();
iter!=signatures.end(); ++
iter)
3654 fprintf(foutSign,
"%d ",
iter->first);
3662 const std::multimap<int, int> &
ref = ss->
getWords();
3663 for(std::multimap<int, int>::const_iterator jter=
ref.begin(); jter!=
ref.end(); ++jter)
3665 const cv::Point3f & pt = ss->
getWords3()[jter->second];
3667 if(pcl::isFinite(pt) &&
3668 (pt.x != 0 || pt.y != 0 || pt.z != 0))
3670 fprintf(foutSign,
"%d ", (*jter).first);
3677 const std::multimap<int, int> &
ref = ss->
getWords();
3678 for(std::multimap<int, int>::const_iterator jter=
ref.begin(); jter!=
ref.end(); ++jter)
3680 fprintf(foutSign,
"%d ", (*jter).first);
3684 fprintf(foutSign,
"\n");
3695 fopen_s(&foutTree, fileNameTree,
"w");
3697 foutTree = fopen(fileNameTree,
"w");
3702 fprintf(foutTree,
"SignatureID Weight NbLoopClosureIds LoopClosureIds... NbChildLoopClosureIds ChildLoopClosureIds...\n");
3706 fprintf(foutTree,
"%d %d",
i->first,
i->second->getWeight());
3708 std::map<int, Link> loopIds, childIds;
3710 for(std::map<int, Link>::const_iterator
iter =
i->second->getLinks().begin();
3711 iter!=
i->second->getLinks().end();
3717 if(
iter->first <
i->first)
3719 childIds.insert(*
iter);
3721 else if(
iter->second.from() !=
iter->second.to())
3723 loopIds.insert(*
iter);
3728 fprintf(foutTree,
" %d", (
int)loopIds.size());
3729 for(std::map<int, Link>::const_iterator
j=loopIds.begin();
j!=loopIds.end(); ++
j)
3731 fprintf(foutTree,
" %d",
j->first);
3734 fprintf(foutTree,
" %d", (
int)childIds.size());
3735 for(std::map<int, Link>::const_iterator
j=childIds.begin();
j!=childIds.end(); ++
j)
3737 fprintf(foutTree,
" %d",
j->first);
3740 fprintf(foutTree,
"\n");
3750 unsigned long memoryUsage =
sizeof(
Memory);
3751 memoryUsage +=
_signatures.size() * (
sizeof(
int)+
sizeof(std::map<int, Signature *>::iterator)) +
sizeof(std::map<int, Signature *>);
3754 memoryUsage +=
iter->second->getMemoryUsed(
true);
3760 memoryUsage +=
_stMem.size() * (
sizeof(
int)+
sizeof(std::set<int>::iterator)) +
sizeof(std::set<int>);
3761 memoryUsage +=
_workingMem.size() * (
sizeof(
int)+
sizeof(
double)+
sizeof(std::map<int, double>::iterator)) +
sizeof(std::map<int, double>);
3762 memoryUsage +=
_groundTruths.size() * (
sizeof(
int)+
sizeof(
Transform)+12*
sizeof(
float) +
sizeof(std::map<int, Transform>::iterator)) +
sizeof(std::map<int, Transform>);
3763 memoryUsage +=
_labels.size() * (
sizeof(
int)+
sizeof(std::string) +
sizeof(std::map<int, std::string>::iterator)) +
sizeof(std::map<int, std::string>);
3766 memoryUsage+=
iter->second.size();
3768 memoryUsage +=
_landmarksIndex.size() * (
sizeof(
int)+
sizeof(std::set<int>) +
sizeof(std::map<int, std::set<int> >
::iterator)) +
sizeof(std::map<int, std::set<int> >);
3771 memoryUsage+=
iter->second.size()*(
sizeof(
int)+
sizeof(std::set<int>::iterator)) +
sizeof(std::set<int>);
3800 if(
s->getWeight() >= 0 &&
s->id() != signature->
id())
3809 UDEBUG(
"Comparing with signature (%d)...",
id);
3829 if(
stats)
stats->addStatistic(Statistics::kMemoryRehearsal_merged(), merged);
3830 if(
stats)
stats->addStatistic(Statistics::kMemoryRehearsal_sim(), sim);
3832 UDEBUG(
"merged=%d, sim=%f t=%fs", merged, sim,
timer.ticks());
3836 if(
stats)
stats->addStatistic(Statistics::kMemoryRehearsal_merged(), 0);
3837 if(
stats)
stats->addStatistic(Statistics::kMemoryRehearsal_sim(), 0);
3849 std::map<int, Link>::const_iterator
iter = oldS->
getLinks().find(newS->
id());
3853 iter->second.from() !=
iter->second.to())
3856 UWARN(
"already merged, old=%d, new=%d", oldId, newId);
3861 UINFO(
"Rehearsal merging %d (w=%d) and %d (w=%d)",
3866 bool intermediateMerge =
false;
3867 if(!newS->
getLinks().empty() && !newS->
getLinks().begin()->second.transform().isNull())
3882 UINFO(
"Rehearsal ignored because the robot has moved more than %f m or %f rad (\"Mem/RehearsalWeightIgnoredWhileMoving\"=true)",
3886 fullMerge = !isMoving && newS->
hasLink(oldS->
id());
3887 intermediateMerge = !isMoving && !newS->
hasLink(oldS->
id());
3891 fullMerge = newS->
hasLink(oldS->
id()) && newS->
getLinks().begin()->second.transform().isNull();
3893 UDEBUG(
"fullMerge=%s intermediateMerge=%s _idUpdatedToNewOneRehearsal=%s",
3894 fullMerge?
"true":
"false",
3895 intermediateMerge?
"true":
"false",
3908 const std::multimap<int, Link> & links = oldS->
getLinks();
3909 for(std::multimap<int, Link>::const_iterator
iter = links.begin();
iter!=links.end(); ++
iter)
3911 if(
iter->second.from() !=
iter->second.to())
3921 s->removeLink(oldS->
id());
3928 UERROR(
"Didn't find neighbor %d of %d in RAM...", link.
to(), oldS->
id());
3977 oldS->
setWeight(intermediateMerge?-1:0);
3988 newS->
setWeight(intermediateMerge?-1:0);
3996 UERROR(
"newId=%d, oldId=%d, Signature %d not found in working/st memories", newId, oldId, newId);
4000 UERROR(
"newId=%d, oldId=%d, Signature %d not found in working/st memories", newId, oldId, oldId);
4009 int mapId = -1, weight;
4015 getNodeInfo(signatureId, pose, mapId, weight, label, stamp, groundTruth,
velocity, gps, sensors, lookInDatabase);
4028 getNodeInfo(signatureId, pose, mapId, weight, label, stamp, groundTruth,
velocity, gps, sensors, lookInDatabase);
4041 getNodeInfo(signatureId, pose, mapId, weight, label, stamp, groundTruth,
velocity, gps, sensors, lookInDatabase);
4056 getNodeInfo(
id, odomPose, mapId, weight, label, stamp, groundTruth,
velocity, gps, sensors, lookInDatabase);
4058 if(gps.
stamp() == 0.0)
4062 std::map<int, int> nearestIds;
4063 nearestIds =
getNeighborsId(
id, maxGraphDepth, lookInDatabase?-1:0,
true,
false,
true);
4064 std::multimap<int, int> nearestIdsSorted;
4065 for(std::map<int, int>::iterator
iter=nearestIds.begin();
iter!=nearestIds.end(); ++
iter)
4067 nearestIdsSorted.insert(std::make_pair(
iter->second,
iter->first));
4070 for(std::map<int, int>::iterator
iter=nearestIdsSorted.begin();
iter!=nearestIdsSorted.end(); ++
iter)
4074 if(
s->sensorData().gps().stamp() > 0.0)
4077 if(
path.size() >= 2)
4079 gps =
s->sensorData().gps();
4081 offsetENU = localToENU*(
s->getPose().rotation()*
path.rbegin()->second);
4086 UWARN(
"Failed to find path %d -> %d",
s->id(),
id);
4097 std::string & label,
4100 std::vector<float> & velocity,
4103 bool lookInDatabase)
const
4108 odomPose =
s->getPose().clone();
4110 weight =
s->getWeight();
4111 label = std::string(
s->getLabel());
4112 stamp =
s->getStamp();
4113 groundTruth =
s->getGroundTruthPose().clone();
4114 velocity = std::vector<float>(
s->getVelocity());
4115 gps =
GPS(
s->sensorData().gps());
4116 sensors =
EnvSensors(
s->sensorData().envSensors());
4132 image =
s->sensorData().imageCompressed();
4138 image =
data.imageCompressed();
4148 if(
s && (!
s->isSaved() ||
4149 ((!images || !
s->sensorData().imageCompressed().empty()) &&
4150 (!scan || !
s->sensorData().laserScanCompressed().isEmpty()) &&
4151 (!userData || !
s->sensorData().userDataCompressed().empty()) &&
4152 (!occupancyGrid ||
s->sensorData().gridCellSize() != 0.0f))))
4154 r =
s->sensorData();
4157 r.
setRGBDImage(cv::Mat(), cv::Mat(), std::vector<CameraModel>());
4182 std::multimap<int, int> & words,
4183 std::vector<cv::KeyPoint> & wordsKpts,
4184 std::vector<cv::Point3f> & words3,
4185 cv::Mat & wordsDescriptors,
4186 std::vector<GlobalDescriptor> & globalDescriptors)
const
4192 words =
s->getWords();
4193 wordsKpts =
s->getWordsKpts();
4194 words3 =
s->getWords3();
4195 wordsDescriptors =
s->getWordsDescriptors();
4196 globalDescriptors =
s->sensorData().globalDescriptors();
4201 std::list<Signature*> signatures;
4203 ids.push_back(nodeId);
4204 std::set<int> loadedFromTrash;
4206 if(signatures.size())
4208 words = signatures.front()->getWords();
4209 wordsKpts = signatures.front()->getWordsKpts();
4210 words3 = signatures.front()->getWords3();
4211 wordsDescriptors = signatures.front()->getWordsDescriptors();
4212 globalDescriptors = signatures.front()->sensorData().globalDescriptors();
4213 if(loadedFromTrash.size())
4220 delete signatures.front();
4227 std::vector<CameraModel> & models,
4228 std::vector<StereoCameraModel> & stereoModels)
const
4234 models =
s->sensorData().cameraModels();
4235 stereoModels =
s->sensorData().stereoCameraModels();
4248 UERROR(
"A database must must loaded first...");
4256 const std::map<int, Transform> & poses,
4257 const cv::Mat & map,
4266 UERROR(
"A database must be loaded first...");
4270 if(poses.empty() || poses.lower_bound(1) == poses.end())
4284 for(std::map<int, Transform>::const_iterator
iter=poses.lower_bound(1);
iter!=poses.end(); ++
iter)
4289 UINFO(
"Processing %d grids...", maxPoses);
4290 int processedGrids = 1;
4291 int gridsScansModified = 0;
4292 for(std::map<int, Transform>::const_iterator
iter=poses.lower_bound(1);
iter!=poses.end(); ++
iter, ++processedGrids)
4296 cv::Mat gridObstacles;
4302 data.uncompressData(0,0,&scan,0,&gridGround,&gridObstacles,&gridEmpty);
4304 if(!gridObstacles.empty())
4307 cv::Mat filtered = cv::Mat(1, gridObstacles.cols, gridObstacles.type());
4309 for(
int i=0;
i<gridObstacles.cols; ++
i)
4311 const float * ptr = gridObstacles.ptr<
float>(0,
i);
4312 cv::Point3f pt(ptr[0], ptr[1], gridObstacles.channels()==2?0:ptr[2]);
4315 int x =
int((pt.x - xMin) / cellSize + 0.5f);
4316 int y =
int((pt.y - yMin) / cellSize + 0.5f);
4318 if(
x>=0 &&
x<map.cols &&
4321 bool obstacleDetected =
false;
4323 for(
int j=-cropRadius;
j<=cropRadius && !obstacleDetected; ++
j)
4325 for(
int k=-cropRadius; k<=cropRadius && !obstacleDetected; ++k)
4327 if(
x+
j>=0 &&
x+
j<map.cols &&
4328 y+k>=0 &&
y+k<map.rows &&
4329 map.at<
unsigned char>(
y+k,
x+
j) == 100)
4331 obstacleDetected =
true;
4336 if(map.at<
unsigned char>(
y,
x) != 0 || obstacleDetected)
4345 if(oi != gridObstacles.cols)
4347 UINFO(
"Grid id=%d (%d/%d) filtered %d -> %d",
iter->first, processedGrids, maxPoses, gridObstacles.cols, oi);
4348 gridsScansModified += 1;
4352 cv::Mat newObstacles = cv::Mat(filtered,
cv::Range::all(), cv::Range(0, oi));
4353 bool modifyDb =
true;
4356 s->sensorData().setOccupancyGrid(gridGround, newObstacles, gridEmpty, cellSize,
data.gridViewPoint());
4370 data.gridViewPoint());
4375 if(filterScans && !scan.
isEmpty())
4379 cv::Mat filtered = cv::Mat(1, scan.
size(), scan.
dataType());
4381 for(
int i=0;
i<scan.
size(); ++
i)
4383 const float * ptr = scan.
data().ptr<
float>(0,
i);
4384 cv::Point3f pt(ptr[0], ptr[1], scan.
is2d()?0:ptr[2]);
4387 int x =
int((pt.x - xMin) / cellSize + 0.5f);
4388 int y =
int((pt.y - yMin) / cellSize + 0.5f);
4390 if(
x>=0 &&
x<map.cols &&
4393 bool obstacleDetected =
false;
4395 for(
int j=-cropRadius;
j<=cropRadius && !obstacleDetected; ++
j)
4397 for(
int k=-cropRadius; k<=cropRadius && !obstacleDetected; ++k)
4399 if(
x+
j>=0 &&
x+
j<map.cols &&
4400 y+k>=0 &&
y+k<map.rows &&
4401 map.at<
unsigned char>(
y+k,
x+
j) == 100)
4403 obstacleDetected =
true;
4408 if(map.at<
unsigned char>(
y,
x) != 0 || obstacleDetected)
4417 if(oi != scan.
size())
4419 UINFO(
"Scan id=%d (%d/%d) filtered %d -> %d",
iter->first, processedGrids, maxPoses, (
int)scan.
size(), oi);
4420 gridsScansModified += 1;
4449 bool modifyDb =
true;
4452 s->sensorData().setLaserScan(scan,
true);
4467 return gridsScansModified;
4496 id.push_back(to->
id());
4502 UDEBUG(
"Loaded image data from database");
4514 ULOGGER_ERROR(
"Can't merge the signatures because there are not same type.");
4540 bool isIntermediateNode =
data.id() < 0;
4544 if(!isIntermediateNode)
4549 data.keypoints().empty() ||
4550 (
int)
data.keypoints().size() !=
data.descriptors().rows ||
4551 data.descriptors().empty() ||
4559 bool needRawScan =
true;
4561 if( (needRawImages &&
data.imageRaw().empty() && !
data.imageCompressed().empty()) ||
4562 (needRawImages &&
data.depthOrRightRaw().empty() && !
data.depthOrRightCompressed().empty()) ||
4563 (needRawScan &&
data.laserScanRaw().empty() && !
data.laserScanCompressed().empty()))
4565 cv::Mat left, right;
4567 UDEBUG(
"Uncompressing data...");
4568 data.uncompressData(
4569 needRawImages &&
data.imageRaw().empty() && !
data.imageCompressed().empty() ? &left : 0,
4570 needRawImages &&
data.depthOrRightRaw().empty() && !
data.depthOrRightCompressed().empty() ? &right : 0,
4571 needRawScan &&
data.laserScanRaw().empty() && !
data.laserScanCompressed().empty() ? &laserScan : 0);
4572 UDEBUG(
"Uncompressing data...done!");
4577 data.imageRaw().type() == CV_8UC1 ||
4578 data.imageRaw().type() == CV_8UC3);
4580 ( (
data.depthOrRightRaw().type() == CV_16UC1 ||
4581 data.depthOrRightRaw().type() == CV_32FC1 ||
4582 data.depthOrRightRaw().type() == CV_8UC1 ||
4583 data.depthOrRightRaw().type() == CV_8UC3)
4585 ( (
data.imageRaw().empty() && !(
data.depthOrRightRaw().type() == CV_8UC1 ||
data.depthOrRightRaw().type() == CV_8UC3)) ||
4586 (
data.depthOrRightRaw().rows <=
data.imageRaw().rows &&
data.depthOrRightRaw().cols <=
data.imageRaw().cols))),
4587 uFormat(
"image=(%d/%d, type=%d, [accepted=%d,%d]) depth=(%d/%d, type=%d [accepted=%d(depth mm),%d(depth m),%d-%d(stereo)]). "
4588 "For stereo, left and right images should be same size. "
4589 "For RGB-D, depth can be X times smaller than RGB (where X is an integer).",
4590 data.imageRaw().cols,
4591 data.imageRaw().rows,
4592 data.imageRaw().type(),
4595 data.depthOrRightRaw().cols,
4596 data.depthOrRightRaw().rows,
4597 data.depthOrRightRaw().type(),
4598 CV_16UC1, CV_32FC1, CV_8UC1, CV_8UC3).c_str());
4600 if(!
data.depthOrRightRaw().empty() &&
4601 data.cameraModels().empty() &&
4602 data.stereoCameraModels().empty() &&
4605 UERROR(
"No camera calibration found, calibrate your camera!");
4615 std::vector<cv::KeyPoint> keypoints;
4616 cv::Mat descriptors;
4626 UERROR(
"Received image ID is null. "
4627 "Please set parameter Mem/GenerateIds to \"true\" or "
4628 "make sure the input source provides image ids (seq).");
4637 UERROR(
"Id of acquired image (%d) is smaller than the last in memory (%d). "
4638 "Please set parameter Mem/GenerateIds to \"true\" or "
4639 "make sure the input source provides image ids (seq) over the last in "
4640 "memory, which is %d.",
4653 if(
data.cameraModels().size())
4655 UDEBUG(
"Monocular rectification");
4657 UASSERT(
int((
data.imageRaw().cols/
data.cameraModels().size())*
data.cameraModels().size()) ==
data.imageRaw().cols);
4658 int subImageWidth =
data.imageRaw().cols/
data.cameraModels().size();
4659 cv::Mat rectifiedImages(
data.imageRaw().size(),
data.imageRaw().type());
4665 for(
unsigned int i=0;
i<
data.cameraModels().
size(); ++
i)
4667 if(
data.cameraModels()[
i].isValidForRectification())
4674 UWARN(
"Initializing rectification maps for camera %d (only done for the first image received)...",
i);
4676 UWARN(
"Initializing rectification maps for camera %d (only done for the first image received)... done!",
i);
4681 cv::Mat rectifiedImage =
_rectCameraModels[
i].rectifyImage(cv::Mat(
data.imageRaw(), cv::Rect(subImageWidth*
i, 0, subImageWidth,
data.imageRaw().rows)));
4682 rectifiedImage.copyTo(cv::Mat(rectifiedImages, cv::Rect(subImageWidth*
i, 0, subImageWidth,
data.imageRaw().rows)));
4683 imagesRectified =
true;
4687 UERROR(
"Calibration for camera %d cannot be used to rectify the image. Make sure to do a "
4688 "full calibration. If images are already rectified, set %s parameter back to true.",
4690 Parameters::kRtabmapImagesAlreadyRectified().
c_str());
4691 std::cout <<
data.cameraModels()[
i] << std::endl;
4695 data.setRGBDImage(rectifiedImages,
data.depthOrRightRaw(),
data.cameraModels());
4697 else if(
data.stereoCameraModels().size())
4699 UDEBUG(
"Stereo rectification");
4700 UASSERT(
int((
data.imageRaw().cols/
data.stereoCameraModels().size())*
data.stereoCameraModels().size()) ==
data.imageRaw().cols);
4701 int subImageWidth =
data.imageRaw().cols/
data.stereoCameraModels().size();
4702 UASSERT(subImageWidth ==
data.rightRaw().cols/(
int)
data.stereoCameraModels().size());
4703 cv::Mat rectifiedLefts(
data.imageRaw().size(),
data.imageRaw().type());
4704 cv::Mat rectifiedRights(
data.rightRaw().size(),
data.rightRaw().type());
4711 for(
unsigned int i=0;
i<
data.stereoCameraModels().
size(); ++
i)
4713 if(
data.stereoCameraModels()[
i].isValidForRectification())
4720 UWARN(
"Initializing rectification maps (only done for the first image received)...");
4722 UWARN(
"Initializing rectification maps (only done for the first image received)...done!");
4728 cv::Mat rectifiedLeft =
_rectStereoCameraModels[
i].left().rectifyImage(cv::Mat(
data.imageRaw(), cv::Rect(subImageWidth*
i, 0, subImageWidth,
data.imageRaw().rows)));
4729 cv::Mat rectifiedRight =
_rectStereoCameraModels[
i].right().rectifyImage(cv::Mat(
data.rightRaw(), cv::Rect(subImageWidth*
i, 0, subImageWidth,
data.rightRaw().rows)));
4730 rectifiedLeft.copyTo(cv::Mat(rectifiedLefts, cv::Rect(subImageWidth*
i, 0, subImageWidth,
data.imageRaw().rows)));
4731 rectifiedRight.copyTo(cv::Mat(rectifiedRights, cv::Rect(subImageWidth*
i, 0, subImageWidth,
data.rightRaw().rows)));
4732 imagesRectified =
true;
4736 UERROR(
"Calibration for camera %d cannot be used to rectify the image. Make sure to do a "
4737 "full calibration. If images are already rectified, set %s parameter back to true.",
4739 Parameters::kRtabmapImagesAlreadyRectified().
c_str());
4740 std::cout <<
data.stereoCameraModels()[
i] << std::endl;
4745 data.setStereoImage(
4748 data.stereoCameraModels());
4752 UERROR(
"Stereo calibration cannot be used to rectify images. Make sure to do a "
4753 "full stereo calibration. If images are already rectified, set %s parameter back to true.",
4754 Parameters::kRtabmapImagesAlreadyRectified().
c_str());
4758 if(
stats)
stats->addStatistic(Statistics::kTimingMemRectification(),
t*1000.0
f);
4759 UDEBUG(
"time rectification = %fs",
t);
4771 UDEBUG(
"Start dictionary update thread");
4772 preUpdateThread.
start();
4778 UASSERT(
int((
data.imageRaw().cols/
data.cameraModels().size())*
data.cameraModels().size()) ==
data.imageRaw().cols);
4779 int subInputImageWidth =
data.imageRaw().cols/
data.cameraModels().size();
4780 int subInputDepthWidth =
data.depthRaw().cols/
data.cameraModels().size();
4781 int subOutputImageWidth = 0;
4782 int subOutputDepthWidth = 0;
4783 cv::Mat rotatedColorImages;
4784 cv::Mat rotatedDepthImages;
4785 std::vector<CameraModel> rotatedCameraModels;
4786 bool allOutputSizesAreOkay =
true;
4787 bool atLeastOneCameraRotated =
false;
4788 for(
size_t i=0;
i<
data.cameraModels().
size(); ++
i)
4790 UDEBUG(
"Rotating camera %ld",
i);
4791 cv::Mat rgb = cv::Mat(
data.imageRaw(), cv::Rect(subInputImageWidth*
i, 0, subInputImageWidth,
data.imageRaw().rows));
4792 cv::Mat depth = !
data.depthRaw().empty()?cv::Mat(
data.depthRaw(), cv::Rect(subInputDepthWidth*
i, 0, subInputDepthWidth,
data.depthRaw().rows)):cv::Mat();
4795 if(rotatedColorImages.empty())
4797 rotatedColorImages = cv::Mat(cv::Size(rgb.cols *
data.cameraModels().size(), rgb.rows), rgb.type());
4798 subOutputImageWidth = rgb.cols;;
4801 rotatedDepthImages = cv::Mat(cv::Size(depth.cols *
data.cameraModels().size(), depth.rows), depth.type());
4802 subOutputDepthWidth = depth.cols;
4805 else if(rgb.cols != subOutputImageWidth || depth.cols != subOutputDepthWidth ||
4806 rgb.rows != rotatedColorImages.rows || depth.rows != rotatedDepthImages.rows)
4808 UWARN(
"Rotated image for camera index %d (rgb=%dx%d depth=%dx%d) doesn't tally "
4809 "with the first camera (rgb=%dx%d, depth=%dx%d). Aborting upside up rotation, "
4810 "will use original image orientation. Set parameter %s to false to avoid "
4814 depth.cols, depth.rows,
4815 subOutputImageWidth, rotatedColorImages.rows,
4816 subOutputDepthWidth, rotatedDepthImages.rows,
4817 Parameters::kMemRotateImagesUpsideUp().c_str());
4818 allOutputSizesAreOkay =
false;
4821 rgb.copyTo(cv::Mat(rotatedColorImages, cv::Rect(subOutputImageWidth*
i, 0, subOutputImageWidth, rgb.rows)));
4824 depth.copyTo(cv::Mat(rotatedDepthImages, cv::Rect(subOutputDepthWidth*
i, 0, subOutputDepthWidth, depth.rows)));
4826 rotatedCameraModels.push_back(
model);
4828 if(allOutputSizesAreOkay && atLeastOneCameraRotated)
4830 data.setRGBDImage(rotatedColorImages, rotatedDepthImages, rotatedCameraModels);
4833 if(!
data.keypoints().empty() || !
data.keypoints3D().empty() || !
data.descriptors().empty())
4837 static bool warned =
false;
4840 UWARN(
"Because parameter %s is enabled, parameter %s is inhibited as "
4841 "features have to be regenerated. To avoid this warning, set "
4842 "explicitly %s to false. This message is only "
4844 Parameters::kMemRotateImagesUpsideUp().
c_str(),
4845 Parameters::kMemUseOdomFeatures().
c_str(),
4846 Parameters::kMemUseOdomFeatures().
c_str());
4850 data.setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
4856 static bool warned =
false;
4859 UWARN(
"Parameter %s can only be used with RGB-only or RGB-D cameras. "
4860 "Ignoring upside up rotation. This message is only printed once.",
4861 Parameters::kMemRotateImagesUpsideUp().
c_str());
4866 unsigned int preDecimation = 1;
4867 std::vector<cv::Point3f> keypoints3D;
4869 UDEBUG(
"Received kpts=%d kpts3D=%d, descriptors=%d _useOdometryFeatures=%s",
4872 data.keypoints().empty() ||
4873 (
int)
data.keypoints().size() !=
data.descriptors().rows ||
4878 decimatedData =
data;
4883 if( !
data.cameraModels().empty() &&
4884 data.cameraModels()[0].imageHeight()>0 &&
4885 data.cameraModels()[0].imageWidth()>0)
4889 if(targetSize >=
data.depthRaw().rows)
4891 decimationDepth = 1;
4895 decimationDepth = (
int)
ceil(
float(
data.depthRaw().rows) /
float(targetSize));
4900 std::vector<CameraModel> cameraModels = decimatedData.
cameraModels();
4901 for(
unsigned int i=0;
i<cameraModels.size(); ++
i)
4905 if(!cameraModels.empty())
4913 std::vector<StereoCameraModel> stereoCameraModels = decimatedData.
stereoCameraModels();
4914 for(
unsigned int i=0;
i<stereoCameraModels.size(); ++
i)
4918 if(!stereoCameraModels.empty())
4923 stereoCameraModels);
4927 UINFO(
"Extract features");
4929 if(decimatedData.
imageRaw().channels() == 3)
4931 cv::cvtColor(decimatedData.
imageRaw(), imageMono, CV_BGR2GRAY);
4935 imageMono = decimatedData.
imageRaw();
4941 if(imageMono.rows % decimatedData.
depthRaw().rows == 0 &&
4942 imageMono.cols % decimatedData.
depthRaw().cols == 0 &&
4943 imageMono.rows/decimatedData.
depthRaw().rows == imageMono.cols/decimatedData.
depthRaw().cols)
4945 depthMask = decimatedData.
depthRaw();
4955 depthMask = depthBelow;
4961 UDEBUG(
"Masking floor done.");
4968 UWARN(
"%s is true, but RGB size (%dx%d) modulo depth size (%dx%d) is not 0. Ignoring depth mask for feature detection (%s=%d).",
4969 Parameters::kMemDepthAsMask().
c_str(),
4970 imageMono.cols, imageMono.rows,
4976 bool useProvided3dPoints =
false;
4979 UDEBUG(
"Using provided keypoints (%d)", (
int)
data.keypoints().size());
4980 keypoints =
data.keypoints();
4982 useProvided3dPoints = keypoints.size() ==
data.keypoints3D().size();
4990 for(
unsigned int i=0;
i < keypoints.size(); ++
i)
4992 cv::KeyPoint & kpt = keypoints[
i];
4995 kpt.pt.x *= decimationRatio;
4996 kpt.pt.y *= decimationRatio;
4997 kpt.size *= decimationRatio;
4998 kpt.octave += log2value;
5000 if(useProvided3dPoints)
5002 keypoints[
i].class_id =
i;
5024 if(tmpMaxFeatureParameter.size())
5026 tmpMaxFeatureParameter.at(Parameters::kKpMaxFeatures()) =
uNumber2Str(oldMaxFeatures);
5030 if(
stats)
stats->addStatistic(Statistics::kTimingMemKeypoints_detection(),
t*1000.0
f);
5031 UDEBUG(
"time keypoints (%d) = %fs", (
int)keypoints.size(),
t);
5036 if(
stats)
stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(),
t*1000.0
f);
5037 UDEBUG(
"time descriptors (%d) = %fs", descriptors.rows,
t);
5040 if(descriptors.rows && descriptors.rows <
_badSignRatio *
float(meanWordsPerLocation))
5042 descriptors = cv::Mat();
5046 if(!imagesRectified && decimatedData.
cameraModels().size())
5048 UASSERT_MSG((
int)keypoints.size() == descriptors.rows,
uFormat(
"%d vs %d", (
int)keypoints.size(), descriptors.rows).c_str());
5049 std::vector<cv::KeyPoint> keypointsValid;
5050 keypointsValid.reserve(keypoints.size());
5051 cv::Mat descriptorsValid;
5052 descriptorsValid.reserve(descriptors.rows);
5057 std::vector<cv::Point2f> pointsIn, pointsOut;
5058 cv::KeyPoint::convert(keypoints,pointsIn);
5061 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
5064 cv::Mat
D(1, 4, CV_64FC1);
5065 D.at<
double>(0,0) = decimatedData.
cameraModels()[0].D_raw().at<
double>(0,0);
5066 D.at<
double>(0,1) = decimatedData.
cameraModels()[0].D_raw().at<
double>(0,1);
5067 D.at<
double>(0,2) = decimatedData.
cameraModels()[0].D_raw().at<
double>(0,4);
5068 D.at<
double>(0,3) = decimatedData.
cameraModels()[0].D_raw().at<
double>(0,5);
5069 cv::fisheye::undistortPoints(pointsIn, pointsOut,
5077 UWARN(
"Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
5078 CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
5083 cv::undistortPoints(pointsIn, pointsOut,
5089 UASSERT(pointsOut.size() == keypoints.size());
5090 for(
unsigned int i=0;
i<pointsOut.size(); ++
i)
5092 if(pointsOut.at(
i).x>=0 && pointsOut.at(
i).x<decimatedData.
cameraModels()[0].imageWidth() &&
5093 pointsOut.at(
i).y>=0 && pointsOut.at(
i).y<decimatedData.
cameraModels()[0].imageHeight())
5095 keypointsValid.push_back(keypoints.at(
i));
5096 keypointsValid.back().pt.x = pointsOut.at(
i).x;
5097 keypointsValid.back().pt.y = pointsOut.at(
i).y;
5098 descriptorsValid.push_back(descriptors.row(
i));
5106 for(
unsigned int i=0;
i<keypoints.size(); ++
i)
5108 int cameraIndex =
int(keypoints.at(
i).pt.x / subImageWidth);
5110 uFormat(
"cameraIndex=%d, models=%d, kpt.x=%f, subImageWidth=%f (Camera model image width=%d)",
5111 cameraIndex, (
int)decimatedData.
cameraModels().size(), keypoints[
i].pt.x, subImageWidth, decimatedData.
cameraModels()[0].imageWidth()).c_str());
5113 std::vector<cv::Point2f> pointsIn, pointsOut;
5114 pointsIn.push_back(cv::Point2f(keypoints.at(
i).pt.x-subImageWidth*cameraIndex, keypoints.at(
i).pt.y));
5115 if(decimatedData.
cameraModels()[cameraIndex].D_raw().cols == 6)
5117 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
5120 cv::Mat
D(1, 4, CV_64FC1);
5121 D.at<
double>(0,0) = decimatedData.
cameraModels()[cameraIndex].D_raw().at<
double>(0,0);
5122 D.at<
double>(0,1) = decimatedData.
cameraModels()[cameraIndex].D_raw().at<
double>(0,1);
5123 D.at<
double>(0,2) = decimatedData.
cameraModels()[cameraIndex].D_raw().at<
double>(0,4);
5124 D.at<
double>(0,3) = decimatedData.
cameraModels()[cameraIndex].D_raw().at<
double>(0,5);
5125 cv::fisheye::undistortPoints(pointsIn, pointsOut,
5133 UWARN(
"Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
5134 CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
5139 cv::undistortPoints(pointsIn, pointsOut,
5146 if(pointsOut[0].
x>=0 && pointsOut[0].
x<decimatedData.
cameraModels()[cameraIndex].imageWidth() &&
5147 pointsOut[0].y>=0 && pointsOut[0].y<decimatedData.
cameraModels()[cameraIndex].imageHeight())
5149 keypointsValid.push_back(keypoints.at(
i));
5150 keypointsValid.back().pt.x = pointsOut[0].x + subImageWidth*cameraIndex;
5151 keypointsValid.back().pt.y = pointsOut[0].y;
5152 descriptorsValid.push_back(descriptors.row(
i));
5157 keypoints = keypointsValid;
5158 descriptors = descriptorsValid;
5161 if(
stats)
stats->addStatistic(Statistics::kTimingMemRectification(),
t*1000.0
f);
5162 UDEBUG(
"time rectification = %fs",
t);
5165 if(useProvided3dPoints && keypoints.size() !=
data.keypoints3D().size())
5167 UDEBUG(
"Using provided 3d points (%d->%d)", (
int)
data.keypoints3D().size(), (
int)keypoints.size());
5168 keypoints3D.resize(keypoints.size());
5169 for(
size_t i=0;
i<keypoints.size(); ++
i)
5171 UASSERT(keypoints[
i].class_id < (
int)
data.keypoints3D().size());
5172 keypoints3D[
i] =
data.keypoints3D()[keypoints[
i].class_id];
5175 else if(useProvided3dPoints && keypoints.size() ==
data.keypoints3D().size())
5177 UDEBUG(
"Using provided 3d points (%d)", (
int)
data.keypoints3D().size());
5178 keypoints3D =
data.keypoints3D();
5185 if(
stats)
stats->addStatistic(Statistics::kTimingMemKeypoints_3D(),
t*1000.0
f);
5186 UDEBUG(
"time keypoints 3D (%d) = %fs", (
int)keypoints3D.size(),
t);
5194 else if(
data.imageRaw().empty())
5196 UDEBUG(
"Empty image, cannot extract features...");
5198 else if(_feature2D->getMaxFeatures() < 0)
5200 UDEBUG(
"_feature2D->getMaxFeatures()(%d<0) so don't extract any features...", _feature2D->getMaxFeatures());
5204 UDEBUG(
"Intermediate node detected, don't extract features!");
5207 else if(_feature2D->getMaxFeatures() >= 0 && !isIntermediateNode)
5209 UINFO(
"Use odometry features: kpts=%d 3d=%d desc=%d (dim=%d, type=%d)",
5210 (
int)
data.keypoints().size(),
5211 (
int)
data.keypoints3D().size(),
5212 data.descriptors().rows,
5213 data.descriptors().cols,
5214 data.descriptors().type());
5215 keypoints =
data.keypoints();
5216 keypoints3D =
data.keypoints3D();
5217 descriptors =
data.descriptors().clone();
5219 UASSERT(descriptors.empty() || descriptors.rows == (
int)keypoints.size());
5220 UASSERT(keypoints3D.empty() || keypoints3D.size() == keypoints.size());
5222 int maxFeatures = _rawDescriptorsKept&&!pose.isNull()&&_feature2D->getMaxFeatures()>0&&_feature2D->getMaxFeatures()<_visMaxFeatures?_visMaxFeatures:_feature2D->getMaxFeatures();
5223 bool ssc = _rawDescriptorsKept&&!pose.isNull()&&_feature2D->getMaxFeatures()>0&&_feature2D->getMaxFeatures()<_visMaxFeatures?_visSSC:_feature2D->getSSC();
5224 if((
int)keypoints.size() > maxFeatures)
5226 if(
data.cameraModels().size()==1 ||
data.stereoCameraModels().size()==1)
5227 _feature2D->limitKeypoints(keypoints, keypoints3D, descriptors, maxFeatures,
data.cameraModels().size()?
data.cameraModels()[0].imageSize():
data.stereoCameraModels()[0].left().imageSize(), ssc);
5229 _feature2D->limitKeypoints(keypoints, keypoints3D, descriptors, maxFeatures);
5232 if(stats)
stats->addStatistic(Statistics::kTimingMemKeypoints_detection(), t*1000.0f);
5233 UDEBUG(
"time keypoints (%d) = %fs", (
int)keypoints.size(), t);
5235 if(descriptors.empty())
5238 if(
data.imageRaw().channels() == 3)
5240 cv::cvtColor(
data.imageRaw(), imageMono, CV_BGR2GRAY);
5244 imageMono =
data.imageRaw();
5247 UASSERT_MSG(imagesRectified,
"Cannot extract descriptors on not rectified image from keypoints which assumed to be undistorted");
5248 descriptors = _feature2D->generateDescriptors(imageMono, keypoints);
5250 else if(!imagesRectified && !
data.cameraModels().empty())
5252 std::vector<cv::KeyPoint> keypointsValid;
5253 keypointsValid.reserve(keypoints.size());
5254 cv::Mat descriptorsValid;
5255 descriptorsValid.reserve(descriptors.rows);
5256 std::vector<cv::Point3f> keypoints3DValid;
5257 keypoints3DValid.reserve(keypoints3D.size());
5260 if(
data.cameraModels().size() == 1)
5262 std::vector<cv::Point2f> pointsIn, pointsOut;
5263 cv::KeyPoint::convert(keypoints,pointsIn);
5264 if(
data.cameraModels()[0].D_raw().cols == 6)
5266 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
5269 cv::Mat
D(1, 4, CV_64FC1);
5270 D.at<
double>(0,0) =
data.cameraModels()[0].D_raw().at<
double>(0,0);
5271 D.at<
double>(0,1) =
data.cameraModels()[0].D_raw().at<
double>(0,1);
5272 D.at<
double>(0,2) =
data.cameraModels()[0].D_raw().at<
double>(0,4);
5273 D.at<
double>(0,3) =
data.cameraModels()[0].D_raw().at<
double>(0,5);
5274 cv::fisheye::undistortPoints(pointsIn, pointsOut,
5275 data.cameraModels()[0].K_raw(),
5277 data.cameraModels()[0].R(),
5278 data.cameraModels()[0].P());
5282 UWARN(
"Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
5283 CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
5288 cv::undistortPoints(pointsIn, pointsOut,
5289 data.cameraModels()[0].K_raw(),
5290 data.cameraModels()[0].D_raw(),
5291 data.cameraModels()[0].R(),
5292 data.cameraModels()[0].P());
5294 UASSERT(pointsOut.size() == keypoints.size());
5295 for(
unsigned int i=0;
i<pointsOut.size(); ++
i)
5297 if(pointsOut.at(i).x>=0 && pointsOut.at(i).x<
data.cameraModels()[0].imageWidth() &&
5298 pointsOut.at(i).y>=0 && pointsOut.at(i).y<
data.cameraModels()[0].imageHeight())
5300 keypointsValid.push_back(keypoints.at(i));
5301 keypointsValid.back().pt.x = pointsOut.at(i).x;
5302 keypointsValid.back().pt.y = pointsOut.at(i).y;
5303 descriptorsValid.push_back(descriptors.row(i));
5304 if(!keypoints3D.empty())
5306 keypoints3DValid.push_back(keypoints3D.at(i));
5313 float subImageWidth;
5314 if(!
data.imageRaw().empty())
5316 UASSERT(
int((
data.imageRaw().cols/
data.cameraModels().size())*
data.cameraModels().size()) ==
data.imageRaw().cols);
5317 subImageWidth =
data.imageRaw().cols/
data.cameraModels().size();
5322 subImageWidth =
data.cameraModels()[0].imageWidth();
5325 for(
unsigned int i=0;
i<keypoints.size(); ++
i)
5327 int cameraIndex =
int(keypoints.at(i).pt.x / subImageWidth);
5328 UASSERT_MSG(cameraIndex >= 0 && cameraIndex < (
int)
data.cameraModels().size(),
5329 uFormat(
"cameraIndex=%d, models=%d, kpt.x=%f, subImageWidth=%f (Camera model image width=%d)",
5330 cameraIndex, (
int)
data.cameraModels().size(), keypoints[i].pt.x, subImageWidth,
data.cameraModels()[0].imageWidth()).c_str());
5332 std::vector<cv::Point2f> pointsIn, pointsOut;
5333 pointsIn.push_back(cv::Point2f(keypoints.at(i).pt.x-subImageWidth*cameraIndex, keypoints.at(i).pt.y));
5334 if(
data.cameraModels()[cameraIndex].D_raw().cols == 6)
5336 #if CV_MAJOR_VERSION > 2 or (CV_MAJOR_VERSION == 2 and (CV_MINOR_VERSION >4 or (CV_MINOR_VERSION == 4 and CV_SUBMINOR_VERSION >=10)))
5339 cv::Mat
D(1, 4, CV_64FC1);
5340 D.at<
double>(0,0) =
data.cameraModels()[cameraIndex].D_raw().at<
double>(0,0);
5341 D.at<
double>(0,1) =
data.cameraModels()[cameraIndex].D_raw().at<
double>(0,1);
5342 D.at<
double>(0,2) =
data.cameraModels()[cameraIndex].D_raw().at<
double>(0,4);
5343 D.at<
double>(0,3) =
data.cameraModels()[cameraIndex].D_raw().at<
double>(0,5);
5344 cv::fisheye::undistortPoints(pointsIn, pointsOut,
5345 data.cameraModels()[cameraIndex].K_raw(),
5347 data.cameraModels()[cameraIndex].R(),
5348 data.cameraModels()[cameraIndex].P());
5352 UWARN(
"Too old opencv version (%d,%d,%d) to support fisheye model (min 2.4.10 required)!",
5353 CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION);
5358 cv::undistortPoints(pointsIn, pointsOut,
5359 data.cameraModels()[cameraIndex].K_raw(),
5360 data.cameraModels()[cameraIndex].D_raw(),
5361 data.cameraModels()[cameraIndex].R(),
5362 data.cameraModels()[cameraIndex].P());
5365 if(pointsOut[0].x>=0 && pointsOut[0].x<
data.cameraModels()[cameraIndex].imageWidth() &&
5366 pointsOut[0].y>=0 && pointsOut[0].y<
data.cameraModels()[cameraIndex].imageHeight())
5368 keypointsValid.push_back(keypoints.at(i));
5369 keypointsValid.back().pt.x = pointsOut[0].x + subImageWidth*cameraIndex;
5370 keypointsValid.back().pt.y = pointsOut[0].y;
5371 descriptorsValid.push_back(descriptors.row(i));
5372 if(!keypoints3D.empty())
5374 keypoints3DValid.push_back(keypoints3D.at(i));
5380 keypoints = keypointsValid;
5381 descriptors = descriptorsValid;
5382 keypoints3D = keypoints3DValid;
5385 if(stats)
stats->addStatistic(Statistics::kTimingMemRectification(), t*1000.0f);
5386 UDEBUG(
"time rectification = %fs", t);
5389 if(stats)
stats->addStatistic(Statistics::kTimingMemDescriptors_extraction(), t*1000.0f);
5390 UDEBUG(
"time descriptors (%d) = %fs", descriptors.rows, t);
5392 if(keypoints3D.empty() &&
5393 ((!
data.depthRaw().empty() &&
data.cameraModels().size() &&
data.cameraModels()[0].isValidForProjection()) ||
5394 (!
data.rightRaw().empty() &&
data.stereoCameraModels().size() &&
data.stereoCameraModels()[0].isValidForProjection())))
5396 keypoints3D = _feature2D->generateKeypoints3D(data, keypoints);
5398 if(_feature2D->getMinDepth() > 0.0f || _feature2D->getMaxDepth() > 0.0f)
5400 _feature2D->filterKeypointsByDepth(keypoints, descriptors, keypoints3D, _feature2D->getMinDepth(), _feature2D->getMaxDepth());
5403 if(stats)
stats->addStatistic(Statistics::kTimingMemKeypoints_3D(), t*1000.0f);
5404 UDEBUG(
"time keypoints 3D (%d) = %fs", (
int)keypoints3D.size(), t);
5406 UDEBUG(
"ratio=%f, meanWordsPerLocation=%d", _badSignRatio, meanWordsPerLocation);
5407 if(descriptors.rows && descriptors.rows < _badSignRatio *
float(meanWordsPerLocation))
5409 descriptors = cv::Mat();
5415 UDEBUG(
"Joining dictionary update thread...");
5416 preUpdateThread.join();
5417 UDEBUG(
"Joining dictionary update thread... thread finished!");
5421 if(stats)
stats->addStatistic(Statistics::kTimingMemJoining_dictionary_update(), t*1000.0f);
5424 UDEBUG(
"time descriptor and memory update (%d of size=%d) = %fs", descriptors.rows, descriptors.cols, t);
5428 UDEBUG(
"time descriptor (%d of size=%d) = %fs", descriptors.rows, descriptors.cols, t);
5431 std::list<int> wordIds;
5432 if(descriptors.rows)
5436 std::vector<bool> inliers;
5437 cv::Mat descriptorsForQuantization = descriptors;
5438 std::vector<int> quantizedToRawIndices;
5439 if(_feature2D->getMaxFeatures()>0 && descriptors.rows > _feature2D->getMaxFeatures())
5441 UASSERT((
int)keypoints.size() == descriptors.rows);
5442 int inliersCount = 0;
5443 if((_feature2D->getGridRows() > 1 || _feature2D->getGridCols() > 1) &&
5444 (decimatedData.cameraModels().size()==1 || decimatedData.stereoCameraModels().size()==1 ||
5445 data.cameraModels().size()==1 ||
data.stereoCameraModels().size()==1))
5447 Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures(),
5448 decimatedData.cameraModels().size()?decimatedData.cameraModels()[0].imageSize():
5449 decimatedData.stereoCameraModels().size()?decimatedData.stereoCameraModels()[0].left().imageSize():
5450 data.cameraModels().size()?
data.cameraModels()[0].imageSize():
data.stereoCameraModels()[0].left().imageSize(),
5451 _feature2D->getGridRows(), _feature2D->getGridCols(), _feature2D->getSSC());
5455 if(_feature2D->getGridRows() > 1 || _feature2D->getGridCols() > 1)
5457 UWARN(
"Ignored %s and %s parameters as they cannot be used for multi-cameras setup or uncalibrated camera.",
5458 Parameters::kKpGridCols().
c_str(), Parameters::kKpGridRows().
c_str());
5460 if(decimatedData.cameraModels().size()==1 || decimatedData.stereoCameraModels().size()==1 ||
5461 data.cameraModels().size()==1 ||
data.stereoCameraModels().size()==1)
5463 Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures(),
5464 decimatedData.cameraModels().size()?decimatedData.cameraModels()[0].imageSize():
5465 decimatedData.stereoCameraModels().size()?decimatedData.stereoCameraModels()[0].left().imageSize():
5466 data.cameraModels().size()?
data.cameraModels()[0].imageSize():
data.stereoCameraModels()[0].left().imageSize(),
5467 _feature2D->getSSC());
5471 Feature2D::limitKeypoints(keypoints, inliers, _feature2D->getMaxFeatures());
5474 for(
size_t i=0;
i<inliers.size(); ++
i)
5480 descriptorsForQuantization = cv::Mat(inliersCount, descriptors.cols, descriptors.type());
5481 quantizedToRawIndices.resize(inliersCount);
5483 UASSERT((
int)inliers.size() == descriptors.rows);
5484 for(
int k=0; k < descriptors.rows; ++k)
5488 UASSERT(oi < quantizedToRawIndices.size());
5489 if(descriptors.type() == CV_32FC1)
5491 memcpy(descriptorsForQuantization.ptr<
float>(oi), descriptors.ptr<
float>(k), descriptors.cols*
sizeof(
float));
5495 memcpy(descriptorsForQuantization.ptr<
char>(oi), descriptors.ptr<
char>(k), descriptors.cols*
sizeof(
char));
5497 quantizedToRawIndices[oi] = k;
5502 uFormat(
"oi=%d inliersCount=%d (maxFeatures=%d, grid=%dx%d)",
5503 oi, inliersCount, _feature2D->getMaxFeatures(), _feature2D->getGridCols(), _feature2D->getGridRows()).c_str());
5507 wordIds = _vwd->addNewWords(descriptorsForQuantization,
id);
5510 if(wordIds.size() < keypoints.size())
5512 std::vector<int> allWordIds;
5513 allWordIds.resize(keypoints.size(),-1);
5515 for(std::list<int>::iterator
iter=wordIds.begin();
iter!=wordIds.end(); ++
iter)
5517 allWordIds[quantizedToRawIndices[
i]] = *
iter;
5521 for(i=0;
i<(
int)allWordIds.size(); ++
i)
5523 if(allWordIds[i] < 0)
5525 allWordIds[
i] = negIndex--;
5532 if(stats)
stats->addStatistic(Statistics::kTimingMemAdd_new_words(), t*1000.0f);
5533 UDEBUG(
"time addNewWords %fs indexed=%d not=%d", t, _vwd->getIndexedWordsCount(), _vwd->getNotIndexedWordsCount());
5537 UDEBUG(
"id %d is a bad signature",
id);
5540 std::multimap<int, int> words;
5541 std::vector<cv::KeyPoint> wordsKpts;
5542 std::vector<cv::Point3f> words3D;
5543 cv::Mat wordsDescriptors;
5544 int words3DValid = 0;
5545 if(wordIds.size() > 0)
5547 UASSERT(wordIds.size() == keypoints.size());
5548 UASSERT(keypoints3D.size() == 0 || keypoints3D.size() == wordIds.size());
5550 float decimationRatio =
float(preDecimation) /
float(_imagePostDecimation);
5551 double log2value =
log(
double(preDecimation))/
log(2.0);
5552 for(std::list<int>::iterator
iter=wordIds.begin();
iter!=wordIds.end() && i < keypoints.size(); ++
iter, ++i)
5554 cv::KeyPoint kpt = keypoints[
i];
5555 if(preDecimation != _imagePostDecimation)
5558 kpt.pt.x *= decimationRatio;
5559 kpt.pt.y *= decimationRatio;
5560 kpt.size *= decimationRatio;
5561 kpt.octave += log2value;
5563 words.insert(std::make_pair(*
iter, words.size()));
5564 wordsKpts.push_back(kpt);
5566 if(keypoints3D.size())
5568 words3D.push_back(keypoints3D.at(i));
5569 if(util3d::isFinite(keypoints3D.at(i)))
5574 if(_rawDescriptorsKept)
5576 wordsDescriptors.push_back(descriptors.row(i));
5582 if(!landmarks.empty() && isIntermediateNode)
5584 UDEBUG(
"Landmarks provided (size=%ld) are ignored because this signature is set as intermediate.", landmarks.size());
5587 else if(_detectMarkers && !isIntermediateNode && !
data.imageRaw().empty())
5589 UDEBUG(
"Detecting markers...");
5590 if(landmarks.empty())
5592 std::vector<CameraModel> models =
data.cameraModels();
5595 for(
size_t i=0;
i<
data.stereoCameraModels().
size(); ++
i)
5597 models.push_back(
data.stereoCameraModels()[i].left());
5601 if(!models.empty() && models[0].isValidForProjection())
5603 std::map<int, MarkerInfo> markers = _markerDetector->detect(
data.imageRaw(), models,
data.depthRaw(), _landmarksSize);
5605 for(std::map<int, MarkerInfo>::iterator
iter=markers.begin();
iter!=markers.end(); ++
iter)
5607 if(
iter->first <= 0)
5609 UERROR(
"Invalid marker received! IDs should be > 0 (it is %d). Ignoring this marker.",
iter->first);
5612 cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
5613 if(_markerOrientationIgnored)
5615 covariance(cv::Range(3,6), cv::Range(3,6)) *= 9999;
5616 bool isGTSAM =
uStr2Int(
uValue(parameters_, Parameters::kOptimizerStrategy(),
uNumber2Str(Parameters::defaultOptimizerStrategy()))) == Optimizer::kTypeGTSAM;
5619 covariance(cv::Range(0,3), cv::Range(0,3)) *= _markerLinVariance;
5621 else if(_registrationPipeline->force3DoF())
5624 covariance(cv::Range(0,1), cv::Range(0,1)) *= _markerAngVariance;
5625 covariance(cv::Range(1,3), cv::Range(1,3)) *= _markerLinVariance;
5630 covariance(cv::Range(0,2), cv::Range(0,2)) *= _markerAngVariance;
5631 covariance(cv::Range(2,3), cv::Range(2,3)) *= _markerLinVariance;
5636 covariance(cv::Range(0,3), cv::Range(0,3)) *= _markerLinVariance;
5637 covariance(cv::Range(3,6), cv::Range(3,6)) *= _markerAngVariance;
5639 landmarks.insert(std::make_pair(
iter->first, Landmark(
iter->first,
iter->second.length(),
iter->second.pose(), covariance)));
5641 UDEBUG(
"Markers detected = %d", (
int)markers.size());
5645 UWARN(
"No valid camera calibration for marker detection");
5650 UWARN(
"Input data has already landmarks, cannot do marker detection.");
5653 if(stats)
stats->addStatistic(Statistics::kTimingMemMarkers_detection(), t*1000.0f);
5654 UDEBUG(
"time markers detection = %fs", t);
5657 cv::Mat image =
data.imageRaw();
5658 cv::Mat depthOrRightImage =
data.depthOrRightRaw();
5659 std::vector<CameraModel> cameraModels =
data.cameraModels();
5660 std::vector<StereoCameraModel> stereoCameraModels =
data.stereoCameraModels();
5663 if(_imagePostDecimation > 1 && !isIntermediateNode)
5665 if(_imagePostDecimation == preDecimation && decimatedData.isValid())
5667 image = decimatedData.imageRaw();
5668 depthOrRightImage = decimatedData.depthOrRightRaw();
5669 cameraModels = decimatedData.cameraModels();
5670 stereoCameraModels = decimatedData.stereoCameraModels();
5674 int decimationDepth = _imagePreDecimation;
5675 if( !
data.cameraModels().empty() &&
5676 data.cameraModels()[0].imageHeight()>0 &&
5677 data.cameraModels()[0].imageWidth()>0)
5680 int targetSize =
data.cameraModels()[0].imageHeight() / _imagePreDecimation;
5681 if(targetSize >=
data.depthRaw().rows)
5683 decimationDepth = 1;
5687 decimationDepth = (
int)
ceil(
float(
data.depthRaw().rows) /
float(targetSize));
5690 UDEBUG(
"decimation rgbOrLeft(rows=%d)=%d, depthOrRight(rows=%d)=%d",
data.imageRaw().rows, _imagePostDecimation,
data.depthOrRightRaw().rows, decimationDepth);
5694 for(
unsigned int i=0;
i<cameraModels.size(); ++
i)
5696 cameraModels[
i] = cameraModels[
i].scaled(1.0/
double(_imagePostDecimation));
5698 for(
unsigned int i=0;
i<stereoCameraModels.size(); ++
i)
5700 stereoCameraModels[
i].scale(1.0/
double(_imagePostDecimation));
5704 if(!image.empty() && (depthOrRightImage.cols > image.cols || depthOrRightImage.rows > image.rows))
5706 UWARN(
"Depth image is bigger than RGB image after post decimation, %s=%d is too high! RGB=%dx%d, depth=%dx%d",
5707 Parameters::kMemImagePostDecimation().
c_str(), _imagePostDecimation,
5708 image.cols, image.rows, depthOrRightImage.cols, depthOrRightImage.rows);
5712 if(stats)
stats->addStatistic(Statistics::kTimingMemPost_decimation(), t*1000.0f);
5713 UDEBUG(
"time post-decimation = %fs", t);
5716 if(_stereoFromMotion &&
5718 cameraModels.size() == 1 &&
5720 (words3D.size() == 0 || (words.size() == words3D.size() && words3DValid!=(
int)words3D.size())) &&
5721 _registrationPipeline->isImageRequired() &&
5722 _signatures.size() &&
5723 _signatures.rbegin()->second->mapId() == _idMapCount)
5725 UDEBUG(
"Generate 3D words using odometry (%s=true and words3DValid=%d/%d)",
5726 Parameters::kMemStereoFromMotion().
c_str(), words3DValid, (
int)words3D.size());
5727 Signature * previousS = _signatures.rbegin()->second;
5728 if(previousS->getWords().size() > 8 && words.size() > 8 && !previousS->getPose().isNull())
5730 UDEBUG(
"Previous pose(%d) = %s", previousS->id(), previousS->getPose().prettyPrint().c_str());
5731 UDEBUG(
"Current pose(%d) = %s",
id, pose.prettyPrint().c_str());
5732 Transform cameraTransform = pose.inverse() * previousS->getPose();
5734 Signature cpPrevious(2);
5737 std::vector<cv::KeyPoint> uniqueWordsKpts;
5738 cv::Mat uniqueWordsDescriptors;
5739 std::multimap<int, int> uniqueWords;
5740 for(std::map<int, int>::iterator
iter=uniqueWordsOld.begin();
iter!=uniqueWordsOld.end(); ++
iter)
5742 uniqueWords.insert(std::make_pair(
iter->first, uniqueWords.size()));
5743 uniqueWordsKpts.push_back(previousS->getWordsKpts()[
iter->second]);
5744 uniqueWordsDescriptors.push_back(previousS->getWordsDescriptors().row(
iter->second));
5746 cpPrevious.sensorData().setCameraModels(previousS->sensorData().cameraModels());
5747 cpPrevious.setWords(uniqueWords, uniqueWordsKpts, std::vector<cv::Point3f>(), uniqueWordsDescriptors);
5748 Signature cpCurrent(1);
5750 uniqueWordsKpts.clear();
5751 uniqueWordsDescriptors = cv::Mat();
5752 uniqueWords.clear();
5753 for(std::map<int, int>::iterator
iter=uniqueWordsOld.begin();
iter!=uniqueWordsOld.end(); ++
iter)
5755 uniqueWords.insert(std::make_pair(
iter->first, uniqueWords.size()));
5756 uniqueWordsKpts.push_back(wordsKpts[
iter->second]);
5757 uniqueWordsDescriptors.push_back(wordsDescriptors.row(
iter->second));
5759 cpCurrent.sensorData().setCameraModels(cameraModels);
5761 cpCurrent.setWords(uniqueWords, uniqueWordsKpts, std::vector<cv::Point3f>(), uniqueWordsDescriptors);
5765 RegistrationVis reg(parameters_);
5766 if(_registrationPipeline->isScanRequired())
5769 RegistrationVis vis(parameters_);
5770 tmpt = vis.computeTransformationMod(cpCurrent, cpPrevious, cameraTransform);
5774 tmpt = _registrationPipeline->computeTransformationMod(cpCurrent, cpPrevious, cameraTransform);
5776 UDEBUG(
"t=%s", tmpt.prettyPrint().c_str());
5781 std::map<int, cv::KeyPoint> currentWords;
5782 std::map<int, cv::KeyPoint> previousWords;
5783 for(std::map<int, int>::iterator
iter=currentUniqueWords.begin();
iter!=currentUniqueWords.end(); ++
iter)
5785 currentWords.insert(std::make_pair(
iter->first, cpCurrent.getWordsKpts()[
iter->second]));
5787 for(std::map<int, int>::iterator
iter=previousUniqueWords.begin();
iter!=previousUniqueWords.end(); ++
iter)
5789 previousWords.insert(std::make_pair(
iter->first, cpPrevious.getWordsKpts()[
iter->second]));
5797 UDEBUG(
"inliers=%d", (
int)inliers.size());
5800 float bad_point = std::numeric_limits<float>::quiet_NaN ();
5801 UASSERT(words3D.size() == 0 || words.size() == words3D.size());
5802 bool words3DWasEmpty = words3D.empty();
5803 int added3DPointsWithoutDepth = 0;
5804 for(std::multimap<int, int>::const_iterator
iter=words.begin();
iter!=words.end(); ++
iter)
5806 std::map<int, cv::Point3f>::iterator jter=inliers.find(
iter->first);
5809 if(jter != inliers.end())
5811 words3D.push_back(jter->second);
5812 ++added3DPointsWithoutDepth;
5816 words3D.push_back(cv::Point3f(bad_point,bad_point,bad_point));
5819 else if(!util3d::isFinite(words3D[
iter->second]) && jter != inliers.end())
5821 words3D[
iter->second] = jter->second;
5822 ++added3DPointsWithoutDepth;
5825 UDEBUG(
"added3DPointsWithoutDepth=%d", added3DPointsWithoutDepth);
5826 if(stats)
stats->addStatistic(Statistics::kMemoryTriangulated_points(), (
float)added3DPointsWithoutDepth);
5829 UASSERT(words3D.size() == words.size());
5830 if(stats)
stats->addStatistic(Statistics::kTimingMemKeypoints_3D_motion(), t*1000.0f);
5831 UDEBUG(
"time keypoints 3D by motion (%d) = %fs", (
int)words3D.size(), t);
5835 LaserScan laserScan =
data.laserScanRaw();
5837 if(!isIntermediateNode && laserScan.size())
5839 if(laserScan.rangeMax() == 0.0f)
5841 bool id2d = laserScan.is2d();
5842 float maxRange = 0.0f;
5843 for(
int i=0;
i<laserScan.size(); ++
i)
5845 const float * ptr = laserScan.data().ptr<
float>(0,
i);
5849 r = ptr[0]*ptr[0] + ptr[1]*ptr[1];
5853 r = ptr[0]*ptr[0] + ptr[1]*ptr[1] + ptr[2]*ptr[2];
5862 laserScan=LaserScan(laserScan.data(), laserScan.maxPoints(),
sqrt(maxRange), laserScan.format(), laserScan.localTransform());
5867 _laserScanDownsampleStepSize,
5870 _laserScanVoxelSize,
5872 _laserScanNormalRadius,
5873 _laserScanGroundNormalsUp);
5875 if(stats)
stats->addStatistic(Statistics::kTimingMemScan_filtering(), t*1000.0f);
5876 UDEBUG(
"time normals scan = %fs", t);
5880 if(this->isBinDataKept() && (!isIntermediateNode || _saveIntermediateNodeData))
5882 UDEBUG(
"Bin data kept: rgb=%d, depth=%d, scan=%d, userData=%d",
5884 depthOrRightImage.empty()?0:1,
5885 laserScan.isEmpty()?0:1,
5886 data.userDataRaw().empty()?0:1);
5888 std::vector<unsigned char> imageBytes;
5889 std::vector<unsigned char> depthBytes;
5891 if(!depthOrRightImage.empty() && depthOrRightImage.type() == CV_32FC1)
5893 if(_saveDepth16Format)
5895 static bool warned =
false;
5898 UWARN(
"Converting depth data to 16 bits format because depth type detected is 32FC1, "
5899 "feed 16UC1 depth format directly to avoid this conversion (or set parameter %s=false "
5900 "to save 32bits format). This warning is only printed once.",
5901 Parameters::kMemSaveDepth16Format().
c_str());
5906 else if(_depthCompressionFormat ==
".rvl")
5908 static bool warned =
false;
5911 UWARN(
"%s is set to false to use 32bits format but this is not "
5912 "compatible with the compressed depth format chosen (%s=\"%s\"), depth "
5913 "images will be compressed in \".png\" format instead. Explicitly "
5914 "set %s to true to keep using \"%s\" format and images will be "
5915 "converted to 16bits for convenience (warning: that would "
5916 "remove all depth values over 65 meters). Explicitly set %s=\".png\" "
5917 "to suppress this warning. This warning is only printed once.",
5918 Parameters::kMemSaveDepth16Format().
c_str(),
5919 Parameters::kMemDepthCompressionFormat().
c_str(),
5920 _depthCompressionFormat.c_str(),
5921 Parameters::kMemSaveDepth16Format().c_str(),
5922 _depthCompressionFormat.c_str(),
5923 Parameters::kMemDepthCompressionFormat().c_str());
5929 cv::Mat compressedImage;
5930 cv::Mat compressedDepth;
5931 cv::Mat compressedScan;
5932 cv::Mat compressedUserData;
5933 if(_compressionParallelized)
5936 rtabmap::CompressionThread ctDepth(depthOrRightImage, depthOrRightImage.type() == CV_32FC1 || depthOrRightImage.type() == CV_16UC1?_depthCompressionFormat:_rgbCompressionFormat);
5943 if(!depthOrRightImage.empty())
5947 if(!laserScan.isEmpty())
5949 ctLaserScan.start();
5951 if(!
data.userDataRaw().empty())
5960 compressedImage = ctImage.getCompressedData();
5961 compressedDepth = ctDepth.getCompressedData();
5962 compressedScan = ctLaserScan.getCompressedData();
5963 compressedUserData = ctUserData.getCompressedData();
5968 compressedDepth =
compressImage2(depthOrRightImage, depthOrRightImage.type() == CV_32FC1 || depthOrRightImage.type() == CV_16UC1?_depthCompressionFormat:_rgbCompressionFormat);
5973 s =
new Signature(
id,
5975 isIntermediateNode?-1:0,
5980 !stereoCameraModels.empty()?
5982 laserScan.angleIncrement() == 0.0f?
5983 LaserScan(compressedScan.empty()?
data.laserScanCompressed().data():compressedScan,
5984 laserScan.maxPoints(),
5985 laserScan.rangeMax(),
5987 laserScan.localTransform()):
5988 LaserScan(compressedScan.empty()?
data.laserScanCompressed().data():compressedScan,
5990 laserScan.rangeMin(),
5991 laserScan.rangeMax(),
5992 laserScan.angleMin(),
5993 laserScan.angleMax(),
5994 laserScan.angleIncrement(),
5995 laserScan.localTransform()),
5996 compressedImage.empty()?
data.imageCompressed():compressedImage,
5997 compressedDepth.empty()?
data.depthOrRightCompressed():compressedDepth,
6001 compressedUserData):
6003 laserScan.angleIncrement() == 0.0f?
6004 LaserScan(compressedScan.empty()?
data.laserScanCompressed().data():compressedScan,
6005 laserScan.maxPoints(),
6006 laserScan.rangeMax(),
6008 laserScan.localTransform()):
6009 LaserScan(compressedScan.empty()?
data.laserScanCompressed().data():compressedScan,
6011 laserScan.rangeMin(),
6012 laserScan.rangeMax(),
6013 laserScan.angleMin(),
6014 laserScan.angleMax(),
6015 laserScan.angleIncrement(),
6016 laserScan.localTransform()),
6017 compressedImage.empty()?
data.imageCompressed():compressedImage,
6018 compressedDepth.empty()?
data.depthOrRightCompressed():compressedDepth,
6022 compressedUserData));
6026 UDEBUG(
"Bin data kept: scan=%d, userData=%d",
6027 laserScan.isEmpty()?0:1,
6028 data.userDataRaw().empty()?0:1);
6031 cv::Mat compressedScan;
6032 cv::Mat compressedUserData;
6033 if(_compressionParallelized)
6037 if(!
data.userDataRaw().empty() && !isIntermediateNode)
6041 if(!laserScan.isEmpty() && !isIntermediateNode)
6043 ctLaserScan.start();
6048 compressedScan = ctLaserScan.getCompressedData();
6049 compressedUserData = ctUserData.getCompressedData();
6057 s =
new Signature(
id,
6059 isIntermediateNode?-1:0,
6064 !stereoCameraModels.empty()?
6066 laserScan.angleIncrement() == 0.0f?
6067 LaserScan(compressedScan.empty()?
data.laserScanCompressed().data():compressedScan,
6068 laserScan.maxPoints(),
6069 laserScan.rangeMax(),
6071 laserScan.localTransform()):
6072 LaserScan(compressedScan.empty()?
data.laserScanCompressed().data():compressedScan,
6074 laserScan.rangeMin(),
6075 laserScan.rangeMax(),
6076 laserScan.angleMin(),
6077 laserScan.angleMax(),
6078 laserScan.angleIncrement(),
6079 laserScan.localTransform()),
6085 compressedUserData):
6087 laserScan.angleIncrement() == 0.0f?
6088 LaserScan(compressedScan.empty()?
data.laserScanCompressed().data():compressedScan,
6089 laserScan.maxPoints(),
6090 laserScan.rangeMax(),
6092 laserScan.localTransform()):
6093 LaserScan(compressedScan.empty()?
data.laserScanCompressed().data():compressedScan,
6095 laserScan.rangeMin(),
6096 laserScan.rangeMax(),
6097 laserScan.angleMin(),
6098 laserScan.angleMax(),
6099 laserScan.angleIncrement(),
6100 laserScan.localTransform()),
6106 compressedUserData));
6109 s->setWords(words, wordsKpts,
6110 _reextractLoopClosureFeatures?std::vector<cv::Point3f>():words3D,
6111 _reextractLoopClosureFeatures?cv::Mat():wordsDescriptors);
6114 if(!cameraModels.empty())
6116 s->sensorData().setRGBDImage(image, depthOrRightImage, cameraModels,
false);
6120 s->sensorData().setStereoImage(image, depthOrRightImage, stereoCameraModels,
false);
6122 s->sensorData().setLaserScan(laserScan,
false);
6123 s->sensorData().setUserData(
data.userDataRaw(),
false);
6125 UDEBUG(
"data.groundTruth() =%s",
data.groundTruth().prettyPrint().c_str());
6126 UDEBUG(
"data.gps() =%s",
data.gps().stamp()?
"true":
"false");
6127 UDEBUG(
"data.envSensors() =%d", (
int)
data.envSensors().size());
6128 UDEBUG(
"data.globalDescriptors()=%d", (
int)
data.globalDescriptors().size());
6129 s->sensorData().setGroundTruth(
data.groundTruth());
6130 s->sensorData().setGPS(
data.gps());
6131 s->sensorData().setEnvSensors(
data.envSensors());
6133 if(!isIntermediateNode)
6135 std::vector<GlobalDescriptor> globalDescriptors =
data.globalDescriptors();
6136 if(_globalDescriptorExtractor)
6138 GlobalDescriptor gdescriptor = _globalDescriptorExtractor->extract(inputData);
6139 if(!gdescriptor.data().empty())
6141 globalDescriptors.push_back(gdescriptor);
6144 s->sensorData().setGlobalDescriptors(globalDescriptors);
6146 else if(!
data.globalDescriptors().empty())
6148 UDEBUG(
"Global descriptors provided (size=%ld) are ignored because this signature is set as intermediate.",
data.globalDescriptors().size());
6152 if(stats)
stats->addStatistic(Statistics::kTimingMemCompressing_data(), t*1000.0f);
6153 UDEBUG(
"time compressing data (id=%d) %fs",
id, t);
6156 s->setEnabled(
true);
6160 if(_createOccupancyGrid && !isIntermediateNode)
6162 if( (_localMapMaker->isGridFromDepth() && !
data.depthOrRightRaw().empty()) ||
6163 (!_localMapMaker->isGridFromDepth() && !
data.laserScanRaw().empty()))
6165 cv::Mat ground, obstacles,
empty;
6166 float cellSize = 0.0f;
6167 cv::Point3f viewPoint(0,0,0);
6168 _localMapMaker->createLocalMap(*s, ground, obstacles,
empty, viewPoint);
6169 cellSize = _localMapMaker->getCellSize();
6170 s->sensorData().setOccupancyGrid(ground, obstacles,
empty, cellSize, viewPoint);
6173 if(stats)
stats->addStatistic(Statistics::kTimingMemOccupancy_grid(), t*1000.0f);
6174 UDEBUG(
"time grid map = %fs", t);
6176 else if(
data.gridCellSize() != 0.0f)
6178 s->sensorData().setOccupancyGrid(
6179 data.gridGroundCellsRaw(),
6180 data.gridObstacleCellsRaw(),
6181 data.gridEmptyCellsRaw(),
6182 data.gridCellSize(),
6183 data.gridViewPoint());
6188 if(!
data.globalPose().isNull() &&
data.globalPoseCovariance().cols==6 &&
data.globalPoseCovariance().rows==6 &&
data.globalPoseCovariance().cols==CV_64FC1)
6190 s->addLink(Link(
s->id(),
s->id(), Link::kPosePrior,
data.globalPose(),
data.globalPoseCovariance().inv()));
6191 UDEBUG(
"Added global pose prior: %s",
data.globalPose().prettyPrint().c_str());
6193 if(
data.gps().stamp() > 0.0)
6195 UWARN(
"GPS constraint ignored as global pose is also set.");
6198 else if(
data.gps().stamp() > 0.0)
6205 data.gps().error() > 0.0)
6207 if(_gpsOrigin.stamp() <= 0.0)
6209 _gpsOrigin =
data.gps();
6210 UINFO(
"Added GPS origin: long=%f lat=%f alt=%f bearing=%f error=%f",
data.gps().longitude(),
data.gps().latitude(),
data.gps().altitude(),
data.gps().bearing(),
data.gps().error());
6212 cv::Point3f pt =
data.gps().toGeodeticCoords().toENU_WGS84(_gpsOrigin.toGeodeticCoords());
6213 Transform gpsPose(pt.x, pt.y,
data.gps().altitude(), 0, 0, -(
data.gps().bearing()-90.0)*
M_PI/180.0);
6214 cv::Mat gpsInfMatrix = cv::Mat::eye(6,6,CV_64FC1)/9999.0;
6216 UDEBUG(
"Added GPS prior: x=%f y=%f z=%f yaw=%f", gpsPose.x(), gpsPose.y(), gpsPose.z(), gpsPose.theta());
6218 gpsInfMatrix.at<
double>(0,0) = gpsInfMatrix.at<
double>(1,1) = 1.0/
data.gps().error();
6219 gpsInfMatrix.at<
double>(2,2) =
data.gps().error()>1.0?1.0/
data.gps().error():1.0;
6220 s->addLink(Link(
s->id(),
s->id(), Link::kPosePrior, gpsPose, gpsInfMatrix));
6224 UERROR(
"Invalid GPS value: long=%f lat=%f alt=%f bearing=%f error=%f",
data.gps().longitude(),
data.gps().latitude(),
data.gps().altitude(),
data.gps().bearing(),
data.gps().error());
6229 if(_useOdometryGravity && !pose.isNull())
6231 s->addLink(Link(
s->id(),
s->id(), Link::kGravity, pose.rotation()));
6232 UDEBUG(
"Added gravity constraint from odom pose: %s", pose.rotation().prettyPrint().c_str());
6234 else if(!
data.imu().localTransform().isNull() &&
6235 (
data.imu().orientation()[0] != 0 ||
6236 data.imu().orientation()[1] != 0 ||
6237 data.imu().orientation()[2] != 0 ||
6238 data.imu().orientation()[3] != 0))
6241 Transform
orientation(0,0,0,
data.imu().orientation()[0],
data.imu().orientation()[1],
data.imu().orientation()[2],
data.imu().orientation()[3]);
6250 for(Landmarks::const_iterator
iter = landmarks.begin();
iter!=landmarks.end(); ++
iter)
6252 if(
iter->second.id() > 0)
6254 int landmarkId = -
iter->first;
6255 cv::Mat landmarkSize;
6256 if(
iter->second.size() > 0.0f)
6258 landmarkSize = cv::Mat(1,1,CV_32FC1);
6259 landmarkSize.at<
float>(0,0) =
iter->second.size();
6261 std::pair<std::map<int, float>::iterator,
bool> inserted=_landmarksSize.insert(std::make_pair(
iter->first,
iter->second.size()));
6262 if(!inserted.second)
6264 if(inserted.first->second != landmarkSize.at<
float>(0,0))
6266 UWARN(
"Trying to update landmark size buffer for landmark %d with size=%f but "
6267 "it has already a different size set. Keeping old size (%f).",
6268 -landmarkId, inserted.first->second, landmarkSize.at<
float>(0,0));
6274 Transform landmarkPose =
iter->second.pose();
6275 if(_registrationPipeline->force3DoF())
6280 if(
fabs(tx.
z()) > 0.9)
6284 else if(
fabs(ty.
z()) > 0.9)
6290 Link landmark(
s->id(), landmarkId, Link::kLandmark, landmarkPose,
iter->second.covariance().inv(), landmarkSize);
6291 s->addLandmark(landmark);
6294 std::map<int, std::set<int> >
::iterator nter = _landmarksIndex.find(landmarkId);
6295 if(nter!=_landmarksIndex.end())
6297 nter->second.insert(
s->id());
6302 tmp.insert(
s->id());
6303 _landmarksIndex.insert(std::make_pair(landmarkId, tmp));
6308 UERROR(
"Invalid landmark received! IDs should be > 0 (it is %d). Ignoring this landmark.",
iter->second.id());
6315 void Memory::disableWordsRef(
int signatureId)
6317 UDEBUG(
"id=%d", signatureId);
6319 Signature * ss = this->_getSignature(signatureId);
6322 const std::multimap<int, int> & words = ss->
getWords();
6324 int count = _vwd->getTotalActiveReferences();
6326 for(std::list<int>::const_iterator
i=
keys.begin();
i!=
keys.end(); ++
i)
6328 _vwd->removeAllWordRef(*
i, signatureId);
6331 count -= _vwd->getTotalActiveReferences();
6333 UDEBUG(
"%d words total ref removed from signature %d... (total active ref = %d)",
count, ss->
id(), _vwd->getTotalActiveReferences());
6337 void Memory::cleanUnusedWords()
6339 std::vector<VisualWord*> removedWords = _vwd->getUnusedWords();
6340 UDEBUG(
"Removing %d words (dictionary size=%d)...", removedWords.size(), _vwd->getVisualWords().size());
6341 if(removedWords.size())
6344 _vwd->removeWords(removedWords);
6346 for(
unsigned int i=0;
i<removedWords.size(); ++
i)
6350 _dbDriver->asyncSave(removedWords[
i]);
6354 delete removedWords[
i];
6360 void Memory::enableWordsRef(
const std::list<int> & signatureIds)
6362 UDEBUG(
"size=%d", signatureIds.size());
6366 std::map<int, int> refsToChange;
6368 std::set<int> oldWordIds;
6369 std::list<Signature *> surfSigns;
6370 for(std::list<int>::const_iterator
i=signatureIds.begin();
i!=signatureIds.end(); ++
i)
6375 surfSigns.push_back(ss);
6379 for(std::list<int>::const_iterator k=uniqueKeys.begin(); k!=uniqueKeys.end(); ++k)
6381 if(*k>0 && _vwd->getWord(*k) == 0 && _vwd->getUnusedWord(*k) == 0)
6383 oldWordIds.insert(oldWordIds.end(), *k);
6389 if(!_vwd->isIncremental() && oldWordIds.size())
6391 UWARN(
"Dictionary is fixed, but some words retrieved have not been found!?");
6394 UDEBUG(
"oldWordIds.size()=%d, getOldIds time=%fs", oldWordIds.size(),
timer.ticks());
6397 std::list<VisualWord *> vws;
6398 if(oldWordIds.size() && _dbDriver)
6401 _dbDriver->loadWords(oldWordIds, vws);
6403 UDEBUG(
"loading words(%d) time=%fs", oldWordIds.size(),
timer.ticks());
6409 std::vector<int> vwActiveIds = _vwd->findNN(vws);
6410 UDEBUG(
"find active ids (number=%d) time=%fs", vws.size(),
timer.ticks());
6412 for(std::list<VisualWord *>::iterator iterVws=vws.begin(); iterVws!=vws.end(); ++iterVws)
6414 if(vwActiveIds[
i] > 0)
6417 refsToChange.insert(refsToChange.end(), std::pair<int, int>((*iterVws)->id(), vwActiveIds[
i]));
6418 if((*iterVws)->isSaved())
6424 _dbDriver->asyncSave(*iterVws);
6430 _vwd->addWord(*iterVws);
6434 UDEBUG(
"Added %d to dictionary, time=%fs", vws.size()-refsToChange.size(),
timer.ticks());
6437 for(std::map<int, int>::const_iterator
iter=refsToChange.begin();
iter != refsToChange.end(); ++
iter)
6440 for(std::list<Signature *>::iterator
j=surfSigns.begin();
j!=surfSigns.end(); ++
j)
6442 (*j)->changeWordsRef(
iter->first,
iter->second);
6445 UDEBUG(
"changing ref, total=%d, time=%fs", refsToChange.size(),
timer.ticks());
6448 int count = _vwd->getTotalActiveReferences();
6451 for(std::list<Signature *>::iterator
j=surfSigns.begin();
j!=surfSigns.end(); ++
j)
6453 const std::vector<int> &
keys =
uKeys((*j)->getWords());
6457 for(
unsigned int i=0;
i<
keys.size(); ++
i)
6461 _vwd->addWordRef(
keys.at(
i), (*j)->id());
6464 (*j)->setEnabled(
true);
6468 count = _vwd->getTotalActiveReferences() -
count;
6469 UDEBUG(
"%d words total ref added from %d signatures, time=%fs...",
count, surfSigns.size(),
timer.ticks());
6472 std::set<int> Memory::reactivateSignatures(
const std::list<int> & ids,
unsigned int maxLoaded,
double & timeDbAccess)
6480 std::list<int> idsToLoad;
6481 std::map<int, int>::iterator wmIter;
6482 for(std::list<int>::const_iterator
i=ids.begin();
i!=ids.end(); ++
i)
6484 if(!this->getSignature(*
i) && !
uContains(idsToLoad, *
i))
6486 if(!maxLoaded || idsToLoad.size() < maxLoaded)
6488 idsToLoad.push_back(*
i);
6489 UINFO(
"Loading location %d from database...", *
i);
6494 UDEBUG(
"idsToLoad = %d", idsToLoad.size());
6496 std::list<Signature *> reactivatedSigns;
6499 _dbDriver->loadSignatures(idsToLoad, reactivatedSigns);
6501 timeDbAccess =
timer.getElapsedTime();
6502 std::list<int> idsLoaded;
6503 for(std::list<Signature *>::iterator
i=reactivatedSigns.begin();
i!=reactivatedSigns.end(); ++
i)
6505 if(!(*i)->getLandmarks().empty())
6508 for(std::map<int, Link>::const_iterator
iter = (*i)->getLandmarks().begin();
iter!=(*i)->getLandmarks().end(); ++
iter)
6510 int landmarkId =
iter->first;
6513 cv::Mat landmarkSize =
iter->second.uncompressUserDataConst();
6514 if(!landmarkSize.empty() && landmarkSize.type() == CV_32FC1 && landmarkSize.total()==1)
6516 std::pair<std::map<int, float>::iterator,
bool> inserted=_landmarksSize.insert(std::make_pair(-landmarkId, landmarkSize.at<
float>(0,0)));
6517 if(!inserted.second)
6519 if(inserted.first->second != landmarkSize.at<
float>(0,0))
6521 UWARN(
"Trying to update landmark size buffer for landmark %d with size=%f but "
6522 "it has already a different size set. Keeping old size (%f).",
6523 -landmarkId, inserted.first->second, landmarkSize.at<
float>(0,0));
6528 std::map<int, std::set<int> >
::iterator nter = _landmarksIndex.find(landmarkId);
6529 if(nter!=_landmarksIndex.end())
6531 nter->second.insert((*i)->id());
6536 tmp.insert((*i)->id());
6537 _landmarksIndex.insert(std::make_pair(landmarkId, tmp));
6542 idsLoaded.push_back((*i)->id());
6544 this->addSignatureToWmFromLTM(*
i);
6546 this->enableWordsRef(idsLoaded);
6548 return std::set<int>(idsToLoad.begin(), idsToLoad.end());
6553 void Memory::getMetricConstraints(
6554 const std::set<int> & ids,
6555 std::map<int, Transform> & poses,
6556 std::multimap<int, Link> & links,
6557 bool lookInDatabase,
6558 bool landmarksAdded)
6561 for(std::set<int>::const_iterator
iter=ids.begin();
iter!=ids.end(); ++
iter)
6566 poses.insert(std::make_pair(*
iter, pose));
6570 for(std::set<int>::const_iterator
iter=ids.begin();
iter!=ids.end(); ++
iter)
6574 std::multimap<int, Link> tmpLinks = getLinks(*
iter, lookInDatabase,
true);
6575 for(std::multimap<int, Link>::iterator jter=tmpLinks.begin(); jter!=tmpLinks.end(); ++jter)
6577 std::multimap<int, Link>::iterator addedLinksIterator =
graph::findLink(links, *
iter, jter->first);
6578 if( jter->second.isValid() &&
6579 (addedLinksIterator == links.end() || addedLinksIterator->second.from()==addedLinksIterator->second.to()) &&
6580 (
uContains(poses, jter->first) || (landmarksAdded && jter->second.type() == Link::kLandmark)))
6582 if(!lookInDatabase &&
6583 (jter->second.type() == Link::kNeighbor ||
6584 jter->second.type() == Link::kNeighborMerged))
6586 const Signature *
s = this->getSignature(jter->first);
6588 if(
s->getWeight() == -1)
6590 Link link = jter->second;
6591 while(
s &&
s->getWeight() == -1)
6595 std::multimap<int, Link>
n = this->getNeighborLinks(
s->id(),
false);
6597 std::multimap<int, Link>::iterator uter =
n.upper_bound(
s->id());
6600 const Signature * s2 = this->getSignature(uter->first);
6603 link = link.
merge(uter->second, uter->second.type());
6604 poses.erase(
s->id());
6614 links.insert(std::make_pair(*
iter, link));
6618 links.insert(std::make_pair(*
iter, jter->second));
6621 else if(jter->second.type() != Link::kLandmark)
6623 links.insert(std::make_pair(*
iter, jter->second));
6625 else if(landmarksAdded)
6629 poses.insert(std::make_pair(jter->first, poses.at(*
iter) * jter->second.transform()));
6631 links.insert(std::make_pair(jter->first, jter->second.inverse()));