mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 17:40:23 +08:00
Updated not incremental dictionary approach for save/reload (can set a database path as dictionary for convenience)
This commit is contained in:
@@ -155,7 +155,7 @@ public:
|
||||
void executeNoResult(const std::string & sql) const;
|
||||
|
||||
// Load objects
|
||||
void load(VWDictionary * dictionary) const;
|
||||
void load(VWDictionary * dictionary, bool lastStateOnly = true) const;
|
||||
void loadLastNodes(std::list<Signature *> & signatures) const;
|
||||
void loadSignatures(const std::list<int> & ids, std::list<Signature *> & signatures, std::set<int> * loadedFromTrash = 0);
|
||||
void loadWords(const std::set<int> & wordIds, std::list<VisualWord *> & vws);
|
||||
@@ -255,7 +255,7 @@ private:
|
||||
cv::Mat * textures) const = 0;
|
||||
|
||||
// Load objects
|
||||
virtual void loadQuery(VWDictionary * dictionary) const = 0;
|
||||
virtual void loadQuery(VWDictionary * dictionary, bool lastStateOnly = true) const = 0;
|
||||
virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const = 0;
|
||||
virtual void loadSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const = 0;
|
||||
virtual void loadWordsQuery(const std::set<int> & wordIds, std::list<VisualWord *> & vws) const = 0;
|
||||
|
||||
@@ -436,7 +436,7 @@ void DBDriver::saveOrUpdate(const std::vector<Signature *> & signatures)
|
||||
|
||||
void DBDriver::saveOrUpdate(const std::vector<VisualWord *> & words) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
ULOGGER_DEBUG("words.size=%d", (int)words.size());
|
||||
std::list<VisualWord *> toSave;
|
||||
std::list<VisualWord *> toUpdate;
|
||||
if(this->isConnected() && words.size())
|
||||
@@ -511,10 +511,10 @@ void DBDriver::updateDepthImage(int nodeId, const cv::Mat & image)
|
||||
_dbSafeAccessMutex.unlock();
|
||||
}
|
||||
|
||||
void DBDriver::load(VWDictionary * dictionary) const
|
||||
void DBDriver::load(VWDictionary * dictionary, bool lastStateOnly) const
|
||||
{
|
||||
_dbSafeAccessMutex.lock();
|
||||
this->loadQuery(dictionary);
|
||||
this->loadQuery(dictionary, lastStateOnly);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -3077,7 +3077,7 @@ void DBDriverSqlite3::loadLastNodesQuery(std::list<Signature *> & nodes) const
|
||||
}
|
||||
}
|
||||
|
||||
void DBDriverSqlite3::loadQuery(VWDictionary * dictionary) const
|
||||
void DBDriverSqlite3::loadQuery(VWDictionary * dictionary, bool lastStateOnly) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
if(_ppDb && dictionary)
|
||||
@@ -3087,26 +3087,25 @@ void DBDriverSqlite3::loadQuery(VWDictionary * dictionary) const
|
||||
timer.start();
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
std::string query;
|
||||
std::stringstream query;
|
||||
std::list<VisualWord *> visualWords;
|
||||
|
||||
// Get the visual words
|
||||
if(uStrNumCmp(_version, "0.11.11") >= 0)
|
||||
query << "SELECT id, descriptor_size, descriptor FROM Word ";
|
||||
if(lastStateOnly)
|
||||
{
|
||||
query = "SELECT id, descriptor_size, descriptor "
|
||||
"FROM Word "
|
||||
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Info) "
|
||||
"ORDER BY id;";
|
||||
}
|
||||
else
|
||||
{
|
||||
query = "SELECT id, descriptor_size, descriptor "
|
||||
"FROM Word "
|
||||
"WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics) "
|
||||
"ORDER BY id;";
|
||||
if(uStrNumCmp(_version, "0.11.11") >= 0)
|
||||
{
|
||||
query << "WHERE time_enter >= (SELECT MAX(time_enter) FROM Info) ";
|
||||
}
|
||||
else
|
||||
{
|
||||
query << "WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics) ";
|
||||
}
|
||||
}
|
||||
query << "ORDER BY id;";
|
||||
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.str().c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||
|
||||
// Process the result if one
|
||||
|
||||
@@ -124,7 +124,7 @@ private:
|
||||
cv::Mat * textures) const;
|
||||
|
||||
// Load objects
|
||||
virtual void loadQuery(VWDictionary * dictionary) const;
|
||||
virtual void loadQuery(VWDictionary * dictionary, bool lastStateOnly = true) const;
|
||||
virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const;
|
||||
virtual void loadSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const;
|
||||
virtual void loadWordsQuery(const std::set<int> & wordIds, std::list<VisualWord *> & vws) const;
|
||||
|
||||
@@ -279,25 +279,32 @@ void Memory::loadDataFromDb(bool postInitClosingEvents)
|
||||
}
|
||||
|
||||
UDEBUG("load words %d", (int)wordIds.size());
|
||||
if(wordIds.size())
|
||||
if(_vwd->isIncremental())
|
||||
{
|
||||
std::list<VisualWord*> words;
|
||||
_dbDriver->loadWords(wordIds, words);
|
||||
for(std::list<VisualWord*>::iterator iter = words.begin(); iter!=words.end(); ++iter)
|
||||
if(wordIds.size())
|
||||
{
|
||||
_vwd->addWord(*iter);
|
||||
std::list<VisualWord*> words;
|
||||
_dbDriver->loadWords(wordIds, words);
|
||||
for(std::list<VisualWord*>::iterator iter = words.begin(); iter!=words.end(); ++iter)
|
||||
{
|
||||
_vwd->addWord(*iter);
|
||||
}
|
||||
// Get Last word id
|
||||
int id = 0;
|
||||
_dbDriver->getLastWordId(id);
|
||||
_vwd->setLastWordId(id);
|
||||
}
|
||||
// Get Last word id
|
||||
int id = 0;
|
||||
_dbDriver->getLastWordId(id);
|
||||
_vwd->setLastWordId(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbDriver->load(_vwd, false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UDEBUG("load words");
|
||||
// load the last dictionary
|
||||
_dbDriver->load(_vwd);
|
||||
_dbDriver->load(_vwd, _vwd->isIncremental());
|
||||
}
|
||||
UDEBUG("%d words loaded!", _vwd->getUnusedWordsSize());
|
||||
_vwd->update();
|
||||
@@ -649,7 +656,10 @@ void Memory::parseParameters(const ParametersMap & parameters)
|
||||
void Memory::preUpdate()
|
||||
{
|
||||
_signaturesAdded = 0;
|
||||
this->cleanUnusedWords();
|
||||
if(_vwd->isIncremental())
|
||||
{
|
||||
this->cleanUnusedWords();
|
||||
}
|
||||
if(_vwd && !_parallelized)
|
||||
{
|
||||
//When parallelized, it is done in CreateSignature
|
||||
@@ -1584,7 +1594,7 @@ std::map<int, float> Memory::computeLikelihood(const Signature * signature, cons
|
||||
{
|
||||
// "Inverted index" - Pour chaque endroit contenu dans chaque mot
|
||||
vw = _vwd->getWord(*i);
|
||||
UASSERT(vw!=0);
|
||||
UASSERT_MSG(vw!=0, uFormat("Word %d not found in dictionary!?", *i).c_str());
|
||||
|
||||
const std::map<int, int> & refs = vw->getReferences();
|
||||
nw = refs.size();
|
||||
@@ -2055,7 +2065,7 @@ void Memory::moveToTrash(Signature * s, bool keepLinkedToGraph, std::list<int> *
|
||||
}
|
||||
|
||||
this->disableWordsRef(s->id());
|
||||
if(!keepLinkedToGraph)
|
||||
if(!keepLinkedToGraph && _vwd->isIncremental())
|
||||
{
|
||||
std::list<int> keys = uUniqueKeys(s->getWords());
|
||||
for(std::list<int>::const_iterator i=keys.begin(); i!=keys.end(); ++i)
|
||||
@@ -4217,25 +4227,22 @@ void Memory::disableWordsRef(int signatureId)
|
||||
|
||||
void Memory::cleanUnusedWords()
|
||||
{
|
||||
if(_vwd->isIncremental())
|
||||
std::vector<VisualWord*> removedWords = _vwd->getUnusedWords();
|
||||
UDEBUG("Removing %d words (dictionary size=%d)...", removedWords.size(), _vwd->getVisualWords().size());
|
||||
if(removedWords.size())
|
||||
{
|
||||
std::vector<VisualWord*> removedWords = _vwd->getUnusedWords();
|
||||
UDEBUG("Removing %d words (dictionary size=%d)...", removedWords.size(), _vwd->getVisualWords().size());
|
||||
if(removedWords.size())
|
||||
{
|
||||
// remove them from the dictionary
|
||||
_vwd->removeWords(removedWords);
|
||||
// remove them from the dictionary
|
||||
_vwd->removeWords(removedWords);
|
||||
|
||||
for(unsigned int i=0; i<removedWords.size(); ++i)
|
||||
for(unsigned int i=0; i<removedWords.size(); ++i)
|
||||
{
|
||||
if(_dbDriver)
|
||||
{
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->asyncSave(removedWords[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete removedWords[i];
|
||||
}
|
||||
_dbDriver->asyncSave(removedWords[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete removedWords[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4270,6 +4277,11 @@ void Memory::enableWordsRef(const std::list<int> & signatureIds)
|
||||
}
|
||||
}
|
||||
|
||||
if(!_vwd->isIncremental() && oldWordIds.size())
|
||||
{
|
||||
UWARN("Dictionary is fixed, but some words retrieved have not been found!?");
|
||||
}
|
||||
|
||||
UDEBUG("oldWordIds.size()=%d, getOldIds time=%fs", oldWordIds.size(), timer.ticks());
|
||||
|
||||
// the words were deleted, so try to math it with an active word
|
||||
|
||||
@@ -142,79 +142,119 @@ void VWDictionary::setFixedDictionary(const std::string & dictionaryPath)
|
||||
if((!_incrementalDictionary && _dictionaryPath.compare(dictionaryPath) != 0) ||
|
||||
_visualWords.size() == 0)
|
||||
{
|
||||
std::ifstream file;
|
||||
file.open(dictionaryPath.c_str(), std::ifstream::in);
|
||||
if(file.good())
|
||||
UDEBUG("incremental=%d, oldPath=%s newPath=%s, visual words=%d",
|
||||
_incrementalDictionary?1:0, _dictionaryPath.c_str(), dictionaryPath.c_str(), (int)_visualWords.size());
|
||||
|
||||
if(UFile::getExtension(dictionaryPath).compare("db") == 0)
|
||||
{
|
||||
UDEBUG("Deleting old dictionary and loading the new one from \"%s\"", dictionaryPath.c_str());
|
||||
UTimer timer;
|
||||
|
||||
// first line is the header
|
||||
std::string str;
|
||||
std::list<std::string> strList;
|
||||
std::getline(file, str);
|
||||
strList = uSplitNumChar(str);
|
||||
unsigned int dimension = 0;
|
||||
for(std::list<std::string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
|
||||
UDEBUG("Loading fixed vocabulary \"%s\", this may take a while...", dictionaryPath.c_str());
|
||||
DBDriver * driver = DBDriver::create();
|
||||
if(driver->openConnection(dictionaryPath, false))
|
||||
{
|
||||
if(uIsDigit(iter->at(0)))
|
||||
driver->load(this, false);
|
||||
for(std::map<int, VisualWord*>::iterator iter=_visualWords.begin(); iter!=_visualWords.end(); ++iter)
|
||||
{
|
||||
dimension = std::atoi(iter->c_str());
|
||||
break;
|
||||
iter->second->setSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
if(dimension == 0 || dimension > 1000)
|
||||
{
|
||||
UERROR("Invalid dictionary file, visual word dimension (%d) is not valid, \"%s\"", dimension, dictionaryPath.c_str());
|
||||
_incrementalDictionary = _visualWords.size()==0;
|
||||
driver->closeConnection(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Process all words
|
||||
while(file.good())
|
||||
{
|
||||
std::getline(file, str);
|
||||
strList = uSplit(str);
|
||||
if(strList.size() == dimension+1)
|
||||
{
|
||||
//first one is the visual word id
|
||||
std::list<std::string>::iterator iter = strList.begin();
|
||||
int id = std::atoi(iter->c_str());
|
||||
cv::Mat descriptor(1, dimension, CV_32F);
|
||||
++iter;
|
||||
unsigned int i=0;
|
||||
|
||||
//get descriptor
|
||||
for(;i<dimension && iter != strList.end(); ++i, ++iter)
|
||||
{
|
||||
descriptor.at<float>(i) = uStr2Float(*iter);
|
||||
}
|
||||
if(i != dimension)
|
||||
{
|
||||
UERROR("");
|
||||
}
|
||||
|
||||
VisualWord * vw = new VisualWord(id, descriptor, 0);
|
||||
_visualWords.insert(_visualWords.end(), std::pair<int, VisualWord*>(id, vw));
|
||||
_notIndexedWords.insert(_notIndexedWords.end(), id);
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Cannot parse line \"%s\"", str.c_str());
|
||||
}
|
||||
}
|
||||
this->update();
|
||||
_incrementalDictionary = false;
|
||||
UERROR("Could not load dictionary from database %s", dictionaryPath.c_str());
|
||||
}
|
||||
|
||||
|
||||
UDEBUG("Time changing dictionary = %fs", timer.ticks());
|
||||
delete driver;
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Cannot open dictionary file \"%s\"", dictionaryPath.c_str());
|
||||
UWARN("Loading fixed vocabulary \"%s\", this may take a while...", dictionaryPath.c_str());
|
||||
std::ifstream file;
|
||||
file.open(dictionaryPath.c_str(), std::ifstream::in);
|
||||
if(file.good())
|
||||
{
|
||||
UDEBUG("Deleting old dictionary and loading the new one from \"%s\"", dictionaryPath.c_str());
|
||||
UTimer timer;
|
||||
|
||||
// first line is the header
|
||||
std::string str;
|
||||
std::list<std::string> strList;
|
||||
std::getline(file, str);
|
||||
strList = uSplitNumChar(str);
|
||||
int dimension = 0;
|
||||
for(std::list<std::string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
|
||||
{
|
||||
if(uIsDigit(iter->at(0)))
|
||||
{
|
||||
dimension = std::atoi(iter->c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
UDEBUG("descriptor dimension = %d", dimension);
|
||||
|
||||
if(dimension <= 0 || dimension > 1000)
|
||||
{
|
||||
UERROR("Invalid dictionary file, visual word dimension (%d) is not valid, \"%s\"", dimension, dictionaryPath.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Process all words
|
||||
while(file.good())
|
||||
{
|
||||
std::getline(file, str);
|
||||
strList = uSplit(str);
|
||||
if(strList.size() == dimension+1)
|
||||
{
|
||||
//first one is the visual word id
|
||||
std::list<std::string>::iterator iter = strList.begin();
|
||||
int id = std::atoi(iter->c_str());
|
||||
cv::Mat descriptor(1, dimension, CV_32F);
|
||||
++iter;
|
||||
int i=0;
|
||||
|
||||
//get descriptor
|
||||
for(;i<dimension && iter != strList.end(); ++i, ++iter)
|
||||
{
|
||||
descriptor.at<float>(i) = uStr2Float(*iter);
|
||||
}
|
||||
if(i != dimension)
|
||||
{
|
||||
UERROR("Loaded word has not the same size (%d) than descriptor size previously detected (%d).", i, dimension);
|
||||
}
|
||||
|
||||
VisualWord * vw = new VisualWord(id, descriptor, 0);
|
||||
_visualWords.insert(_visualWords.end(), std::pair<int, VisualWord*>(id, vw));
|
||||
_notIndexedWords.insert(_notIndexedWords.end(), id);
|
||||
_unusedWords.insert(_unusedWords.end(), std::pair<int, VisualWord*>(id, vw));
|
||||
}
|
||||
else if(!str.empty())
|
||||
{
|
||||
UWARN("Cannot parse line \"%s\"", str.c_str());
|
||||
}
|
||||
}
|
||||
if(_visualWords.size())
|
||||
{
|
||||
UWARN("Loaded %d words!", (int)_visualWords.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Cannot open dictionary file \"%s\"", dictionaryPath.c_str());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
if(_visualWords.size() == 0)
|
||||
{
|
||||
_incrementalDictionary = _visualWords.size()==0;
|
||||
UWARN("No words loaded, cannot set a fixed dictionary.", (int)_visualWords.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->update();
|
||||
_incrementalDictionary = false;
|
||||
UDEBUG("Loaded %d words!", (int)_visualWords.size());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
else if(!_incrementalDictionary)
|
||||
{
|
||||
@@ -225,14 +265,14 @@ void VWDictionary::setFixedDictionary(const std::string & dictionaryPath)
|
||||
UERROR("Cannot change to a fixed dictionary if there are already words (%d) in the incremental one.", _visualWords.size());
|
||||
}
|
||||
}
|
||||
else if(_visualWords.size() == 0)
|
||||
{
|
||||
_incrementalDictionary = false;
|
||||
}
|
||||
else if(_incrementalDictionary)
|
||||
else if(_incrementalDictionary && _visualWords.size())
|
||||
{
|
||||
UWARN("Cannot change to fixed dictionary, %d words already loaded as incremental", (int)_visualWords.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
_incrementalDictionary = false;
|
||||
}
|
||||
_dictionaryPath = dictionaryPath;
|
||||
}
|
||||
|
||||
@@ -568,7 +608,7 @@ void VWDictionary::addWordRef(int wordId, int signatureId)
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Not found word %d", wordId);
|
||||
UERROR("Not found word %d (dict size=%d)", wordId, (int)_visualWords.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1220,26 +1260,17 @@ VisualWord * VWDictionary::getUnusedWord(int id) const
|
||||
|
||||
std::vector<VisualWord*> VWDictionary::getUnusedWords() const
|
||||
{
|
||||
if(!_incrementalDictionary)
|
||||
{
|
||||
ULOGGER_WARN("This method does nothing on a fixed dictionary");
|
||||
return std::vector<VisualWord*>();
|
||||
}
|
||||
return uValues(_unusedWords);
|
||||
}
|
||||
|
||||
std::vector<int> VWDictionary::getUnusedWordIds() const
|
||||
{
|
||||
if(!_incrementalDictionary)
|
||||
{
|
||||
ULOGGER_WARN("This method does nothing on a fixed dictionary");
|
||||
return std::vector<int>();
|
||||
}
|
||||
return uKeys(_unusedWords);
|
||||
}
|
||||
|
||||
void VWDictionary::removeWords(const std::vector<VisualWord*> & words)
|
||||
{
|
||||
UDEBUG("Removing %d words from dictionary (current size=%d)", (int)words.size(), (int)_visualWords.size());
|
||||
for(unsigned int i=0; i<words.size(); ++i)
|
||||
{
|
||||
_visualWords.erase(words[i]->id());
|
||||
|
||||
Reference in New Issue
Block a user