Increased version 0.20.4. Added parameter Kp/ByteToFloat (default true to use less memory with kdtree and binary descriptors). Memory/Sqlite3: Setting weight to -9 for invalid nodes (to make sure they are not reloaded from database, to fix a graph reduced issue). Added 12-SURF/FREAK detector approach. rtabmap-info: added number of nodes in each sessions.

This commit is contained in:
matlabbe
2020-09-28 10:29:14 -04:00
parent c5158cade5
commit 933ac736f1
13 changed files with 257 additions and 82 deletions

View File

@@ -21,7 +21,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
####################### #######################
SET(RTABMAP_MAJOR_VERSION 0) SET(RTABMAP_MAJOR_VERSION 0)
SET(RTABMAP_MINOR_VERSION 20) SET(RTABMAP_MINOR_VERSION 20)
SET(RTABMAP_PATCH_VERSION 3) SET(RTABMAP_PATCH_VERSION 4)
SET(RTABMAP_VERSION SET(RTABMAP_VERSION
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION}) ${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})

View File

@@ -115,7 +115,8 @@ public:
kFeatureGfttOrb=8, //new 0.10.11 kFeatureGfttOrb=8, //new 0.10.11
kFeatureKaze=9, //new 0.13.2 kFeatureKaze=9, //new 0.13.2
kFeatureOrbOctree=10, //new 0.19.2 kFeatureOrbOctree=10, //new 0.19.2
kFeatureSuperPointTorch=11}; //new 0.19.7 kFeatureSuperPointTorch=11, //new 0.19.7
kFeatureSurfFreak=12}; //new 0.20.4
static std::string typeName(Type type) static std::string typeName(Type type)
{ {
switch(type){ switch(type){
@@ -143,6 +144,8 @@ public:
return "ORB-OCTREE"; return "ORB-OCTREE";
case kFeatureSuperPointTorch: case kFeatureSuperPointTorch:
return "SUPERPOINT"; return "SUPERPOINT";
case kFeatureSurfFreak:
return "SURF+Freak";
default: default:
return "Unknown"; return "Unknown";
} }
@@ -455,6 +458,28 @@ private:
cv::Ptr<CV_FREAK> _freak; cv::Ptr<CV_FREAK> _freak;
}; };
//SURF_FREAK
class RTABMAP_EXP SURF_FREAK : public SURF
{
public:
SURF_FREAK(const ParametersMap & parameters = ParametersMap());
virtual ~SURF_FREAK();
virtual void parseParameters(const ParametersMap & parameters);
virtual Feature2D::Type getType() const {return kFeatureSurfFreak;}
private:
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private:
bool orientationNormalized_;
bool scaleNormalized_;
float patternScale_;
int nOctaves_;
cv::Ptr<CV_FREAK> _freak;
};
//GFTT_ORB //GFTT_ORB
class RTABMAP_EXP GFTT_ORB : public GFTT class RTABMAP_EXP GFTT_ORB : public GFTT
{ {

View File

@@ -236,6 +236,7 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Kp, IncrementalDictionary, bool, true, ""); RTABMAP_PARAM(Kp, IncrementalDictionary, bool, true, "");
RTABMAP_PARAM(Kp, IncrementalFlann, bool, true, uFormat("When using FLANN based strategy, add/remove points to its index without always rebuilding the index (the index is built only when the dictionary increases of the factor \"%s\" in size).", kKpFlannRebalancingFactor().c_str())); RTABMAP_PARAM(Kp, IncrementalFlann, bool, true, uFormat("When using FLANN based strategy, add/remove points to its index without always rebuilding the index (the index is built only when the dictionary increases of the factor \"%s\" in size).", kKpFlannRebalancingFactor().c_str()));
RTABMAP_PARAM(Kp, FlannRebalancingFactor, float, 2.0, uFormat("Factor used when rebuilding the incremental FLANN index (see \"%s\"). Set <=1 to disable.", kKpIncrementalFlann().c_str())); RTABMAP_PARAM(Kp, FlannRebalancingFactor, float, 2.0, uFormat("Factor used when rebuilding the incremental FLANN index (see \"%s\"). Set <=1 to disable.", kKpIncrementalFlann().c_str()));
RTABMAP_PARAM(Kp, ByteToFloat, bool, true, uFormat("For %s=1, binary descriptors are converted to float by converting each byte to float instead of converting each bit to float. When converting bytes instead of bits, less memory is used and search is faster at the cost of slightly less accurate matching.", kKpNNStrategy().c_str()));
RTABMAP_PARAM(Kp, MaxDepth, float, 0, "Filter extracted keypoints by depth (0=inf)."); RTABMAP_PARAM(Kp, MaxDepth, float, 0, "Filter extracted keypoints by depth (0=inf).");
RTABMAP_PARAM(Kp, MinDepth, float, 0, "Filter extracted keypoints by depth."); RTABMAP_PARAM(Kp, MinDepth, float, 0, "Filter extracted keypoints by depth.");
RTABMAP_PARAM(Kp, MaxFeatures, int, 500, "Maximum features extracted from the images (0 means not bounded, <0 means no extraction)."); RTABMAP_PARAM(Kp, MaxFeatures, int, 500, "Maximum features extracted from the images (0 means not bounded, <0 means no extraction).");
@@ -243,9 +244,9 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Kp, NndrRatio, float, 0.8, "NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)"); RTABMAP_PARAM(Kp, NndrRatio, float, 0.8, "NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)");
#if CV_MAJOR_VERSION > 2 && !defined(HAVE_OPENCV_XFEATURES2D) #if CV_MAJOR_VERSION > 2 && !defined(HAVE_OPENCV_XFEATURES2D)
// OpenCV>2 without xFeatures2D module doesn't have BRIEF // OpenCV>2 without xFeatures2D module doesn't have BRIEF
RTABMAP_PARAM(Kp, DetectorStrategy, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch."); RTABMAP_PARAM(Kp, DetectorStrategy, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch 12=SURF/FREAK.");
#else #else
RTABMAP_PARAM(Kp, DetectorStrategy, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch."); RTABMAP_PARAM(Kp, DetectorStrategy, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch 12=SURF/FREAK.");
#endif #endif
RTABMAP_PARAM(Kp, TfIdfLikelihoodUsed, bool, true, "Use of the td-idf strategy to compute the likelihood."); RTABMAP_PARAM(Kp, TfIdfLikelihoodUsed, bool, true, "Use of the td-idf strategy to compute the likelihood.");
RTABMAP_PARAM(Kp, Parallelized, bool, true, "If the dictionary update and signature creation were parallelized."); RTABMAP_PARAM(Kp, Parallelized, bool, true, "If the dictionary update and signature creation were parallelized.");
@@ -586,9 +587,9 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Vis, Iterations, int, 300, "Maximum iterations to compute the transform."); RTABMAP_PARAM(Vis, Iterations, int, 300, "Maximum iterations to compute the transform.");
#if CV_MAJOR_VERSION > 2 && !defined(HAVE_OPENCV_XFEATURES2D) #if CV_MAJOR_VERSION > 2 && !defined(HAVE_OPENCV_XFEATURES2D)
// OpenCV>2 without xFeatures2D module doesn't have BRIEF // OpenCV>2 without xFeatures2D module doesn't have BRIEF
RTABMAP_PARAM(Vis, FeatureType, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch."); RTABMAP_PARAM(Vis, FeatureType, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch 12=SURF/FREAK.");
#else #else
RTABMAP_PARAM(Vis, FeatureType, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch."); RTABMAP_PARAM(Vis, FeatureType, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch 12=SURF/FREAK.");
#endif #endif
RTABMAP_PARAM(Vis, MaxFeatures, int, 1000, "0 no limits."); RTABMAP_PARAM(Vis, MaxFeatures, int, 1000, "0 no limits.");
RTABMAP_PARAM(Vis, MaxDepth, float, 0, "Max depth of the features (0 means no limit)."); RTABMAP_PARAM(Vis, MaxDepth, float, 0, "Max depth of the features (0 means no limit).");

