mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-09 13:00:19 +08:00
VWDictionary: changed miniflann to flann directly so version 1.8 can be used. Added parameter "Kp/IncrementalFlann"
This commit is contained in:
+4
-1
@@ -132,8 +132,11 @@ option(WITH_GTSAM "Include GTSAM support" ON)
|
||||
option(WITH_CVSBA "Include cvsba support" ON)
|
||||
option(WITH_FLYCAPTURE2 "Include FlyCapture2/Triclops support" ON)
|
||||
|
||||
FIND_PACKAGE(FLANN 1.8)
|
||||
SET(FLANN18_FOUND ${FLANN_FOUND})
|
||||
|
||||
FIND_PACKAGE(OpenCV REQUIRED)
|
||||
FIND_PACKAGE(PCL 1.7 REQUIRED)
|
||||
FIND_PACKAGE(PCL 1.7 REQUIRED) # Will find FLANN too
|
||||
FIND_PACKAGE(ZLIB REQUIRED)
|
||||
|
||||
IF(WITH_QT)
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
###############################################################################
|
||||
# Find FLANN
|
||||
#
|
||||
# This sets the following variables:
|
||||
# FLANN_FOUND - True if FLANN was found.
|
||||
# FLANN_INCLUDE_DIRS - Directories containing the FLANN include files.
|
||||
# FLANN_LIBRARIES - Libraries needed to use FLANN.
|
||||
# FLANN_DEFINITIONS - Compiler flags for FLANN.
|
||||
# If FLANN_USE_STATIC is specified and then look for static libraries ONLY else
|
||||
# look for shared ones
|
||||
#
|
||||
# Original from https://github.com/PointCloudLibrary/pcl/blob/master/cmake/Modules/FindFLANN.cmake
|
||||
#
|
||||
|
||||
if(FLANN_USE_STATIC)
|
||||
set(FLANN_RELEASE_NAME flann_cpp_s)
|
||||
set(FLANN_DEBUG_NAME flann_cpp_s-gd)
|
||||
else(FLANN_USE_STATIC)
|
||||
set(FLANN_RELEASE_NAME flann_cpp)
|
||||
set(FLANN_DEBUG_NAME flann_cpp-gd)
|
||||
endif(FLANN_USE_STATIC)
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
if (FLANN_FIND_VERSION)
|
||||
pkg_check_modules(PC_FLANN flann>=${FLANN_FIND_VERSION})
|
||||
else(FLANN_FIND_VERSION)
|
||||
pkg_check_modules(PC_FLANN flann)
|
||||
endif(FLANN_FIND_VERSION)
|
||||
|
||||
set(FLANN_DEFINITIONS ${PC_FLANN_CFLAGS_OTHER})
|
||||
|
||||
find_path(FLANN_INCLUDE_DIR flann/flann.hpp
|
||||
HINTS ${PC_FLANN_INCLUDEDIR} ${PC_FLANN_INCLUDE_DIRS} "${FLANN_ROOT}" "$ENV{FLANN_ROOT}"
|
||||
PATHS "$ENV{PROGRAMFILES}/Flann" "$ENV{PROGRAMW6432}/Flann"
|
||||
PATH_SUFFIXES include)
|
||||
|
||||
find_library(FLANN_LIBRARY
|
||||
NAMES ${FLANN_RELEASE_NAME}
|
||||
HINTS ${PC_FLANN_LIBDIR} ${PC_FLANN_LIBRARY_DIRS} "${FLANN_ROOT}" "$ENV{FLANN_ROOT}"
|
||||
PATHS "$ENV{PROGRAMFILES}/Flann" "$ENV{PROGRAMW6432}/Flann"
|
||||
PATH_SUFFIXES lib)
|
||||
|
||||
find_library(FLANN_LIBRARY_DEBUG
|
||||
NAMES ${FLANN_DEBUG_NAME} ${FLANN_RELEASE_NAME}
|
||||
HINTS ${PC_FLANN_LIBDIR} ${PC_FLANN_LIBRARY_DIRS} "${FLANN_ROOT}" "$ENV{FLANN_ROOT}"
|
||||
PATHS "$ENV{PROGRAMFILES}/Flann" "$ENV{PROGRAMW6432}/Flann"
|
||||
PATH_SUFFIXES lib)
|
||||
|
||||
if(NOT FLANN_LIBRARY_DEBUG)
|
||||
set(FLANN_LIBRARY_DEBUG ${FLANN_LIBRARY})
|
||||
endif(NOT FLANN_LIBRARY_DEBUG)
|
||||
|
||||
set(FLANN_INCLUDE_DIRS ${FLANN_INCLUDE_DIR})
|
||||
set(FLANN_LIBRARIES optimized ${FLANN_LIBRARY} debug ${FLANN_LIBRARY_DEBUG})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(FLANN DEFAULT_MSG FLANN_LIBRARY FLANN_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(FLANN_LIBRARY FLANN_LIBRARY_DEBUG FLANN_INCLUDE_DIR)
|
||||
|
||||
if(FLANN_FOUND)
|
||||
message(STATUS "FLANN found (include: ${FLANN_INCLUDE_DIRS}, lib: ${FLANN_LIBRARIES})")
|
||||
if(FLANN_USE_STATIC)
|
||||
add_definitions(-DFLANN_STATIC)
|
||||
endif(FLANN_USE_STATIC)
|
||||
endif(FLANN_FOUND)
|
||||
@@ -205,6 +205,7 @@ class RTABMAP_EXP Parameters
|
||||
// KeypointMemory (Keypoint-based)
|
||||
RTABMAP_PARAM_COND(Kp, NNStrategy, int, RTABMAP_NONFREE, 1, 3, "kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4");
|
||||
RTABMAP_PARAM(Kp, IncrementalDictionary, bool, true, "");
|
||||
RTABMAP_PARAM(Kp, IncrementalFlann, bool, false, "When using FLANN based strategy, add/remove points to its index without always rebuilding the index (the index is built only when the dictionary doubles in size).");
|
||||
RTABMAP_PARAM(Kp, MaxDepth, float, 0.0, "Filter extracted keypoints by depth (0=inf)");
|
||||
RTABMAP_PARAM(Kp, WordsPerImage, int, 400, "");
|
||||
RTABMAP_PARAM(Kp, BadSignRatio, float, 0.2, "Bad signature ratio (less than Ratio x AverageWordsPerImage = bad).");
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace rtabmap
|
||||
|
||||
class DBDriver;
|
||||
class VisualWord;
|
||||
class FlannIndex;
|
||||
|
||||
class RTABMAP_EXP VWDictionary
|
||||
{
|
||||
@@ -97,14 +98,16 @@ protected:
|
||||
|
||||
private:
|
||||
bool _incrementalDictionary;
|
||||
bool _incrementalFlann;
|
||||
float _nndrRatio;
|
||||
std::string _dictionaryPath; // a pre-computed dictionary (.txt)
|
||||
bool _newWordsComparedTogether;
|
||||
int _lastWordId;
|
||||
cv::flann::Index * _flannIndex;
|
||||
FlannIndex * _flannIndex;
|
||||
cv::Mat _dataTree;
|
||||
NNStrategy _strategy;
|
||||
std::map<int ,int> _mapIndexId;
|
||||
std::map<int ,int> _mapIdIndex;
|
||||
std::map<int, VisualWord*> _unusedWords; //<id,VisualWord*>, note that these words stay in _visualWords
|
||||
std::set<int> _notIndexedWords; // Words that are not indexed in the dictionary
|
||||
std::set<int> _removedIndexedWords; // Words not anymore in the dictionary but still indexed in the dictionary
|
||||
|
||||
@@ -76,6 +76,10 @@ SET(LIBRARIES
|
||||
${ZLIB_LIBRARIES}
|
||||
)
|
||||
|
||||
IF(FLANN18_FOUND)
|
||||
ADD_DEFINITIONS("-DWITH_FLANN18")
|
||||
ENDIF(FLANN18_FOUND)
|
||||
|
||||
IF(Freenect_FOUND)
|
||||
ADD_DEFINITIONS("-DWITH_FREENECT")
|
||||
IF(Freenect_DASH_INCLUDES)
|
||||
|
||||
+288
-66
@@ -35,6 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "rtabmap/utilite/UtiLite.h"
|
||||
|
||||
#include <opencv2/opencv_modules.hpp>
|
||||
|
||||
#if CV_MAJOR_VERSION < 3
|
||||
#include <opencv2/gpu/gpu.hpp>
|
||||
#else
|
||||
@@ -44,23 +45,160 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <flann/flann.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
class FlannIndex
|
||||
{
|
||||
public:
|
||||
FlannIndex():
|
||||
index_(0),
|
||||
binaryType_(false)
|
||||
{
|
||||
}
|
||||
virtual ~FlannIndex()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if(index_)
|
||||
{
|
||||
if(binaryType_)
|
||||
{
|
||||
delete (flann::Index<flann::Hamming<unsigned char> >*)index_;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
delete (flann::Index<flann::L2<float> >*)index_;
|
||||
}
|
||||
index_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void build(
|
||||
const cv::Mat & features,
|
||||
const flann::IndexParams& params,
|
||||
bool binaryType)
|
||||
{
|
||||
this->release();
|
||||
UASSERT(index_ == 0);
|
||||
binaryType_ = binaryType;
|
||||
|
||||
if(binaryType)
|
||||
{
|
||||
flann::Matrix<unsigned char> dataset(features.data, features.rows, features.cols);
|
||||
index_ = new flann::Index<flann::Hamming<unsigned char> >(dataset, params);
|
||||
((flann::Index<flann::Hamming<unsigned char> >*)index_)->buildIndex();
|
||||
}
|
||||
else
|
||||
{
|
||||
flann::Matrix<float> dataset((float*)features.data, features.rows, features.cols);
|
||||
index_ = new flann::Index<flann::L2<float> >(dataset, params);
|
||||
((flann::Index<flann::L2<float> >*)index_)->buildIndex();
|
||||
}
|
||||
}
|
||||
|
||||
bool isIncremental()
|
||||
{
|
||||
#ifdef WITH_FLANN18
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void addPoints(const cv::Mat & features)
|
||||
{
|
||||
#ifdef WITH_FLANN18
|
||||
if(binaryType_)
|
||||
{
|
||||
flann::Matrix<unsigned char> dataset(features.data, features.rows, features.cols);
|
||||
((flann::Index<flann::Hamming<unsigned char> >*)index_)->addPoints(dataset);
|
||||
}
|
||||
else
|
||||
{
|
||||
flann::Matrix<float> dataset((float*)features.data, features.rows, features.cols);
|
||||
((flann::Index<flann::L2<float> >*)index_)->addPoints(dataset);
|
||||
}
|
||||
#else
|
||||
UFATAL("Not built with FLANN 1.8! Only when isIncremental() returns true that you can call this method.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void removePoint(unsigned int index)
|
||||
{
|
||||
#ifdef WITH_FLANN18
|
||||
if(binaryType_)
|
||||
{
|
||||
((flann::Index<flann::Hamming<unsigned char> >*)index_)->removePoint(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
((flann::Index<flann::L2<float> >*)index_)->removePoint(index);
|
||||
}
|
||||
#else
|
||||
UFATAL("Not built with FLANN 1.8! Only when isIncremental() returns true that you can call this method.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void knnSearch(
|
||||
const cv::Mat & query,
|
||||
cv::Mat & indices,
|
||||
cv::Mat & dists,
|
||||
int knn,
|
||||
const flann::SearchParams& params=flann::SearchParams())
|
||||
{
|
||||
if(!index_)
|
||||
{
|
||||
UERROR("Flann index not yet created!");
|
||||
return;
|
||||
}
|
||||
indices.create(query.rows, knn, CV_32S);
|
||||
dists.create(query.rows, knn, binaryType_?CV_32S:CV_32F);
|
||||
|
||||
cv::flann::IndexParams i;
|
||||
|
||||
flann::Matrix<int> indicesF((int*)indices.data, indices.rows, indices.cols);
|
||||
|
||||
if(binaryType_)
|
||||
{
|
||||
flann::Matrix<unsigned int> distsF((unsigned int*)dists.data, dists.rows, dists.cols);
|
||||
flann::Matrix<unsigned char> queryF(query.data, query.rows, query.cols);
|
||||
((flann::Index<flann::Hamming<unsigned char> >*)index_)->knnSearch(queryF, indicesF, distsF, knn, params);
|
||||
}
|
||||
else
|
||||
{
|
||||
flann::Matrix<float> distsF((float*)dists.data, dists.rows, dists.cols);
|
||||
flann::Matrix<float> queryF((float*)query.data, query.rows, query.cols);
|
||||
((flann::Index<flann::L2<float> >*)index_)->knnSearch(queryF, indicesF, distsF, knn, params);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void * index_;
|
||||
bool binaryType_;
|
||||
};
|
||||
|
||||
const int VWDictionary::ID_START = 1;
|
||||
const int VWDictionary::ID_INVALID = 0;
|
||||
|
||||
VWDictionary::VWDictionary(const ParametersMap & parameters) :
|
||||
_totalActiveReferences(0),
|
||||
_incrementalDictionary(Parameters::defaultKpIncrementalDictionary()),
|
||||
_incrementalFlann(Parameters::defaultKpIncrementalFlann()),
|
||||
_nndrRatio(Parameters::defaultKpNndrRatio()),
|
||||
_dictionaryPath(Parameters::defaultKpDictionaryPath()),
|
||||
_newWordsComparedTogether(Parameters::defaultKpNewWordsComparedTogether()),
|
||||
_lastWordId(0),
|
||||
_flannIndex(new cv::flann::Index()),
|
||||
_flannIndex(new FlannIndex()),
|
||||
_strategy(kNNBruteForce)
|
||||
{
|
||||
this->setNNStrategy((NNStrategy)Parameters::defaultKpNNStrategy());
|
||||
@@ -78,6 +216,13 @@ void VWDictionary::parseParameters(const ParametersMap & parameters)
|
||||
ParametersMap::const_iterator iter;
|
||||
Parameters::parse(parameters, Parameters::kKpNndrRatio(), _nndrRatio);
|
||||
Parameters::parse(parameters, Parameters::kKpNewWordsComparedTogether(), _newWordsComparedTogether);
|
||||
Parameters::parse(parameters, Parameters::kKpIncrementalFlann(), _incrementalFlann);
|
||||
|
||||
if(_incrementalFlann && !_flannIndex->isIncremental())
|
||||
{
|
||||
UERROR("TRying to set \"KpIncrementalFlann\"=true but RTAB-Map is not built with FLANN>=1.8. Setting to false.");
|
||||
_incrementalFlann = false;
|
||||
}
|
||||
|
||||
UASSERT_MSG(_nndrRatio > 0.0f, uFormat("String=%s value=%f", uContains(parameters, Parameters::kKpNndrRatio())?parameters.at(Parameters::kKpNndrRatio()).c_str():"", _nndrRatio).c_str());
|
||||
|
||||
@@ -257,7 +402,15 @@ void VWDictionary::setNNStrategy(NNStrategy strategy)
|
||||
}
|
||||
else
|
||||
{
|
||||
bool update = _strategy != strategy;
|
||||
_strategy = strategy;
|
||||
if(update)
|
||||
{
|
||||
_dataTree = cv::Mat();
|
||||
_notIndexedWords = uKeysSet(_visualWords);
|
||||
_removedIndexedWords.clear();
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,55 +440,106 @@ void VWDictionary::update()
|
||||
|
||||
if(_notIndexedWords.size() || _visualWords.size() == 0 || _removedIndexedWords.size())
|
||||
{
|
||||
_mapIndexId.clear();
|
||||
int oldSize = _dataTree.rows;
|
||||
_dataTree = cv::Mat();
|
||||
_flannIndex->release();
|
||||
|
||||
if(_visualWords.size())
|
||||
if(_incrementalFlann &&
|
||||
_flannIndex->isIncremental() &&
|
||||
_strategy < kNNBruteForce &&
|
||||
(_notIndexedWords.size() || _removedIndexedWords.size()) &&
|
||||
oldSize)
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
|
||||
int type = _visualWords.begin()->second->getDescriptor().type();
|
||||
int dim = _visualWords.begin()->second->getDescriptor().cols;
|
||||
|
||||
UASSERT(type == CV_32F || type == CV_8U);
|
||||
UASSERT(dim > 0);
|
||||
|
||||
// Create the data matrix
|
||||
_dataTree = cv::Mat(_visualWords.size(), dim, type); // SURF descriptors are CV_32F
|
||||
std::map<int, VisualWord*>::const_iterator iter = _visualWords.begin();
|
||||
for(unsigned int i=0; i < _visualWords.size(); ++i, ++iter)
|
||||
for(std::set<int>::iterator iter=_notIndexedWords.begin(); iter!=_notIndexedWords.end(); ++iter)
|
||||
{
|
||||
UASSERT(iter->second->getDescriptor().cols == dim);
|
||||
UASSERT(iter->second->getDescriptor().type() == type);
|
||||
|
||||
iter->second->getDescriptor().copyTo(_dataTree.row(i));
|
||||
_mapIndexId.insert(_mapIndexId.end(), std::pair<int, int>(i, iter->second->id()));
|
||||
VisualWord* w = uValue(_visualWords, *iter, (VisualWord*)0);
|
||||
UASSERT(w);
|
||||
UASSERT(w->getDescriptor().cols == _dataTree.cols);
|
||||
UASSERT(w->getDescriptor().type() == _dataTree.type());
|
||||
_dataTree.push_back(w->getDescriptor());
|
||||
_mapIndexId.insert(_mapIndexId.end(), std::pair<int, int>(_dataTree.rows-1, w->id()));
|
||||
std::pair<std::map<int, int>::iterator, bool> inserted = _mapIdIndex.insert(std::pair<int, int>(w->id(), _dataTree.rows-1));
|
||||
if(!inserted.second)
|
||||
{
|
||||
//update to new index
|
||||
inserted.first->second = _dataTree.rows-1;
|
||||
}
|
||||
_flannIndex->addPoints(w->getDescriptor());
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("_mapIndexId.size() = %d, words.size()=%d, _dim=%d",_mapIndexId.size(), _visualWords.size(), dim);
|
||||
ULOGGER_DEBUG("copying data = %f s", timer.ticks());
|
||||
|
||||
switch(_strategy)
|
||||
for(std::set<int>::iterator iter=_removedIndexedWords.begin(); iter!=_removedIndexedWords.end(); ++iter)
|
||||
{
|
||||
case kNNFlannNaive:
|
||||
_flannIndex->build(_dataTree, cv::flann::LinearIndexParams(), type == CV_32F?cvflann::FLANN_DIST_L2:cvflann::FLANN_DIST_HAMMING);
|
||||
break;
|
||||
case kNNFlannKdTree:
|
||||
UASSERT_MSG(type == CV_32F, "To use KdTree dictionary, float descriptors are required!");
|
||||
_flannIndex->build(_dataTree, cv::flann::KDTreeIndexParams(), cvflann::FLANN_DIST_L2);
|
||||
break;
|
||||
case kNNFlannLSH:
|
||||
UASSERT_MSG(type == CV_8U, "To use LSH dictionary, binary descriptors are required!");
|
||||
_flannIndex->build(_dataTree, cv::flann::LshIndexParams(12, 20, 2), cvflann::FLANN_DIST_HAMMING);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
UASSERT(uContains(_mapIdIndex, *iter));
|
||||
_flannIndex->removePoint(_mapIdIndex.at(*iter));
|
||||
}
|
||||
}
|
||||
else if(_strategy >= kNNBruteForce &&
|
||||
_notIndexedWords.size() &&
|
||||
_removedIndexedWords.size() == 0 &&
|
||||
oldSize)
|
||||
{
|
||||
//just add not indexed words
|
||||
for(std::set<int>::iterator iter=_notIndexedWords.begin(); iter!=_notIndexedWords.end(); ++iter)
|
||||
{
|
||||
VisualWord* w = uValue(_visualWords, *iter, (VisualWord*)0);
|
||||
UASSERT(w);
|
||||
UASSERT(w->getDescriptor().cols == _dataTree.cols);
|
||||
UASSERT(w->getDescriptor().type() == _dataTree.type());
|
||||
_dataTree.push_back(w->getDescriptor());
|
||||
_mapIndexId.insert(_mapIndexId.end(), std::pair<int, int>(_dataTree.rows-1, w->id()));
|
||||
std::pair<std::map<int, int>::iterator, bool> inserted = _mapIdIndex.insert(std::pair<int, int>(w->id(), _dataTree.rows-1));
|
||||
UASSERT(inserted.second);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_mapIndexId.clear();
|
||||
_mapIdIndex.clear();
|
||||
_dataTree = cv::Mat();
|
||||
_flannIndex->release();
|
||||
|
||||
ULOGGER_DEBUG("Time to create kd tree = %f s", timer.ticks());
|
||||
if(_visualWords.size())
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
|
||||
int type = _visualWords.begin()->second->getDescriptor().type();
|
||||
int dim = _visualWords.begin()->second->getDescriptor().cols;
|
||||
|
||||
UASSERT(type == CV_32F || type == CV_8U);
|
||||
UASSERT(dim > 0);
|
||||
|
||||
// Create the data matrix
|
||||
_dataTree = cv::Mat(_visualWords.size(), dim, type); // SURF descriptors are CV_32F
|
||||
std::map<int, VisualWord*>::const_iterator iter = _visualWords.begin();
|
||||
for(unsigned int i=0; i < _visualWords.size(); ++i, ++iter)
|
||||
{
|
||||
UASSERT(iter->second->getDescriptor().cols == dim);
|
||||
UASSERT(iter->second->getDescriptor().type() == type);
|
||||
|
||||
iter->second->getDescriptor().copyTo(_dataTree.row(i));
|
||||
_mapIndexId.insert(_mapIndexId.end(), std::pair<int, int>(i, iter->second->id()));
|
||||
_mapIdIndex.insert(_mapIdIndex.end(), std::pair<int, int>(iter->second->id(), i));
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("_mapIndexId.size() = %d, words.size()=%d, _dim=%d",_mapIndexId.size(), _visualWords.size(), dim);
|
||||
ULOGGER_DEBUG("copying data = %f s", timer.ticks());
|
||||
|
||||
switch(_strategy)
|
||||
{
|
||||
case kNNFlannNaive:
|
||||
_flannIndex->build(_dataTree, flann::LinearIndexParams(), type != CV_32F);
|
||||
break;
|
||||
case kNNFlannKdTree:
|
||||
UASSERT_MSG(type == CV_32F, "To use KdTree dictionary, float descriptors are required!");
|
||||
_flannIndex->build(_dataTree, flann::KDTreeIndexParams(), false);
|
||||
break;
|
||||
case kNNFlannLSH:
|
||||
UASSERT_MSG(type == CV_8U, "To use LSH dictionary, binary descriptors are required!");
|
||||
_flannIndex->build(_dataTree, flann::LshIndexParams(12, 20, 2), true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("Time to create kd tree = %f s", timer.ticks());
|
||||
}
|
||||
}
|
||||
UDEBUG("Dictionary updated! (size=%d->%d added=%d removed=%d)",
|
||||
oldSize, _dataTree.rows, _notIndexedWords.size(), _removedIndexedWords.size());
|
||||
@@ -370,6 +574,7 @@ void VWDictionary::clear()
|
||||
_lastWordId = 0;
|
||||
_dataTree = cv::Mat();
|
||||
_mapIndexId.clear();
|
||||
_mapIdIndex.clear();
|
||||
_unusedWords.clear();
|
||||
_flannIndex->release();
|
||||
}
|
||||
@@ -544,10 +749,15 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
{
|
||||
for(int j=0; j<dists.cols; ++j)
|
||||
{
|
||||
if(results.at<int>(i,j) >= 0)
|
||||
float d = dists.at<float>(i,j);
|
||||
int id = uValue(_mapIndexId, results.at<int>(i,j));
|
||||
if(d >= 0.0f && id > 0)
|
||||
{
|
||||
float d = dists.at<float>(i,j);
|
||||
fullResults.insert(std::pair<float, int>(d, uValue(_mapIndexId, results.at<int>(i,j))));
|
||||
std::multimap<float, int>::iterator iter = fullResults.insert(std::pair<float, int>(d, id));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -555,10 +765,15 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
{
|
||||
for(unsigned int j=0; j<matches.at(i).size(); ++j)
|
||||
{
|
||||
if(matches.at(i).at(j).trainIdx >= 0)
|
||||
float d = matches.at(i).at(j).distance;
|
||||
int id = uValue(_mapIndexId, matches.at(i).at(j).trainIdx);
|
||||
if(d >= 0.0f && id > 0)
|
||||
{
|
||||
float d = matches.at(i).at(j).distance;
|
||||
fullResults.insert(std::pair<float, int>(d, uValue(_mapIndexId, matches.at(i).at(j).trainIdx)));
|
||||
std::multimap<float, int>::iterator iter = fullResults.insert(std::pair<float, int>(d, id));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -566,8 +781,8 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
// Check if this descriptor matches with a word from the last signature (a word not already added to the tree)
|
||||
if(_newWordsComparedTogether && newWords.rows)
|
||||
{
|
||||
cv::flann::Index linearSeach;
|
||||
linearSeach.build(newWords, cv::flann::LinearIndexParams(), type == CV_32F?cvflann::FLANN_DIST_L2:cvflann::FLANN_DIST_HAMMING);
|
||||
FlannIndex linearSeach;
|
||||
linearSeach.build(newWords, flann::LinearIndexParams(), type != CV_32F);
|
||||
cv::Mat resultsLinear;
|
||||
cv::Mat distsLinear;
|
||||
linearSeach.knnSearch(descriptors.row(i), resultsLinear, distsLinear, newWords.rows>1?2:1);
|
||||
@@ -582,10 +797,15 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
{
|
||||
for(int j=0; j<resultsLinear.cols; ++j)
|
||||
{
|
||||
if(resultsLinear.at<int>(0,j) >= 0)
|
||||
float d = distsLinear.at<float>(0,j);
|
||||
if(d >= 0.0f && resultsLinear.at<int>(0,j) >= 0)
|
||||
{
|
||||
float d = distsLinear.at<float>(0,j);
|
||||
fullResults.insert(std::pair<float, int>(d, newWordsId[resultsLinear.at<int>(0,j)]));
|
||||
std::multimap<float, int>::iterator iter = fullResults.insert(std::pair<float, int>(d, newWordsId[resultsLinear.at<int>(0,j)]));
|
||||
UASSERT(iter->second > 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -637,7 +857,6 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
|
||||
this->addWordRef(fullResults.begin()->second, signatureId);
|
||||
wordIds.push_back(fullResults.begin()->second);
|
||||
UASSERT(fullResults.begin()->second>0);
|
||||
}
|
||||
}
|
||||
else if(fullResults.size())
|
||||
@@ -786,8 +1005,8 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws) const
|
||||
|
||||
// Find nearest neighbor
|
||||
ULOGGER_DEBUG("Searching in words not indexed...");
|
||||
cv::flann::Index linearSeach;
|
||||
linearSeach.build(dataNotIndexed, cv::flann::LinearIndexParams(), type == CV_32F?cvflann::FLANN_DIST_L2:cvflann::FLANN_DIST_HAMMING);
|
||||
FlannIndex linearSeach;
|
||||
linearSeach.build(dataNotIndexed, flann::LinearIndexParams(), type != CV_32F);
|
||||
linearSeach.knnSearch(query, resultsNotIndexed, distsNotIndexed, _notIndexedWords.size()>1?2:1);
|
||||
// In case of binary descriptors
|
||||
if(distsNotIndexed.type() == CV_32S)
|
||||
@@ -806,10 +1025,11 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws) const
|
||||
{
|
||||
for(int j=0; j<dists.cols; ++j)
|
||||
{
|
||||
if(results.at<int>(i,j) > 0)
|
||||
float d = dists.at<float>(i,j);
|
||||
int id = uValue(_mapIndexId, results.at<int>(i,j));
|
||||
if(d >= 0.0f && id > 0)
|
||||
{
|
||||
float d = dists.at<float>(i,j);
|
||||
fullResults.insert(std::pair<float, int>(d, uValue(_mapIndexId, results.at<int>(i,j))));
|
||||
fullResults.insert(std::pair<float, int>(d, id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -817,10 +1037,11 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws) const
|
||||
{
|
||||
for(unsigned int j=0; j<matches.at(i).size(); ++j)
|
||||
{
|
||||
if(matches.at(i).at(j).trainIdx > 0)
|
||||
float d = matches.at(i).at(j).distance;
|
||||
int id = uValue(_mapIndexId, matches.at(i).at(j).trainIdx);
|
||||
if(d >= 0.0f && id > 0)
|
||||
{
|
||||
float d = matches.at(i).at(j).distance;
|
||||
fullResults.insert(std::pair<float, int>(d, uValue(_mapIndexId, matches.at(i).at(j).trainIdx)));
|
||||
fullResults.insert(std::pair<float, int>(d, id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -828,10 +1049,11 @@ std::vector<int> VWDictionary::findNN(const std::list<VisualWord *> & vws) const
|
||||
// not indexed..
|
||||
for(int j=0; j<distsNotIndexed.cols; ++j)
|
||||
{
|
||||
if(resultsNotIndexed.at<int>(i,j) > 0)
|
||||
float d = distsNotIndexed.at<float>(i,j);
|
||||
if(d >= 0.0f && resultsNotIndexed.at<int>(i,j) > 0)
|
||||
{
|
||||
float d = distsNotIndexed.at<float>(i,j);
|
||||
fullResults.insert(std::pair<float, int>(d, uValue(mapIndexIdNotIndexed, resultsNotIndexed.at<int>(i,j))));
|
||||
std::multimap<float, int>::iterator iter = fullResults.insert(std::pair<float, int>(d, uValue(mapIndexIdNotIndexed, resultsNotIndexed.at<int>(i,j))));
|
||||
UASSERT(iter->second > 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <opencv2/core/version.hpp>
|
||||
#include <pcl/pcl_config.h>
|
||||
|
||||
#include <flann/config.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
AboutDialog::AboutDialog(QWidget * parent) :
|
||||
@@ -53,6 +55,7 @@ AboutDialog::AboutDialog(QWidget * parent) :
|
||||
#endif
|
||||
_ui->label_version->setText(version);
|
||||
_ui->label_opencv_version->setText(cv_version);
|
||||
_ui->label_flann_version->setText(FLANN_VERSION_);
|
||||
_ui->label_pcl_version->setText(PCL_VERSION_PRETTY);
|
||||
_ui->label_freenect->setText(CameraFreenect::available()?"Yes":"No");
|
||||
_ui->label_openni2->setText(CameraOpenNI2::available()?"Yes":"No");
|
||||
|
||||
@@ -121,6 +121,10 @@ INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
|
||||
|
||||
add_definitions(${PCL_DEFINITIONS})
|
||||
|
||||
IF(FLANN18_FOUND)
|
||||
ADD_DEFINITIONS("-DWITH_FLANN18")
|
||||
ENDIF(FLANN18_FOUND)
|
||||
|
||||
# create a library from the source files
|
||||
ADD_LIBRARY(rtabmap_gui ${SRC_FILES})
|
||||
# Linking with Qt libraries
|
||||
|
||||
@@ -490,6 +490,11 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
//Keypoint-based
|
||||
_ui->comboBox_dictionary_strategy->setObjectName(Parameters::kKpNNStrategy().c_str());
|
||||
_ui->checkBox_dictionary_incremental->setObjectName(Parameters::kKpIncrementalDictionary().c_str());
|
||||
_ui->checkBox_kp_incrementalFlann->setObjectName(Parameters::kKpIncrementalFlann().c_str());
|
||||
#ifndef WITH_FLANN18
|
||||
_ui->checkBox_kp_incrementalFlann->setEnabled(false);
|
||||
_ui->checkBox_kp_incrementalFlann->setChecked(false);
|
||||
#endif
|
||||
_ui->comboBox_detector_strategy->setObjectName(Parameters::kKpDetectorStrategy().c_str());
|
||||
_ui->surf_doubleSpinBox_nndrRatio->setObjectName(Parameters::kKpNndrRatio().c_str());
|
||||
_ui->surf_doubleSpinBox_maxDepth->setObjectName(Parameters::kKpMaxDepth().c_str());
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>824</width>
|
||||
<height>581</height>
|
||||
<width>831</width>
|
||||
<height>615</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -82,21 +82,31 @@ p, li { white-space: pre-wrap; }
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1">
|
||||
<item row="10" column="0">
|
||||
<item row="9" column="1">
|
||||
<widget class="QLabel" name="label_pcl_version">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>With Freenect :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>With OpenNI2 :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="0">
|
||||
<item row="14" column="0">
|
||||
<widget class="QLabel" name="label_16">
|
||||
<property name="text">
|
||||
<string>With stereo dc1394 :</string>
|
||||
@@ -202,24 +212,14 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QLabel" name="label_pcl_version">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="0">
|
||||
<item row="16" column="0">
|
||||
<widget class="QLabel" name="label_14">
|
||||
<property name="text">
|
||||
<string>With g2o :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<item row="11" column="1">
|
||||
<widget class="QLabel" name="label_freenect">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -229,7 +229,7 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="1">
|
||||
<item row="12" column="1">
|
||||
<widget class="QLabel" name="label_openni2">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -239,7 +239,7 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="15" column="1">
|
||||
<item row="16" column="1">
|
||||
<widget class="QLabel" name="label_g2o">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -249,21 +249,21 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<item row="13" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>With Freenect2 :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="0">
|
||||
<item row="15" column="0">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="text">
|
||||
<string>With stereo FlyCapture2 :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<item row="13" column="1">
|
||||
<widget class="QLabel" name="label_freenect2">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -273,7 +273,7 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<item row="14" column="1">
|
||||
<widget class="QLabel" name="label_dc1394">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -283,7 +283,7 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="14" column="1">
|
||||
<item row="15" column="1">
|
||||
<widget class="QLabel" name="label_flycapture2">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -293,14 +293,14 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="0">
|
||||
<item row="18" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>With cvsba :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="17" column="1">
|
||||
<item row="18" column="1">
|
||||
<widget class="QLabel" name="label_cvsba">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -310,14 +310,14 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="0">
|
||||
<item row="17" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>With GTSAM :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="16" column="1">
|
||||
<item row="17" column="1">
|
||||
<widget class="QLabel" name="label_gtsam">
|
||||
<property name="text">
|
||||
<string/>
|
||||
@@ -327,6 +327,23 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>FLANN version :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<widget class="QLabel" name="label_flann_version">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-509</y>
|
||||
<y>-349</y>
|
||||
<width>760</width>
|
||||
<height>1598</height>
|
||||
</rect>
|
||||
@@ -86,7 +86,7 @@
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>19</number>
|
||||
<number>9</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_22">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_29">
|
||||
@@ -4973,6 +4973,29 @@ When set to false, no new words are added to dictionary, so no more updates are
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<widget class="QLabel" name="label_260">
|
||||
<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 doubles in size).</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_incrementalFlann">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -736,4 +736,26 @@ inline bool uStrContains(const std::string & string, const std::string & substri
|
||||
return string.find(substring) != std::string::npos;
|
||||
}
|
||||
|
||||
inline int uCompareVersion(const std::string & version, int major, int minor=-1, int patch=-1)
|
||||
{
|
||||
std::vector<std::string> v = uListToVector(uSplit(version, '.'));
|
||||
if(v.size() == 3)
|
||||
{
|
||||
int vMajor = atoi(v[0].c_str());
|
||||
int vMinor = atoi(v[1].c_str());
|
||||
int vPatch = atoi(v[2].c_str());
|
||||
if(vMajor > major ||
|
||||
(vMajor == major && minor!=-1 && vMinor > minor) ||
|
||||
(vMajor == major && minor!=-1 && vMinor == minor && patch!=-1 && vPatch > patch))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if(vMajor == major && (minor == -1 || (vMinor == minor && (patch == -1 || vPatch == patch))))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* USTL_H */
|
||||
|
||||
Reference in New Issue
Block a user