Skip to content

Commit 8051be4

Browse files
authored
Automated dictionary recovery/repairing (#1669)
* Automated dictionary recovery/repairing * typo * updated comment * updating dictionary after fixing it * Fixing missing ref * Adding helping assert msg in case of repairing failure
1 parent 0ef9077 commit 8051be4

File tree

3 files changed

+115
-7
lines changed

3 files changed

+115
-7
lines changed

corelib/include/rtabmap/core/VWDictionary.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class RTABMAP_CORE_EXPORT VWDictionary
8989
std::vector<int> findNN(const std::list<VisualWord *> & vws) const;
9090
std::vector<int> findNN(const cv::Mat & descriptors) const;
9191

92-
void addWordRef(int wordId, int signatureId);
92+
bool addWordRef(int wordId, int signatureId);
9393
void removeAllWordRef(int wordId, int signatureId);
9494
const VisualWord * getWord(int id) const;
9595
VisualWord * getUnusedWord(int id) const;

corelib/src/Memory.cpp

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,8 @@ void Memory::loadDataFromDb(bool postInitClosingEvents)
437437
UTimer timer;
438438
// Enable loaded signatures
439439
const std::map<int, Signature *> & signatures = this->getSignatures();
440-
for(std::map<int, Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
440+
bool corruptedDictionary = false;
441+
for(std::map<int, Signature *>::const_iterator i=signatures.begin(); i!=signatures.end() && !corruptedDictionary; ++i)
441442
{
442443
Signature * s = this->_getSignature(i->first);
443444
UASSERT(s != 0);
@@ -450,12 +451,114 @@ void Memory::loadDataFromDb(bool postInitClosingEvents)
450451
{
451452
if(iter->first > 0)
452453
{
453-
_vwd->addWordRef(iter->first, i->first);
454+
if(!_vwd->addWordRef(iter->first, s->id()))
455+
{
456+
corruptedDictionary = true;
457+
break;
458+
}
459+
}
460+
}
461+
s->setEnabled(!corruptedDictionary);
462+
if(corruptedDictionary)
463+
{
464+
//revert all changes from that signature till it broke above
465+
for(std::multimap<int, int>::const_iterator iter = words.begin(); iter!=words.end(); ++iter)
466+
{
467+
if(iter->first > 0)
468+
{
469+
_vwd->removeAllWordRef(iter->first, s->id());
470+
}
454471
}
455472
}
456-
s->setEnabled(true);
457473
}
458474
}
475+
if(corruptedDictionary)
476+
{
477+
if(!_vwd->isIncremental())
478+
{
479+
UERROR("The dictionary is empty or missing some words from nodes in WM, "
480+
"we cannot repair it because it is a fixed dictionary. Make sure you "
481+
"are using the right fixed dictionary that was used to generate the map.");
482+
}
483+
else
484+
{
485+
std::string msg = uFormat(
486+
"The dictionary is empty or missing some words from nodes in WM, "
487+
"we will try to repair it. This can be caused by rtabmap closing before it has time "
488+
"to save the dictionary. Re-creating the dictionary from %ld nodes...",
489+
signatures.size());
490+
UWARN("%s", msg.c_str());
491+
if(postInitClosingEvents) UEventsManager::post(new RtabmapEventInit(msg));
492+
493+
//remove all words ref
494+
495+
const std::map<int, VisualWord *> & addedWords = _vwd->getVisualWords();
496+
int nodesRepaired = 0;
497+
size_t oldSize = addedWords.size();
498+
std::string assertMsg =
499+
"If we assert here, the problem is maybe deeper. Try "
500+
"to use rtabmap-recovery tool instead to fix the database.";
501+
for(std::map<int, Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
502+
{
503+
Signature * s = this->_getSignature(i->first);
504+
UASSERT_MSG(s != 0, assertMsg.c_str());
505+
506+
if(s->isEnabled())
507+
{
508+
// Words already in dictionary and references added
509+
continue;
510+
}
511+
512+
const std::multimap<int, int> * words = &s->getWords();
513+
if(words->size())
514+
{
515+
cv::Mat descriptors = s->getWordsDescriptors();
516+
std::multimap<int, int> loadedWords;
517+
if(descriptors.empty())
518+
{
519+
// We may have started rtabmap without loading features, check in the database
520+
std::multimap<int, int> w;
521+
std::vector<cv::KeyPoint> k;
522+
std::vector<cv::Point3f> p;
523+
_dbDriver->getLocalFeatures(s->id(), loadedWords, k, p, descriptors);
524+
UASSERT_MSG(loadedWords.size() == words->size(), assertMsg.c_str()); // Just doublecheck
525+
words = &loadedWords; // The index will be set
526+
UASSERT_MSG(!descriptors.empty(), assertMsg.c_str());
527+
}
528+
bool repaired = false;
529+
for(std::multimap<int, int>::const_iterator iter = words->begin(); iter!=words->end(); ++iter)
530+
{
531+
if(iter->first > 0)
532+
{
533+
if(addedWords.find(iter->first) == addedWords.end())
534+
{
535+
UASSERT_MSG(iter->second >= 0 && iter->second < descriptors.rows,
536+
uFormat("iter->second=%d descriptors.rows=%d (signature=%d word=%d). %s",
537+
iter->second, descriptors.rows, s->id(), iter->first, assertMsg.c_str()).c_str());
538+
_vwd->addWord(new VisualWord(iter->first, descriptors.row(iter->second).clone()));
539+
repaired = true;
540+
}
541+
UASSERT_MSG(_vwd->addWordRef(iter->first, s->id()), assertMsg.c_str());
542+
}
543+
}
544+
nodesRepaired += (repaired?1:0);
545+
s->setEnabled(true);
546+
}
547+
}
548+
549+
msg = uFormat(
550+
"Regenerated the dictionary with %ld missing words (%ld -> %ld) from %d nodes.",
551+
addedWords.size() - oldSize,
552+
oldSize,
553+
addedWords.size(),
554+
nodesRepaired);
555+
UWARN("%s", msg.c_str());
556+
if(postInitClosingEvents) UEventsManager::post(new RtabmapEventInit(msg));
557+
_memoryChanged = true; // This will force rtabmap to save back the dictionary even if we don't process any new data
558+
_vwd->update();
559+
}
560+
}
561+
459562
if(postInitClosingEvents) UEventsManager::post(new RtabmapEventInit(uFormat("Adding word references, done! (%d)", _vwd->getTotalActiveReferences())));
460563

461564
if(_vwd->getUnusedWordsSize() && _vwd->isIncremental())
@@ -6599,7 +6702,10 @@ void Memory::enableWordsRef(const std::list<int> & signatureIds)
65996702
{
66006703
if(keys.at(i)>0)
66016704
{
6602-
_vwd->addWordRef(keys.at(i), (*j)->id());
6705+
if(_vwd->addWordRef(keys.at(i), (*j)->id()))
6706+
{
6707+
UERROR("Could not add word ref %d to node %d!?", keys.at(i), (*j)->id());
6708+
}
66036709
}
66046710
}
66056711
(*j)->setEnabled(true);

corelib/src/VWDictionary.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,7 @@ int VWDictionary::getNextId()
868868
return ++_lastWordId;
869869
}
870870

871-
void VWDictionary::addWordRef(int wordId, int signatureId)
871+
bool VWDictionary::addWordRef(int wordId, int signatureId)
872872
{
873873
VisualWord * vw = 0;
874874
vw = uValue(_visualWords, wordId, vw);
@@ -878,10 +878,12 @@ void VWDictionary::addWordRef(int wordId, int signatureId)
878878
_totalActiveReferences += 1;
879879

880880
_unusedWords.erase(vw->id());
881+
return true;
881882
}
882883
else
883884
{
884-
UERROR("Not found word %d (dict size=%d)", wordId, (int)_visualWords.size());
885+
UWARN("Not found word %d (dict size=%d)", wordId, (int)_visualWords.size());
886+
return false;
885887
}
886888
}
887889

0 commit comments

Comments
 (0)