@@ -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 );
0 commit comments