View File

@@ -101,7 +101,7 @@ public:
int getTotalActiveReferences() const {return _totalActiveReferences;} int getTotalActiveReferences() const {return _totalActiveReferences;}
unsigned int getIndexedWordsCount() const; unsigned int getIndexedWordsCount() const;
unsigned int getIndexMemoryUsed() const; unsigned int getIndexMemoryUsed() const;
void setNNStrategy(NNStrategy strategy); bool setNNStrategy(NNStrategy strategy); // Return true if the search tree has been re-initialized
bool isIncremental() const {return _incrementalDictionary;} bool isIncremental() const {return _incrementalDictionary;}
bool isIncrementalFlann() const {return _incrementalFlann;} bool isIncrementalFlann() const {return _incrementalFlann;}
void setIncrementalDictionary(); void setIncrementalDictionary();
@@ -117,8 +117,8 @@ public:
void deleteUnusedWords(); void deleteUnusedWords();
public: public:
static cv::Mat convertBinTo32F(const cv::Mat & descriptorsIn); static cv::Mat convertBinTo32F(const cv::Mat & descriptorsIn, bool byteToFloat = true);
static cv::Mat convert32FToBin(const cv::Mat & descriptorsIn); static cv::Mat convert32FToBin(const cv::Mat & descriptorsIn, bool byteToFloat = true);
protected: protected:
int getNextId(); int getNextId();
@@ -131,6 +131,7 @@ private:
bool _incrementalDictionary; bool _incrementalDictionary;
bool _incrementalFlann; bool _incrementalFlann;
float _rebalancingFactor; float _rebalancingFactor;
bool _byteToFloat;
float _nndrRatio; float _nndrRatio;
std::string _dictionaryPath; // a pre-computed dictionary (.txt or .db) std::string _dictionaryPath; // a pre-computed dictionary (.txt or .db)
std::string _newDictionaryPath; // a pre-computed dictionary (.txt or .db) std::string _newDictionaryPath; // a pre-computed dictionary (.txt or .db)

View File

@@ -2377,6 +2377,7 @@ void DBDriverSqlite3::getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildre
query << "INNER JOIN Link "; query << "INNER JOIN Link ";
query << "ON id = to_id "; // use to_id to ignore all children (which don't have link pointing on them) query << "ON id = to_id "; // use to_id to ignore all children (which don't have link pointing on them)
query << "WHERE from_id != to_id "; // ignore self referring links query << "WHERE from_id != to_id "; // ignore self referring links
query << "AND weight>-9 "; //ignore invalid nodes
} }
if(ignoreBadSignatures) if(ignoreBadSignatures)
@@ -3622,6 +3623,7 @@ void DBDriverSqlite3::loadWordsQuery(const std::set<int> & wordIds, std::list<Vi
int descriptorSize; int descriptorSize;
const void * descriptor; const void * descriptor;
int dRealSize; int dRealSize;
unsigned long dRealSizeTotal = 0;
for(std::set<int>::const_iterator iter=wordIds.begin(); iter!=wordIds.end(); ++iter) for(std::set<int>::const_iterator iter=wordIds.begin(); iter!=wordIds.end(); ++iter)
{ {
// bind id // bind id
@@ -3654,6 +3656,7 @@ void DBDriverSqlite3::loadWordsQuery(const std::set<int> & wordIds, std::list<Vi
} }
memcpy(d.data, descriptor, dRealSize); memcpy(d.data, descriptor, dRealSize);
dRealSizeTotal+=dRealSize;
VisualWord * vw = new VisualWord(*iter, d); VisualWord * vw = new VisualWord(*iter, d);
if(vw) if(vw)
{ {
@@ -3675,7 +3678,7 @@ void DBDriverSqlite3::loadWordsQuery(const std::set<int> & wordIds, std::list<Vi
rc = sqlite3_finalize(ppStmt); rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str()); UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
ULOGGER_DEBUG("Time=%fs", timer.ticks()); UDEBUG("Time=%fs (%d words, %lu MB)", timer.ticks(), (int)vws.size(), dRealSizeTotal/1000000);
if(wordIds.size() != loaded.size()) if(wordIds.size() != loaded.size())
{ {

View File

@@ -511,7 +511,7 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION <= 3) || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION < 4 || (CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION<11))) #if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION <= 3) || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION < 4 || (CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION<11)))
#ifndef RTABMAP_NONFREE #ifndef RTABMAP_NONFREE
if(type == Feature2D::kFeatureSurf || type == Feature2D::kFeatureSift) if(type == Feature2D::kFeatureSurf || type == Feature2D::kFeatureSift || type == Feature2D::kFeatureSurfFreak)
{ {
#if CV_MAJOR_VERSION < 3 #if CV_MAJOR_VERSION < 3
UWARN("SURF and SIFT features cannot be used because OpenCV was not built with nonfree module. GFTT/ORB is used instead."); UWARN("SURF and SIFT features cannot be used because OpenCV was not built with nonfree module. GFTT/ORB is used instead.");
@@ -524,7 +524,8 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
if(type == Feature2D::kFeatureFastBrief || if(type == Feature2D::kFeatureFastBrief ||
type == Feature2D::kFeatureFastFreak || type == Feature2D::kFeatureFastFreak ||
type == Feature2D::kFeatureGfttBrief || type == Feature2D::kFeatureGfttBrief ||
type == Feature2D::kFeatureGfttFreak) type == Feature2D::kFeatureGfttFreak ||
type == Feature2D::kFeatureSurfFreak)
{ {
UWARN("BRIEF and FREAK features cannot be used because OpenCV was not built with xfeatures2d module. GFTT/ORB is used instead."); UWARN("BRIEF and FREAK features cannot be used because OpenCV was not built with xfeatures2d module. GFTT/ORB is used instead.");
type = Feature2D::kFeatureGfttOrb; type = Feature2D::kFeatureGfttOrb;
@@ -535,7 +536,7 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
#else // >= 4.4.0 >= 3.4.11 #else // >= 4.4.0 >= 3.4.11
#ifndef RTABMAP_NONFREE #ifndef RTABMAP_NONFREE
if(type == Feature2D::kFeatureSurf) if(type == Feature2D::kFeatureSurf || type == Feature2D::kFeatureSurfFreak)
{ {
UWARN("SURF features cannot be used because OpenCV was not built with nonfree module. SIFT is used instead."); UWARN("SURF features cannot be used because OpenCV was not built with nonfree module. SIFT is used instead.");
type = Feature2D::kFeatureSift; type = Feature2D::kFeatureSift;
@@ -614,6 +615,9 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
feature2D = new SuperPointTorch(parameters); feature2D = new SuperPointTorch(parameters);
break; break;
#endif #endif
case Feature2D::kFeatureSurfFreak:
feature2D = new SURF_FREAK(parameters);
break;
#ifdef RTABMAP_NONFREE #ifdef RTABMAP_NONFREE
default: default:
feature2D = new SURF(parameters); feature2D = new SURF(parameters);
@@ -1724,6 +1728,59 @@ cv::Mat GFTT_FREAK::generateDescriptorsImpl(const cv::Mat & image, std::vector<c
return descriptors; return descriptors;
} }
//////////////////////////
//SURF-FREAK
//////////////////////////
SURF_FREAK::SURF_FREAK(const ParametersMap & parameters) :
SURF(parameters),
orientationNormalized_(Parameters::defaultFREAKOrientationNormalized()),
scaleNormalized_(Parameters::defaultFREAKScaleNormalized()),
patternScale_(Parameters::defaultFREAKPatternScale()),
nOctaves_(Parameters::defaultFREAKNOctaves())
{
parseParameters(parameters);
}
SURF_FREAK::~SURF_FREAK()
{
}
void SURF_FREAK::parseParameters(const ParametersMap & parameters)
{
SURF::parseParameters(parameters);
Parameters::parse(parameters, Parameters::kFREAKOrientationNormalized(), orientationNormalized_);
Parameters::parse(parameters, Parameters::kFREAKScaleNormalized(), scaleNormalized_);
Parameters::parse(parameters, Parameters::kFREAKPatternScale(), patternScale_);
Parameters::parse(parameters, Parameters::kFREAKNOctaves(), nOctaves_);
#if CV_MAJOR_VERSION < 3
_freak = cv::Ptr<CV_FREAK>(new CV_FREAK(orientationNormalized_, scaleNormalized_, patternScale_, nOctaves_));
#else
#ifdef HAVE_OPENCV_XFEATURES2D
_freak = CV_FREAK::create(orientationNormalized_, scaleNormalized_, patternScale_, nOctaves_);
#else
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so Freak cannot be used!");
#endif
#endif
}
cv::Mat SURF_FREAK::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
{
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
cv::Mat descriptors;
#if CV_MAJOR_VERSION < 3
_freak->compute(image, keypoints, descriptors);
#else
#ifdef HAVE_OPENCV_XFEATURES2D
_freak->compute(image, keypoints, descriptors);
#else
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so Freak cannot be used!");
#endif
#endif
return descriptors;
}
////////////////////////// //////////////////////////
//GFTT-ORB //GFTT-ORB
////////////////////////// //////////////////////////

View File

@@ -1131,7 +1131,7 @@ void Memory::moveSignatureToWMFromSTM(int id, int * reducedTo)
} }
} }
this->moveToTrash(s, _notLinkedNodesKeptInDb); this->moveToTrash(s, false);
s = 0; s = 0;
} }
} }
@@ -2368,7 +2368,7 @@ void Memory::moveToTrash(Signature * s, bool keepLinkedToGraph, std::list<int> *
} }
s->removeLinks(true); // remove all links, but keep self referring link s->removeLinks(true); // remove all links, but keep self referring link
s->removeLandmarks(); // remove all landmarks s->removeLandmarks(); // remove all landmarks
s->setWeight(0); s->setWeight(-9); // invalid
s->setLabel(""); // reset label s->setLabel(""); // reset label
} }
else else

View File

@@ -213,6 +213,10 @@ void RegistrationVis::parseParameters(const ParametersMap & parameters)
{ {
uInsert(_featureParameters, ParametersPair(Parameters::kKpNndrRatio(), parameters.at(Parameters::kVisCorNNDR()))); uInsert(_featureParameters, ParametersPair(Parameters::kKpNndrRatio(), parameters.at(Parameters::kVisCorNNDR())));
} }
if(uContains(parameters, Parameters::kKpByteToFloat()))
{
uInsert(_featureParameters, ParametersPair(Parameters::kKpByteToFloat(), parameters.at(Parameters::kKpByteToFloat())));
}
if(uContains(parameters, Parameters::kVisFeatureType())) if(uContains(parameters, Parameters::kVisFeatureType()))
{ {
uInsert(_featureParameters, ParametersPair(Parameters::kKpDetectorStrategy(), parameters.at(Parameters::kVisFeatureType()))); uInsert(_featureParameters, ParametersPair(Parameters::kKpDetectorStrategy(), parameters.at(Parameters::kVisFeatureType())));

View File

@@ -432,6 +432,16 @@ void Rtabmap::close(bool databaseSaved, const std::string & ouputDatabasePath)
{ {
if(databaseSaved) if(databaseSaved)
{ {
if(_memory->isGraphReduced() && _memory->isIncremental())
{
// Force reducing graph, then remove filtered nodes from the optimized poses
std::map<int, int> reducedIds;
_memory->incrementMapId(&reducedIds);
for(std::map<int, int>::iterator iter=reducedIds.begin(); iter!=reducedIds.end(); ++iter)
{
_optimizedPoses.erase(iter->first);
}
}
_memory->saveOptimizedPoses(_optimizedPoses, _lastLocalizationPose); _memory->saveOptimizedPoses(_optimizedPoses, _lastLocalizationPose);
} }
_memory->close(databaseSaved, true, ouputDatabasePath); _memory->close(databaseSaved, true, ouputDatabasePath);

View File

@@ -65,6 +65,7 @@ VWDictionary::VWDictionary(const ParametersMap & parameters) :
_incrementalDictionary(Parameters::defaultKpIncrementalDictionary()), _incrementalDictionary(Parameters::defaultKpIncrementalDictionary()),
_incrementalFlann(Parameters::defaultKpIncrementalFlann()), _incrementalFlann(Parameters::defaultKpIncrementalFlann()),
_rebalancingFactor(Parameters::defaultKpFlannRebalancingFactor()), _rebalancingFactor(Parameters::defaultKpFlannRebalancingFactor()),
_byteToFloat(Parameters::defaultKpByteToFloat()),
_nndrRatio(Parameters::defaultKpNndrRatio()), _nndrRatio(Parameters::defaultKpNndrRatio()),
_newDictionaryPath(Parameters::defaultKpDictionaryPath()), _newDictionaryPath(Parameters::defaultKpDictionaryPath()),
_newWordsComparedTogether(Parameters::defaultKpNewWordsComparedTogether()), _newWordsComparedTogether(Parameters::defaultKpNewWordsComparedTogether()),
@@ -90,6 +91,8 @@ void VWDictionary::parseParameters(const ParametersMap & parameters)
Parameters::parse(parameters, Parameters::kKpNewWordsComparedTogether(), _newWordsComparedTogether); Parameters::parse(parameters, Parameters::kKpNewWordsComparedTogether(), _newWordsComparedTogether);
Parameters::parse(parameters, Parameters::kKpIncrementalFlann(), _incrementalFlann); Parameters::parse(parameters, Parameters::kKpIncrementalFlann(), _incrementalFlann);
Parameters::parse(parameters, Parameters::kKpFlannRebalancingFactor(), _rebalancingFactor); Parameters::parse(parameters, Parameters::kKpFlannRebalancingFactor(), _rebalancingFactor);
bool byteToFloat = _byteToFloat;
Parameters::parse(parameters, Parameters::kKpByteToFloat(), _byteToFloat);
UASSERT_MSG(_nndrRatio > 0.0f, uFormat("String=%s value=%f", uContains(parameters, Parameters::kKpNndrRatio())?parameters.at(Parameters::kKpNndrRatio()).c_str():"", _nndrRatio).c_str()); UASSERT_MSG(_nndrRatio > 0.0f, uFormat("String=%s value=%f", uContains(parameters, Parameters::kKpNndrRatio())?parameters.at(Parameters::kKpNndrRatio()).c_str():"", _nndrRatio).c_str());
@@ -104,10 +107,19 @@ void VWDictionary::parseParameters(const ParametersMap & parameters)
} }
// Verifying hypotheses strategy // Verifying hypotheses strategy
bool treeUpdated = false;
if((iter=parameters.find(Parameters::kKpNNStrategy())) != parameters.end()) if((iter=parameters.find(Parameters::kKpNNStrategy())) != parameters.end())
{ {
NNStrategy nnStrategy = (NNStrategy)std::atoi((*iter).second.c_str()); NNStrategy nnStrategy = (NNStrategy)std::atoi((*iter).second.c_str());
this->setNNStrategy(nnStrategy); treeUpdated = this->setNNStrategy(nnStrategy);
}
if(!treeUpdated && byteToFloat!=_byteToFloat && _strategy == kNNFlannKdTree)
{
UINFO("KDTree: Binary to Float conversion approach has changed, re-initialize kd-tree.");
_dataTree = cv::Mat();
_notIndexedWords = uKeysSet(_visualWords);
_removedIndexedWords.clear();
this->update();
} }
if(incrementalDictionary) if(incrementalDictionary)
@@ -277,7 +289,7 @@ void VWDictionary::setFixedDictionary(const std::string & dictionaryPath)
_newDictionaryPath = dictionaryPath; _newDictionaryPath = dictionaryPath;
} }
void VWDictionary::setNNStrategy(NNStrategy strategy) bool VWDictionary::setNNStrategy(NNStrategy strategy)
{ {
#if CV_MAJOR_VERSION < 3 #if CV_MAJOR_VERSION < 3
#ifdef HAVE_OPENCV_GPU #ifdef HAVE_OPENCV_GPU
@@ -319,11 +331,14 @@ void VWDictionary::setNNStrategy(NNStrategy strategy)
_strategy = strategy; _strategy = strategy;
if(update) if(update)
{ {
UINFO("Nearest neighbor strategy has changed, re-initialize search tree.");
_dataTree = cv::Mat(); _dataTree = cv::Mat();
_notIndexedWords = uKeysSet(_visualWords); _notIndexedWords = uKeysSet(_visualWords);
_removedIndexedWords.clear(); _removedIndexedWords.clear();
this->update(); this->update();
return true;
} }
return false;
} }
int VWDictionary::getLastIndexedWordId() const int VWDictionary::getLastIndexedWordId() const
@@ -348,59 +363,75 @@ unsigned int VWDictionary::getIndexMemoryUsed() const
return _flannIndex->memoryUsed(); return _flannIndex->memoryUsed();
} }
cv::Mat VWDictionary::convertBinTo32F(const cv::Mat & descriptorsIn) cv::Mat VWDictionary::convertBinTo32F(const cv::Mat & descriptorsIn, bool byteToFloat)
{ {
// Old approach if(byteToFloat)
//cv::Mat descriptorsOut;
//descriptorsIn.convertTo(descriptorsOut, CV_32F);
//return descriptorsOut;
// New approach
UASSERT(descriptorsIn.type() == CV_8UC1);
cv::Mat descriptorsOut(descriptorsIn.rows, descriptorsIn.cols*8, CV_32FC1);
for(int i=0; i<descriptorsIn.rows; ++i)
{ {
const unsigned char * ptrIn = descriptorsIn.ptr(i); // Old approach
float * ptrOut = descriptorsOut.ptr<float>(i); cv::Mat descriptorsOut;
for(int j=0; j<descriptorsIn.cols; ++j) descriptorsIn.convertTo(descriptorsOut, CV_32F);
{ return descriptorsOut;
int jo = j*8; }
ptrOut[jo] = (ptrIn[j] & 1) == 1?1.0f:0.0f; else
ptrOut[jo+1] = (ptrIn[j] & (1<<1)) != 0?1.0f:0.0f; {
ptrOut[jo+2] = (ptrIn[j] & (1<<2)) != 0?1.0f:0.0f; // New approach
ptrOut[jo+3] = (ptrIn[j] & (1<<3)) != 0?1.0f:0.0f; UASSERT(descriptorsIn.type() == CV_8UC1);
ptrOut[jo+4] = (ptrIn[j] & (1<<4)) != 0?1.0f:0.0f; cv::Mat descriptorsOut(descriptorsIn.rows, descriptorsIn.cols*8, CV_32FC1);
ptrOut[jo+5] = (ptrIn[j] & (1<<5)) != 0?1.0f:0.0f; for(int i=0; i<descriptorsIn.rows; ++i)
ptrOut[jo+6] = (ptrIn[j] & (1<<6)) != 0?1.0f:0.0f; {
ptrOut[jo+7] = (ptrIn[j] & (1<<7)) != 0?1.0f:0.0f; const unsigned char * ptrIn = descriptorsIn.ptr(i);
} float * ptrOut = descriptorsOut.ptr<float>(i);
for(int j=0; j<descriptorsIn.cols; ++j)
{
int jo = j*8;
ptrOut[jo] = (ptrIn[j] & 1) == 1?1.0f:0.0f;
ptrOut[jo+1] = (ptrIn[j] & (1<<1)) != 0?1.0f:0.0f;
ptrOut[jo+2] = (ptrIn[j] & (1<<2)) != 0?1.0f:0.0f;
ptrOut[jo+3] = (ptrIn[j] & (1<<3)) != 0?1.0f:0.0f;
ptrOut[jo+4] = (ptrIn[j] & (1<<4)) != 0?1.0f:0.0f;
ptrOut[jo+5] = (ptrIn[j] & (1<<5)) != 0?1.0f:0.0f;
ptrOut[jo+6] = (ptrIn[j] & (1<<6)) != 0?1.0f:0.0f;
ptrOut[jo+7] = (ptrIn[j] & (1<<7)) != 0?1.0f:0.0f;
}
}
return descriptorsOut;
} }
return descriptorsOut;
} }
cv::Mat VWDictionary::convert32FToBin(const cv::Mat & descriptorsIn) cv::Mat VWDictionary::convert32FToBin(const cv::Mat & descriptorsIn, bool byteToFloat)
{ {
UASSERT(descriptorsIn.type() == CV_32FC1 && descriptorsIn.cols % 8 == 0); if(byteToFloat)
cv::Mat descriptorsOut(descriptorsIn.rows, descriptorsIn.cols/8, CV_8UC1);
for(int i=0; i<descriptorsIn.rows; ++i)
{ {
const float * ptrIn = descriptorsIn.ptr<float>(i); // Old approach
unsigned char * ptrOut = descriptorsOut.ptr(i); cv::Mat descriptorsOut;
for(int j=0; j<descriptorsOut.cols; ++j) descriptorsIn.convertTo(descriptorsOut, CV_8UC1);
{ return descriptorsOut;
int jo = j*8; }
ptrOut[j] = else
(unsigned char)(ptrIn[jo] == 0?0:1) | {
(ptrIn[jo+1] == 0?0:(1<<1)) | // New approach
(ptrIn[jo+2] == 0?0:(1<<2)) | UASSERT(descriptorsIn.type() == CV_32FC1 && descriptorsIn.cols % 8 == 0);
(ptrIn[jo+3] == 0?0:(1<<3)) | cv::Mat descriptorsOut(descriptorsIn.rows, descriptorsIn.cols/8, CV_8UC1);
(ptrIn[jo+4] == 0?0:(1<<4)) | for(int i=0; i<descriptorsIn.rows; ++i)
(ptrIn[jo+5] == 0?0:(1<<5)) | {
(ptrIn[jo+6] == 0?0:(1<<6)) | const float * ptrIn = descriptorsIn.ptr<float>(i);
(ptrIn[jo+7] == 0?0:(1<<7)); unsigned char * ptrOut = descriptorsOut.ptr(i);
} for(int j=0; j<descriptorsOut.cols; ++j)
{
int jo = j*8;
ptrOut[j] =
(unsigned char)(ptrIn[jo] == 0?0:1) |
(ptrIn[jo+1] == 0?0:(1<<1)) |
(ptrIn[jo+2] == 0?0:(1<<2)) |
(ptrIn[jo+3] == 0?0:(1<<3)) |
(ptrIn[jo+4] == 0?0:(1<<4)) |
(ptrIn[jo+5] == 0?0:(1<<5)) |
(ptrIn[jo+6] == 0?0:(1<<6)) |
(ptrIn[jo+7] == 0?0:(1<<7));
}
}
return descriptorsOut;
} }
return descriptorsOut;
} }
void VWDictionary::update() void VWDictionary::update()
@@ -451,7 +482,7 @@ void VWDictionary::update()
useDistanceL1_ = true; useDistanceL1_ = true;
if(_strategy == kNNFlannKdTree) if(_strategy == kNNFlannKdTree)
{ {
descriptor = convertBinTo32F(w->getDescriptor()); descriptor = convertBinTo32F(w->getDescriptor(), _byteToFloat);
} }
else else
{ {
@@ -543,7 +574,10 @@ void VWDictionary::update()
if(_strategy == kNNFlannKdTree) if(_strategy == kNNFlannKdTree)
{ {
type = CV_32F; type = CV_32F;
dim *= 8; if(!_byteToFloat)
{
dim *= 8;
}
} }
else else
{ {
@@ -568,7 +602,7 @@ void VWDictionary::update()
{ {
if(_strategy == kNNFlannKdTree) if(_strategy == kNNFlannKdTree)
{ {
descriptor = convertBinTo32F(iter->second->getDescriptor()); descriptor = convertBinTo32F(iter->second->getDescriptor(), _byteToFloat);
} }
else else
{ {
@@ -736,7 +770,7 @@ std::list<int> VWDictionary::addNewWords(
useDistanceL1_ = true; useDistanceL1_ = true;
if(_strategy == kNNFlannKdTree) if(_strategy == kNNFlannKdTree)
{ {
descriptors = convertBinTo32F(descriptorsIn); descriptors = convertBinTo32F(descriptorsIn, _byteToFloat);
} }
else else
{ {
@@ -1074,7 +1108,7 @@ std::vector<int> VWDictionary::findNN(const cv::Mat & queryIn) const
{ {
if(_strategy == kNNFlannKdTree) if(_strategy == kNNFlannKdTree)
{ {
query = convertBinTo32F(queryIn); query = convertBinTo32F(queryIn, _byteToFloat);
} }
else else
{ {
@@ -1202,7 +1236,7 @@ std::vector<int> VWDictionary::findNN(const cv::Mat & queryIn) const
{ {
if(_strategy == kNNFlannKdTree) if(_strategy == kNNFlannKdTree)
{ {
descriptor = convertBinTo32F(vw->getDescriptor()); descriptor = convertBinTo32F(vw->getDescriptor(), _byteToFloat);
} }
else else
{ {

View File

@@ -194,7 +194,9 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
//SURF //SURF
#ifndef RTABMAP_NONFREE #ifndef RTABMAP_NONFREE
_ui->comboBox_detector_strategy->setItemData(0, 0, Qt::UserRole - 1); _ui->comboBox_detector_strategy->setItemData(0, 0, Qt::UserRole - 1);
_ui->comboBox_detector_strategy->setItemData(12, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(0, 0, Qt::UserRole - 1); _ui->vis_feature_detector->setItemData(0, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(12, 0, Qt::UserRole - 1);
#endif #endif
// SIFT // SIFT
@@ -210,10 +212,12 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->comboBox_detector_strategy->setItemData(4, 0, Qt::UserRole - 1); _ui->comboBox_detector_strategy->setItemData(4, 0, Qt::UserRole - 1);
_ui->comboBox_detector_strategy->setItemData(5, 0, Qt::UserRole - 1); _ui->comboBox_detector_strategy->setItemData(5, 0, Qt::UserRole - 1);
_ui->comboBox_detector_strategy->setItemData(6, 0, Qt::UserRole - 1); _ui->comboBox_detector_strategy->setItemData(6, 0, Qt::UserRole - 1);
_ui->comboBox_detector_strategy->setItemData(12, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(3, 0, Qt::UserRole - 1); _ui->vis_feature_detector->setItemData(3, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(4, 0, Qt::UserRole - 1); _ui->vis_feature_detector->setItemData(4, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(5, 0, Qt::UserRole - 1); _ui->vis_feature_detector->setItemData(5, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(6, 0, Qt::UserRole - 1); _ui->vis_feature_detector->setItemData(6, 0, Qt::UserRole - 1);
_ui->vis_feature_detector->setItemData(12, 0, Qt::UserRole - 1);
#endif #endif
#ifndef RTABMAP_ORB_OCTREE #ifndef RTABMAP_ORB_OCTREE
@@ -878,6 +882,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->comboBox_dictionary_strategy->setObjectName(Parameters::kKpNNStrategy().c_str()); _ui->comboBox_dictionary_strategy->setObjectName(Parameters::kKpNNStrategy().c_str());
_ui->checkBox_dictionary_incremental->setObjectName(Parameters::kKpIncrementalDictionary().c_str()); _ui->checkBox_dictionary_incremental->setObjectName(Parameters::kKpIncrementalDictionary().c_str());
_ui->checkBox_kp_incrementalFlann->setObjectName(Parameters::kKpIncrementalFlann().c_str()); _ui->checkBox_kp_incrementalFlann->setObjectName(Parameters::kKpIncrementalFlann().c_str());
_ui->checkBox_kp_byteToFloat->setObjectName(Parameters::kKpByteToFloat().c_str());
_ui->surf_doubleSpinBox_rebalancingFactor->setObjectName(Parameters::kKpFlannRebalancingFactor().c_str()); _ui->surf_doubleSpinBox_rebalancingFactor->setObjectName(Parameters::kKpFlannRebalancingFactor().c_str());
_ui->comboBox_detector_strategy->setObjectName(Parameters::kKpDetectorStrategy().c_str()); _ui->comboBox_detector_strategy->setObjectName(Parameters::kKpDetectorStrategy().c_str());
_ui->surf_doubleSpinBox_nndrRatio->setObjectName(Parameters::kKpNndrRatio().c_str()); _ui->surf_doubleSpinBox_nndrRatio->setObjectName(Parameters::kKpNndrRatio().c_str());
@@ -2962,7 +2967,7 @@ bool PreferencesDialog::validateForm()
#ifndef RTABMAP_NONFREE #ifndef RTABMAP_NONFREE
// verify that SURF/SIFT cannot be selected if not built with OpenCV nonfree module // verify that SURF/SIFT cannot be selected if not built with OpenCV nonfree module
// BOW dictionary type // BOW dictionary type
if(_ui->comboBox_detector_strategy->currentIndex() <= 1) if(_ui->comboBox_detector_strategy->currentIndex() <= 1 || _ui->comboBox_detector_strategy->currentIndex() == 12)
{ {
QMessageBox::warning(this, tr("Parameter warning"), QMessageBox::warning(this, tr("Parameter warning"),
tr("Selected feature type (SURF/SIFT) is not available. RTAB-Map is not built " tr("Selected feature type (SURF/SIFT) is not available. RTAB-Map is not built "
@@ -2970,7 +2975,7 @@ bool PreferencesDialog::validateForm()
_ui->comboBox_detector_strategy->setCurrentIndex(Feature2D::kFeatureOrb); _ui->comboBox_detector_strategy->setCurrentIndex(Feature2D::kFeatureOrb);
} }
// BOW Reextract features type // BOW Reextract features type
if(_ui->vis_feature_detector->currentIndex() <= 1) if(_ui->vis_feature_detector->currentIndex() <= 1 || _ui->vis_feature_detector->currentIndex() == 12)
{ {
QMessageBox::warning(this, tr("Parameter warning"), QMessageBox::warning(this, tr("Parameter warning"),
tr("Selected feature type (SURF/SIFT) is not available. RTAB-Map is not built " tr("Selected feature type (SURF/SIFT) is not available. RTAB-Map is not built "
@@ -2983,7 +2988,7 @@ bool PreferencesDialog::validateForm()
#ifndef RTABMAP_NONFREE #ifndef RTABMAP_NONFREE
// verify that SURF cannot be selected if not built with OpenCV nonfree module // verify that SURF cannot be selected if not built with OpenCV nonfree module
// BOW dictionary type // BOW dictionary type
if(_ui->comboBox_detector_strategy->currentIndex() < 1) if(_ui->comboBox_detector_strategy->currentIndex() < 1 || _ui->comboBox_detector_strategy->currentIndex() == 12)
{ {
QMessageBox::warning(this, tr("Parameter warning"), QMessageBox::warning(this, tr("Parameter warning"),
tr("Selected feature type (SURF) is not available. RTAB-Map is not built " tr("Selected feature type (SURF) is not available. RTAB-Map is not built "
@@ -2991,7 +2996,7 @@ bool PreferencesDialog::validateForm()
_ui->comboBox_detector_strategy->setCurrentIndex(Feature2D::kFeatureSift); _ui->comboBox_detector_strategy->setCurrentIndex(Feature2D::kFeatureSift);
} }
// BOW Reextract features type // BOW Reextract features type
if(_ui->vis_feature_detector->currentIndex() < 1) if(_ui->vis_feature_detector->currentIndex() < 1 || _ui->vis_feature_detector->currentIndex() == 12)
{ {
QMessageBox::warning(this, tr("Parameter warning"), QMessageBox::warning(this, tr("Parameter warning"),
tr("Selected feature type (SURF) is not available. RTAB-Map is not built " tr("Selected feature type (SURF) is not available. RTAB-Map is not built "

View File

@@ -63,7 +63,7 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>-366</y> <y>-1179</y>
<width>686</width> <width>686</width>
<height>3236</height> <height>3236</height>
</rect> </rect>
@@ -95,7 +95,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>5</number> <number>21</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1"> <layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
@@ -8964,6 +8964,11 @@ generate the number of words requested.</string>
<string>SuperPoint Torch</string> <string>SuperPoint Torch</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>SURF+FREAK</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="7" column="0">
@@ -9566,7 +9571,7 @@ When set to false, no new words are added to dictionary, so no more updates are
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="2"> <item row="8" column="2">
<widget class="QLabel" name="label_260"> <widget class="QLabel" name="label_260">
<property name="text"> <property name="text">
<string>When using a FLANN-based nearest neighbor strategy, add/remove points to its index without always rebuilding the index (the index is built only when the dictionary increases of the factor below in size).</string> <string>When using a FLANN-based nearest neighbor strategy, add/remove points to its index without always rebuilding the index (the index is built only when the dictionary increases of the factor below in size).</string>
@@ -9579,7 +9584,7 @@ When set to false, no new words are added to dictionary, so no more updates are
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0"> <item row="8" column="0">
<widget class="QCheckBox" name="checkBox_kp_incrementalFlann"> <widget class="QCheckBox" name="checkBox_kp_incrementalFlann">
<property name="text"> <property name="text">
<string/> <string/>
@@ -9589,7 +9594,7 @@ When set to false, no new words are added to dictionary, so no more updates are
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="2"> <item row="9" column="2">
<widget class="QLabel" name="label_451"> <widget class="QLabel" name="label_451">
<property name="text"> <property name="text">
<string>Factor used when rebuilding the incremental FLANN index. Set 1 to disable.</string> <string>Factor used when rebuilding the incremental FLANN index. Set 1 to disable.</string>
@@ -9602,7 +9607,7 @@ When set to false, no new words are added to dictionary, so no more updates are
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="0"> <item row="9" column="0">
<widget class="QDoubleSpinBox" name="surf_doubleSpinBox_rebalancingFactor"> <widget class="QDoubleSpinBox" name="surf_doubleSpinBox_rebalancingFactor">
<property name="decimals"> <property name="decimals">
<number>1</number> <number>1</number>
@@ -9621,6 +9626,29 @@ When set to false, no new words are added to dictionary, so no more updates are
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="2">
<widget class="QLabel" name="label_556">
<property name="text">
<string>For FLANN KdTree, binary descriptors are converted to float by converting each byte to float instead of converting each bit to float. When converting bytes instead of bits, less memory is used and search is faster at the cost of slightly less accurate matching.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="checkBox_kp_byteToFloat">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@@ -18216,6 +18244,11 @@ Lower the ratio -&gt; higher the precision.</string>
<string>SuperPoint Torch</string> <string>SuperPoint Torch</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>SURF+FREAK</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="3" column="0">

View File

@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/DBDriver.h> #include <rtabmap/core/DBDriver.h>
#include <rtabmap/utilite/UDirectory.h> #include <rtabmap/utilite/UDirectory.h>
#include "rtabmap/utilite/UFile.h" #include "rtabmap/utilite/UFile.h"
#include "rtabmap/utilite/UStl.h"
using namespace rtabmap; using namespace rtabmap;
@@ -229,7 +230,7 @@ int main(int argc, char * argv[])
driver->getAllNodeIds(ids); driver->getAllNodeIds(ids);
Transform lastLocalization; Transform lastLocalization;
std::map<int, Transform> optimizedPoses = driver->loadOptimizedPoses(&lastLocalization); std::map<int, Transform> optimizedPoses = driver->loadOptimizedPoses(&lastLocalization);
std::set<int> mapsLinkedToLastGraph; std::multimap<int, int> mapIdsLinkedToLastGraph;
int lastMapId=0; int lastMapId=0;
double previousStamp = 0.0f; double previousStamp = 0.0f;
Transform previousPose; Transform previousPose;
@@ -265,7 +266,7 @@ int main(int argc, char * argv[])
} }
if(optimizedPoses.find(id) != optimizedPoses.end()) if(optimizedPoses.find(id) != optimizedPoses.end())
{ {
mapsLinkedToLastGraph.insert(mapId); mapIdsLinkedToLastGraph.insert(std::make_pair(mapId, id));
} }
if(iter!=ids.begin()) if(iter!=ids.begin())
{ {
@@ -318,13 +319,14 @@ int main(int argc, char * argv[])
} }
std::stringstream sessionsInOptGraphStr; std::stringstream sessionsInOptGraphStr;
for(std::set<int>::iterator iter=mapsLinkedToLastGraph.begin(); iter!=mapsLinkedToLastGraph.end(); ++iter) std::list<int> mapsLinkedToLastGraph = uUniqueKeys(mapIdsLinkedToLastGraph);
for(std::list<int>::iterator iter=mapsLinkedToLastGraph.begin(); iter!=mapsLinkedToLastGraph.end(); ++iter)
{ {
if(iter!=mapsLinkedToLastGraph.begin()) if(iter!=mapsLinkedToLastGraph.begin())
{ {
sessionsInOptGraphStr << ", "; sessionsInOptGraphStr << ", ";
} }
sessionsInOptGraphStr << *iter; sessionsInOptGraphStr << *iter << "(" << mapIdsLinkedToLastGraph.count(*iter) << ")";
} }
std::cout << (uFormat("%s%fs\n", pad("Total time:").c_str(), infoTotalTime)); std::cout << (uFormat("%s%fs\n", pad("Total time:").c_str(), infoTotalTime));