2011-06-05 14:45:39 +00:00
/*
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
*
* This file is part of RTAB-Map.
*
* RTAB-Map is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RTAB-Map is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
*/
2013-04-30 20:16:01 +00:00
#include <rtabmap/utilite/UEventsManager.h>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/UConversion.h>
#include <rtabmap/utilite/UProcessInfo.h>
#include <rtabmap/utilite/UMath.h>
2012-06-24 17:19:34 +00:00
#include "rtabmap/core/Memory.h"
2013-12-11 00:12:44 +00:00
#include "rtabmap/core/Signature.h"
2011-06-05 14:45:39 +00:00
#include "rtabmap/core/Parameters.h"
#include "rtabmap/core/RtabmapEvent.h"
2012-12-11 18:05:05 +00:00
#include "rtabmap/core/VWDictionary.h"
#include "VisualWord.h"
#include "rtabmap/core/Features2d.h"
2013-12-11 00:12:44 +00:00
#include "rtabmap/core/util3d.h"
2012-12-11 18:05:05 +00:00
#include "DBDriverSqlite3.h"
2013-12-11 00:12:44 +00:00
#include "rtabmap/core/util3d.h"
#include "rtabmap/core/Statistics.h"
#include <pcl/io/pcd_io.h>
2011-06-05 14:45:39 +00:00
namespace rtabmap {
2013-06-10 18:54:11 +00:00
const int Memory :: kIdStart = 0 ;
2011-06-05 14:45:39 +00:00
const int Memory :: kIdVirtual = - 1 ;
const int Memory :: kIdInvalid = 0 ;
Memory :: Memory ( const ParametersMap & parameters ) :
_dbDriver ( 0 ),
2012-12-11 18:05:05 +00:00
_similarityThreshold ( Parameters :: defaultMemRehearsalSimilarity ()),
_rawDataKept ( Parameters :: defaultMemImageKept ()),
2013-03-02 21:53:47 +00:00
_keepRehearsedNodesInDb ( Parameters :: defaultMemRehearsedNodesKept ()),
2011-06-05 14:45:39 +00:00
_incrementalMemory ( Parameters :: defaultMemIncrementalMemory ()),
2012-12-11 18:05:05 +00:00
_maxStMemSize ( Parameters :: defaultMemSTMSize ()),
2011-06-05 14:45:39 +00:00
_recentWmRatio ( Parameters :: defaultMemRecentWmRatio ()),
2013-01-27 04:50:49 +00:00
_idUpdatedToNewOneRehearsal ( Parameters :: defaultMemRehearsalIdUpdatedToNewOne ()),
2013-12-11 00:12:44 +00:00
_generateIds ( Parameters :: defaultMemGenerateIds ()),
2014-01-15 20:41:58 +00:00
_badSignaturesIgnored ( Parameters :: defaultMemBadSignaturesIgnored ()),
2012-03-03 01:46:30 +00:00
_idCount ( kIdStart ),
2013-12-11 00:12:44 +00:00
_idMapCount ( kIdStart ),
2012-03-03 01:46:30 +00:00
_lastSignature ( 0 ),
2014-01-22 19:49:28 +00:00
_lastGlobalLoopClosureParentId ( 0 ),
_lastGlobalLoopClosureChildId ( 0 ),
2012-12-11 18:05:05 +00:00
_memoryChanged ( false ),
_signaturesAdded ( 0 ),
_keypointDetector ( 0 ),
_keypointDescriptor ( 0 ),
_badSignRatio ( Parameters :: defaultKpBadSignRatio ()),
_tfIdfLikelihoodUsed ( Parameters :: defaultKpTfIdfLikelihoodUsed ()),
2013-12-11 00:12:44 +00:00
_parallelized ( Parameters :: defaultKpParallelized ()),
_wordsPerImageTarget ( Parameters :: defaultKpWordsPerImage ()),
_roiRatios ( std :: vector < float > ( 4 , 0.0f )),
_bowMinInliers ( Parameters :: defaultLccBowMinInliers ()),
_bowInlierDistance ( Parameters :: defaultLccBowInlierDistance ()),
_bowIterations ( Parameters :: defaultLccBowIterations ()),
_bowMaxDepth ( Parameters :: defaultLccBowMaxDepth ()),
_icpDecimation ( Parameters :: defaultLccIcp3Decimation ()),
_icpMaxDepth ( Parameters :: defaultLccIcp3MaxDepth ()),
_icpVoxelSize ( Parameters :: defaultLccIcp3VoxelSize ()),
_icpSamples ( Parameters :: defaultLccIcp3Samples ()),
_icpMaxCorrespondenceDistance ( Parameters :: defaultLccIcp3MaxCorrespondenceDistance ()),
_icpMaxIterations ( Parameters :: defaultLccIcp3Iterations ()),
_icpMaxFitness ( Parameters :: defaultLccIcp3MaxFitness ()),
_icp2MaxCorrespondenceDistance ( Parameters :: defaultLccIcp2MaxCorrespondenceDistance ()),
_icp2MaxIterations ( Parameters :: defaultLccIcp2Iterations ()),
_icp2MaxFitness ( Parameters :: defaultLccIcp2MaxFitness ()),
2014-01-22 19:49:28 +00:00
_icp2CorrespondenceRatio ( Parameters :: defaultLccIcp2CorrespondenceRatio ()),
_icp2VoxelSize ( Parameters :: defaultLccIcp2VoxelSize ())
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
_vwd = new VWDictionary ( parameters );
2011-06-05 14:45:39 +00:00
this -> parseParameters ( parameters );
}
2013-12-11 00:12:44 +00:00
bool Memory :: init ( const std :: string & dbUrl , bool dbOverwritten , const ParametersMap & parameters , bool postInitEvents )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( RtabmapEventInit :: kInitializing ));
2013-02-03 22:12:02 +00:00
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
this -> parseParameters ( parameters );
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( "Clearing memory..." ));
2013-01-25 21:05:20 +00:00
DBDriver * tmpDriver = 0 ;
2012-12-12 19:17:43 +00:00
if ( ! _memoryChanged )
{
if ( _dbDriver )
{
2013-01-25 21:05:20 +00:00
tmpDriver = _dbDriver ;
_dbDriver = 0 ; // HACK for the clear() below to think that there is no db
2012-12-12 19:17:43 +00:00
}
}
2012-03-03 01:46:30 +00:00
this -> clear ();
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( "Clearing memory, done!" ));
2012-03-03 01:46:30 +00:00
2013-12-11 00:12:44 +00:00
if ( tmpDriver )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
_dbDriver = tmpDriver ;
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
if ( _dbDriver )
{
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( "Closing database connection..." ));
_dbDriver -> closeConnection ();
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( "Closing database connection, done!" ));
}
if ( _dbDriver == 0 && ! dbUrl . empty ())
2012-03-03 01:46:30 +00:00
{
2012-12-11 18:05:05 +00:00
_dbDriver = new DBDriverSqlite3 ( parameters );
2012-03-03 01:46:30 +00:00
}
2011-06-05 14:45:39 +00:00
2013-12-11 00:12:44 +00:00
bool success = true ;
2011-06-05 14:45:39 +00:00
if ( _dbDriver )
{
2013-12-11 00:12:44 +00:00
success = false ;
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( std :: string ( "Connecting to database " ) + dbUrl + "..." ));
2012-03-03 01:46:30 +00:00
if ( _dbDriver -> openConnection ( dbUrl , dbOverwritten ))
2011-06-05 14:45:39 +00:00
{
success = true ;
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( std :: string ( "Connecting to database " ) + dbUrl + ", done!" ));
2011-06-05 14:45:39 +00:00
// Load the last working memory...
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( std :: string ( "Loading last signatures..." )));
2011-06-05 14:45:39 +00:00
std :: list < Signature *> dbSignatures ;
2012-06-24 17:19:34 +00:00
_dbDriver -> loadLastNodes ( dbSignatures );
2011-06-05 14:45:39 +00:00
for ( std :: list < Signature *>:: reverse_iterator iter = dbSignatures . rbegin (); iter != dbSignatures . rend (); ++ iter )
{
2013-06-10 18:54:11 +00:00
// ignore bad signatures
2014-01-15 20:41:58 +00:00
if ( ! (( * iter ) -> isBadSignature () && _badSignaturesIgnored ))
2011-06-05 14:45:39 +00:00
{
2013-06-10 18:54:11 +00:00
_signatures . insert ( std :: pair < int , Signature *> (( * iter ) -> id (), * iter ));
if (( int ) _stMem . size () <= _maxStMemSize )
{
_stMem . insert (( * iter ) -> id ());
}
else
{
_workingMem . insert (( * iter ) -> id ());
}
2011-06-05 14:45:39 +00:00
}
else
{
2013-06-10 18:54:11 +00:00
delete * iter ;
2011-06-05 14:45:39 +00:00
}
}
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( std :: string ( "Loading last signatures, done! (" ) + uNumber2Str ( int ( _workingMem . size () + _stMem . size ())) + " loaded)" ));
2011-06-05 14:45:39 +00:00
// Assign the last signature
if ( _stMem . size () > 0 )
{
_lastSignature = uValue ( _signatures , * _stMem . rbegin (), ( Signature * ) 0 );
}
// Last id
2012-06-24 17:19:34 +00:00
_dbDriver -> getLastNodeId ( _idCount );
2013-12-11 00:12:44 +00:00
_idMapCount = _lastSignature ? _lastSignature -> mapId () : kIdStart ;
2011-06-05 14:45:39 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( RtabmapEventInit :: kError , std :: string ( "Connecting to database " ) + dbUrl + ", path is invalid!" ));
2011-06-05 14:45:39 +00:00
}
}
else
{
_idCount = kIdStart ;
2013-12-11 00:12:44 +00:00
_idMapCount = kIdStart ;
2011-06-05 14:45:39 +00:00
}
2012-12-11 18:05:05 +00:00
_workingMem . insert ( kIdVirtual );
2011-06-05 14:45:39 +00:00
2013-12-11 00:12:44 +00:00
UDEBUG ( "ids start with %d" , _idCount + 1 );
UDEBUG ( "map ids start with %d" , _idMapCount );
2012-12-11 18:05:05 +00:00
// Now load the dictionary if we have a connection
2012-12-12 16:40:18 +00:00
if ( _dbDriver && _dbDriver -> isConnected ())
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( "Loading dictionary..." ));
2012-12-11 18:05:05 +00:00
_dbDriver -> load ( _vwd );
2012-12-12 16:40:18 +00:00
UDEBUG ( "%d words loaded!" , _vwd -> getUnusedWordsSize ());
2014-02-11 23:04:22 +00:00
_vwd -> update ();
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( uFormat ( "Loading dictionary, done! (%d words)" , ( int ) _vwd -> getUnusedWordsSize ())));
2012-12-11 18:05:05 +00:00
}
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( std :: string ( "Adding word references..." )));
2012-12-11 18:05:05 +00:00
// Enable loaded signatures
Signature * ss ;
const std :: map < int , Signature *> & signatures = this -> getSignatures ();
for ( std :: map < int , Signature *>:: const_iterator i = signatures . begin (); i != signatures . end (); ++ i )
{
ss = this -> _getSignature ( i -> first );
if ( ss )
{
2012-12-12 16:40:18 +00:00
const std :: multimap < int , cv :: KeyPoint > & words = ss -> getWords ();
if ( words . size ())
{
UDEBUG ( "node=%d, word references=%d" , ss -> id (), words . size ());
for ( std :: multimap < int , cv :: KeyPoint >:: const_iterator iter = words . begin (); iter != words . end (); ++ iter )
{
_vwd -> addWordRef ( iter -> first , i -> first );
}
ss -> setEnabled ( true );
}
2012-12-11 18:05:05 +00:00
}
}
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( uFormat ( "Adding word references, done! (%d)" , _vwd -> getTotalActiveReferences ())));
2012-12-12 16:40:18 +00:00
if ( _vwd -> getUnusedWordsSize ())
2012-12-11 18:05:05 +00:00
{
2012-12-12 16:40:18 +00:00
UWARN ( "_vwd->getUnusedWordsSize() must be empty... size=%d" , _vwd -> getUnusedWordsSize ());
2012-12-11 18:05:05 +00:00
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "Total word references added = %d" , _vwd -> getTotalActiveReferences ());
2012-12-11 18:05:05 +00:00
2013-12-11 00:12:44 +00:00
if ( postInitEvents ) UEventsManager :: post ( new RtabmapEventInit ( RtabmapEventInit :: kInitialized ));
2011-06-05 14:45:39 +00:00
return success ;
}
Memory ::~ Memory ()
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
if ( ! _memoryChanged )
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
if ( _dbDriver )
{
_dbDriver -> closeConnection ();
delete _dbDriver ;
_dbDriver = 0 ;
}
this -> clear ();
}
else
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
this -> clear ();
if ( _dbDriver )
{
_dbDriver -> emptyTrashes ();
_dbDriver -> closeConnection ();
delete _dbDriver ;
_dbDriver = 0 ;
}
}
2012-12-11 18:05:05 +00:00
if ( _keypointDetector )
{
delete _keypointDetector ;
}
if ( _keypointDescriptor )
{
delete _keypointDescriptor ;
}
if ( _vwd )
{
delete _vwd ;
}
2011-06-05 14:45:39 +00:00
}
void Memory :: parseParameters ( const ParametersMap & parameters )
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
ParametersMap :: const_iterator iter ;
2013-12-11 00:12:44 +00:00
Parameters :: parse ( parameters , Parameters :: kMemImageKept (), _rawDataKept );
Parameters :: parse ( parameters , Parameters :: kMemRehearsedNodesKept (), _keepRehearsedNodesInDb );
Parameters :: parse ( parameters , Parameters :: kMemRehearsalIdUpdatedToNewOne (), _idUpdatedToNewOneRehearsal );
Parameters :: parse ( parameters , Parameters :: kMemGenerateIds (), _generateIds );
2014-01-15 20:41:58 +00:00
Parameters :: parse ( parameters , Parameters :: kMemBadSignaturesIgnored (), _badSignaturesIgnored );
2013-12-11 00:12:44 +00:00
Parameters :: parse ( parameters , Parameters :: kMemRehearsalSimilarity (), _similarityThreshold );
Parameters :: parse ( parameters , Parameters :: kMemRecentWmRatio (), _recentWmRatio );
Parameters :: parse ( parameters , Parameters :: kMemSTMSize (), _maxStMemSize );
UASSERT_MSG ( _maxStMemSize > 0 , uFormat ( "value=%d" , _maxStMemSize ). c_str ());
UASSERT_MSG ( _similarityThreshold >= 0.0f && _similarityThreshold <= 1.0f , uFormat ( "value=%f" , _similarityThreshold ). c_str ());
UASSERT_MSG ( _recentWmRatio >= 0.0f && _recentWmRatio <= 1.0f , uFormat ( "value=%f" , _recentWmRatio ). c_str ());
// SLAM mode vs Localization mode
iter = parameters . find ( Parameters :: kMemIncrementalMemory ());
if ( iter != parameters . end ())
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
bool value = uStr2Bool ( iter -> second . c_str ());
if ( value == false && _incrementalMemory )
{
// From SLAM to localization, change map id
this -> incrementMapId ();
}
_incrementalMemory = value ;
2012-03-03 01:46:30 +00:00
}
2013-12-11 00:12:44 +00:00
2011-06-05 14:45:39 +00:00
if ( _dbDriver )
{
_dbDriver -> parseParameters ( parameters );
}
2012-12-11 18:05:05 +00:00
2013-12-11 00:12:44 +00:00
Parameters :: parse ( parameters , Parameters :: kLccBowMinInliers (), _bowMinInliers );
Parameters :: parse ( parameters , Parameters :: kLccBowInlierDistance (), _bowInlierDistance );
Parameters :: parse ( parameters , Parameters :: kLccBowIterations (), _bowIterations );
Parameters :: parse ( parameters , Parameters :: kLccBowMaxDepth (), _bowMaxDepth );
Parameters :: parse ( parameters , Parameters :: kLccIcp3Decimation (), _icpDecimation );
Parameters :: parse ( parameters , Parameters :: kLccIcp3MaxDepth (), _icpMaxDepth );
Parameters :: parse ( parameters , Parameters :: kLccIcp3VoxelSize (), _icpVoxelSize );
Parameters :: parse ( parameters , Parameters :: kLccIcp3Samples (), _icpSamples );
Parameters :: parse ( parameters , Parameters :: kLccIcp3MaxCorrespondenceDistance (), _icpMaxCorrespondenceDistance );
Parameters :: parse ( parameters , Parameters :: kLccIcp3Iterations (), _icpMaxIterations );
Parameters :: parse ( parameters , Parameters :: kLccIcp3MaxFitness (), _icpMaxFitness );
Parameters :: parse ( parameters , Parameters :: kLccIcp2MaxCorrespondenceDistance (), _icp2MaxCorrespondenceDistance );
Parameters :: parse ( parameters , Parameters :: kLccIcp2Iterations (), _icp2MaxIterations );
Parameters :: parse ( parameters , Parameters :: kLccIcp2MaxFitness (), _icp2MaxFitness );
Parameters :: parse ( parameters , Parameters :: kLccIcp2CorrespondenceRatio (), _icp2CorrespondenceRatio );
2014-01-22 19:49:28 +00:00
Parameters :: parse ( parameters , Parameters :: kLccIcp2VoxelSize (), _icp2VoxelSize );
2013-12-11 00:12:44 +00:00
2014-01-22 19:49:28 +00:00
UASSERT_MSG ( _bowMinInliers >= 1 , uFormat ( "value=%d" , _bowMinInliers ). c_str ());
2013-12-11 00:12:44 +00:00
UASSERT_MSG ( _bowInlierDistance > 0.0f , uFormat ( "value=%f" , _bowInlierDistance ). c_str ());
UASSERT_MSG ( _bowIterations > 0 , uFormat ( "value=%d" , _bowIterations ). c_str ());
UASSERT_MSG ( _bowMaxDepth >= 0.0f , uFormat ( "value=%f" , _bowMaxDepth ). c_str ());
UASSERT_MSG ( _icpDecimation > 0 , uFormat ( "value=%d" , _icpDecimation ). c_str ());
UASSERT_MSG ( _icpMaxDepth >= 0.0f , uFormat ( "value=%f" , _icpMaxDepth ). c_str ());
UASSERT_MSG ( _icpVoxelSize >= 0 , uFormat ( "value=%d" , _icpVoxelSize ). c_str ());
UASSERT_MSG ( _icpSamples >= 0 , uFormat ( "value=%d" , _icpSamples ). c_str ());
UASSERT_MSG ( _icpMaxCorrespondenceDistance > 0.0f , uFormat ( "value=%f" , _icpMaxCorrespondenceDistance ). c_str ());
UASSERT_MSG ( _icpMaxIterations > 0 , uFormat ( "value=%d" , _icpMaxIterations ). c_str ());
UASSERT_MSG ( _icpMaxFitness > 0.0f , uFormat ( "value=%f" , _icpMaxFitness ). c_str ());
UASSERT_MSG ( _icp2MaxCorrespondenceDistance > 0.0f , uFormat ( "value=%f" , _icp2MaxCorrespondenceDistance ). c_str ());
UASSERT_MSG ( _icp2MaxIterations > 0 , uFormat ( "value=%d" , _icp2MaxIterations ). c_str ());
UASSERT_MSG ( _icp2MaxFitness > 0.0f , uFormat ( "value=%f" , _icp2MaxFitness ). c_str ());
UASSERT_MSG ( _icp2CorrespondenceRatio >= 0.0f && _icp2CorrespondenceRatio <= 1.0f , uFormat ( "value=%f" , _icp2MaxFitness ). c_str ());
2014-01-22 19:49:28 +00:00
UASSERT_MSG ( _icp2VoxelSize >= 0 , uFormat ( "value=%d" , _icp2VoxelSize ). c_str ());
2012-12-11 18:05:05 +00:00
// Keypoint stuff
if ( _vwd )
{
_vwd -> parseParameters ( parameters );
}
2013-12-11 00:12:44 +00:00
Parameters :: parse ( parameters , Parameters :: kKpTfIdfLikelihoodUsed (), _tfIdfLikelihoodUsed );
Parameters :: parse ( parameters , Parameters :: kKpParallelized (), _parallelized );
Parameters :: parse ( parameters , Parameters :: kKpBadSignRatio (), _badSignRatio );
Parameters :: parse ( parameters , Parameters :: kKpWordsPerImage (), _wordsPerImageTarget );
2012-12-11 18:05:05 +00:00
2013-12-11 00:12:44 +00:00
if (( iter = parameters . find ( Parameters :: kKpRoiRatios ())) != parameters . end ())
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
this -> setRoi (( * iter ). second );
2012-12-11 18:05:05 +00:00
}
//Keypoint detector
KeypointDetector :: DetectorType detectorStrategy = KeypointDetector :: kDetectorUndef ;
if (( iter = parameters . find ( Parameters :: kKpDetectorStrategy ())) != parameters . end ())
{
detectorStrategy = ( KeypointDetector :: DetectorType ) std :: atoi (( * iter ). second . c_str ());
}
if ( ! _keypointDetector || detectorStrategy != KeypointDetector :: kDetectorUndef )
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "new detector strategy %d" , int ( detectorStrategy ));
2012-12-11 18:05:05 +00:00
if ( _keypointDetector )
{
delete _keypointDetector ;
_keypointDetector = 0 ;
}
if ( _keypointDescriptor )
{
delete _keypointDescriptor ;
_keypointDescriptor = 0 ;
}
2013-12-11 00:12:44 +00:00
switch ( detectorStrategy )
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
case KeypointDetector :: kDetectorSift :
_keypointDetector = new SIFTDetector ( parameters );
2012-12-11 18:05:05 +00:00
_keypointDescriptor = new SIFTDescriptor ( parameters );
break ;
2013-12-11 00:12:44 +00:00
case KeypointDetector :: kDetectorSurf :
2012-12-11 18:05:05 +00:00
default :
2013-12-11 00:12:44 +00:00
_keypointDetector = new SURFDetector ( parameters );
2012-12-11 18:05:05 +00:00
_keypointDescriptor = new SURFDescriptor ( parameters );
break ;
}
}
2013-12-11 00:12:44 +00:00
else
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
if ( _keypointDetector )
{
_keypointDetector -> parseParameters ( parameters );
}
if ( _keypointDescriptor )
{
_keypointDescriptor -> parseParameters ( parameters );
}
2012-12-11 18:05:05 +00:00
}
2011-06-05 14:45:39 +00:00
}
void Memory :: preUpdate ()
{
_signaturesAdded = 0 ;
2012-12-11 18:05:05 +00:00
this -> cleanUnusedWords ();
if ( _vwd && ! _parallelized )
{
//When parallelized, it is done in CreateSignature
_vwd -> update ();
}
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
bool Memory :: update ( const Image & image , Statistics * stats )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
UTimer timer ;
UTimer totalTimer ;
timer . start ();
2011-07-18 17:59:57 +00:00
float t ;
2011-06-05 14:45:39 +00:00
//============================================================
// Pre update...
//============================================================
2013-12-11 00:12:44 +00:00
UDEBUG ( "pre-updating..." );
2011-06-05 14:45:39 +00:00
this -> preUpdate ();
2011-07-18 17:59:57 +00:00
t = timer . ticks () * 1000 ;
2013-12-11 00:12:44 +00:00
if ( stats ) stats -> addStatistic ( Statistics :: kTimingMemPre_update (), t );
UDEBUG ( "time preUpdate=%f ms" , t );
2011-06-05 14:45:39 +00:00
//============================================================
// Create a signature with the image received.
//============================================================
2013-01-21 18:55:25 +00:00
Signature * signature = this -> createSignature ( image , this -> isRawDataKept ());
2011-06-05 14:45:39 +00:00
if ( signature == 0 )
{
2013-12-11 00:12:44 +00:00
UERROR ( "Failed to create a signature..." );
2012-06-24 17:19:34 +00:00
return false ;
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
t = timer . ticks () * 1000 ;
if ( stats ) stats -> addStatistic ( Statistics :: kTimingMemSignature_creation (), t );
UDEBUG ( "time creating signature=%f ms" , t );
2012-03-03 01:46:30 +00:00
// It will be added to the short-term memory, no need to delete it...
2012-12-11 18:05:05 +00:00
this -> addSignatureToStm ( signature );
2012-06-24 17:19:34 +00:00
2011-06-05 14:45:39 +00:00
_lastSignature = signature ;
//============================================================
2012-03-03 01:46:30 +00:00
// Rehearsal step...
2011-06-05 14:45:39 +00:00
// Compare with the X last signatures. If different, add this
// signature like a parent to the memory tree, otherwise add
// it as a child to the similar signature.
//============================================================
2013-06-06 13:41:49 +00:00
if ( _incrementalMemory )
{
this -> rehearsal ( signature , stats );
t = timer . ticks () * 1000 ;
2013-12-11 00:12:44 +00:00
if ( stats ) stats -> addStatistic ( Statistics :: kTimingMemRehearsal (), t );
UDEBUG ( "time rehearsal=%f ms" , t );
}
else
{
if ( _workingMem . size () <= 1 )
{
UWARN ( "The working memory is empty and the memory is not "
"incremental (Mem/IncrementalMemory=False), no loop closure "
"can be detected! Please set Mem/IncrementalMemory=true to increase "
"the memory with new images or decrease the STM size (which is %d "
"including the new one added)." , ( int ) _stMem . size ());
}
2013-06-06 13:41:49 +00:00
}
2011-06-05 14:45:39 +00:00
2012-03-03 01:46:30 +00:00
//============================================================
// Transfer the oldest signature of the short-term memory to the working memory
//============================================================
2012-12-11 18:05:05 +00:00
while ( _stMem . size () && ( int ) _stMem . size () > _maxStMemSize )
2012-03-03 01:46:30 +00:00
{
2012-12-11 18:05:05 +00:00
UDEBUG ( "Inserting node %d from STM in WM..." , * _stMem . begin ());
2012-03-03 01:46:30 +00:00
_workingMem . insert ( _workingMem . end (), * _stMem . begin ());
_stMem . erase ( * _stMem . begin ());
++ _signaturesAdded ;
}
2013-06-06 13:41:49 +00:00
if ( ! _memoryChanged && _incrementalMemory )
2011-06-05 14:45:39 +00:00
{
_memoryChanged = true ;
}
UDEBUG ( "totalTimer = %fs" , totalTimer . ticks ());
2014-01-22 19:49:28 +00:00
if ( stats ) stats -> addStatistic ( Statistics :: kLoopLast_loop_closure_parent (), _lastGlobalLoopClosureParentId );
if ( stats ) stats -> addStatistic ( Statistics :: kLoopLast_loop_closure_child (), _lastGlobalLoopClosureChildId );
2011-06-05 14:45:39 +00:00
return true ;
}
2013-12-11 00:12:44 +00:00
void Memory :: setRoi ( const std :: string & roi )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
std :: list < std :: string > strValues = uSplit ( roi , ' ' );
if ( strValues . size () != 4 )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
ULOGGER_ERROR ( "The number of values must be 4 (roi= \" %s \" )" , roi . c_str ());
2011-06-05 14:45:39 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
std :: vector < float > tmpValues ( 4 );
unsigned int i = 0 ;
for ( std :: list < std :: string >:: iterator iter = strValues . begin (); iter != strValues . end (); ++ iter )
{
tmpValues [ i ] = std :: atof (( * iter ). c_str ());
++ i ;
}
2012-12-11 18:05:05 +00:00
2013-12-11 00:12:44 +00:00
if ( tmpValues [ 0 ] >= 0 && tmpValues [ 0 ] < 1 && tmpValues [ 0 ] < 1.0f - tmpValues [ 1 ] &&
tmpValues [ 1 ] >= 0 && tmpValues [ 1 ] < 1 && tmpValues [ 1 ] < 1.0f - tmpValues [ 0 ] &&
tmpValues [ 2 ] >= 0 && tmpValues [ 2 ] < 1 && tmpValues [ 2 ] < 1.0f - tmpValues [ 3 ] &&
tmpValues [ 3 ] >= 0 && tmpValues [ 3 ] < 1 && tmpValues [ 3 ] < 1.0f - tmpValues [ 2 ])
{
_roiRatios = tmpValues ;
}
else
{
ULOGGER_ERROR ( "The roi ratios are not valid (roi= \" %s \" )" , roi . c_str ());
}
2011-06-05 14:45:39 +00:00
}
}
2012-12-11 18:05:05 +00:00
void Memory :: addSignatureToStm ( Signature * signature )
2011-06-05 14:45:39 +00:00
{
UTimer timer ;
2012-03-03 01:46:30 +00:00
// add signature on top of the short-term memory
if ( signature )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
UDEBUG ( "adding %d" , signature -> id ());
2011-06-05 14:45:39 +00:00
// Update neighbors
if ( _stMem . size ())
{
2013-12-11 00:12:44 +00:00
if ( _signatures . at ( * _stMem . rbegin ()) -> mapId () == signature -> mapId ())
{
Transform motionEstimate ;
if ( ! signature -> getPose (). isNull () &&
! _signatures . at ( * _stMem . rbegin ()) -> getPose (). isNull ())
{
motionEstimate = _signatures . at ( * _stMem . rbegin ()) -> getPose (). inverse () * signature -> getPose ();
_signatures . at ( * _stMem . rbegin ()) -> addNeighbor ( signature -> id (), motionEstimate );
}
else
{
_signatures . at ( * _stMem . rbegin ()) -> addNeighbor ( signature -> id ());
}
signature -> addNeighbor ( * _stMem . rbegin (), motionEstimate . isNull () ? Transform () : motionEstimate . inverse ());
UDEBUG ( "Min STM id = %d" , * _stMem . begin ());
}
else
{
UDEBUG ( "Ignoring neighbor link between %d and %d because they are not in the same map! (%d vs %d)" ,
* _stMem . rbegin (), signature -> id (),
_signatures . at ( * _stMem . rbegin ()) -> mapId (), signature -> mapId ());
}
2011-06-05 14:45:39 +00:00
}
_signatures . insert ( _signatures . end (), std :: pair < int , Signature *> ( signature -> id (), signature ));
_stMem . insert ( _stMem . end (), signature -> id ());
2012-03-03 01:46:30 +00:00
2012-12-11 18:05:05 +00:00
if ( _vwd )
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "%d words ref for the signature %d" , signature -> getWords (). size (), signature -> id ());
2012-12-11 18:05:05 +00:00
}
if ( signature -> getWords (). size ())
{
signature -> setEnabled ( true );
2012-03-03 01:46:30 +00:00
}
2011-06-05 14:45:39 +00:00
}
UDEBUG ( "time = %fs" , timer . ticks ());
}
void Memory :: addSignatureToWm ( Signature * signature )
{
if ( signature )
{
2012-12-11 18:05:05 +00:00
UDEBUG ( "Inserting node %d in WM..." , signature -> id ());
2012-03-03 01:46:30 +00:00
_workingMem . insert ( signature -> id ());
2011-06-05 14:45:39 +00:00
_signatures . insert ( std :: pair < int , Signature *> ( signature -> id (), signature ));
++ _signaturesAdded ;
}
else
{
UERROR ( "Signature is null ?!?" );
}
}
const Signature * Memory :: getSignature ( int id ) const
{
return _getSignature ( id );
}
Signature * Memory :: _getSignature ( int id ) const
{
return uValue ( _signatures , id , ( Signature * ) 0 );
}
2012-12-11 18:05:05 +00:00
int Memory :: getVWDictionarySize () const
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
return _vwd -> getVisualWords (). size ();
2011-06-05 14:45:39 +00:00
}
2014-01-22 19:49:28 +00:00
void Memory :: getPose ( int locationId , Transform & pose , bool lookInDatabase ) const
2013-12-11 00:12:44 +00:00
{
const Signature * s = getSignature ( locationId );
int mapId = - 1 ;
if ( s )
{
pose = s -> getPose ();
mapId = s -> mapId ();
2014-01-22 19:49:28 +00:00
if ( pose . isNull ())
{
UERROR ( "Pose of %d is null?!?" , locationId );
}
2013-12-11 00:12:44 +00:00
}
else if ( lookInDatabase && _dbDriver )
{
_dbDriver -> getPose ( locationId , pose , mapId );
}
}
std :: map < int , Transform > Memory :: getNeighborLinks ( int signatureId , bool ignoreNeighborByLoopClosure , bool lookInDatabase ) const
{
std :: map < int , Transform > links ;
2012-03-03 01:46:30 +00:00
Signature * sTop = uValue ( _signatures , signatureId , ( Signature * ) 0 );
if ( sTop )
2011-06-05 14:45:39 +00:00
{
2012-03-03 01:46:30 +00:00
std :: list < Signature *> loops ;
loops . push_back ( sTop );
while ( loops . size ())
{
Signature * s = * loops . begin ();
loops . pop_front ();
if ( s )
{
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & neighbors = s -> getNeighbors ();
2012-12-11 18:05:05 +00:00
links . insert ( neighbors . begin (), neighbors . end ());
2012-03-03 01:46:30 +00:00
if ( ! ignoreNeighborByLoopClosure )
{
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & loopIds = s -> getLoopClosureIds ();
for ( std :: map < int , Transform >:: const_iterator iter = loopIds . begin (); iter != loopIds . end (); ++ iter )
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
if ( iter -> first > 0 && _stMem . find ( iter -> first ) == _stMem . end ())
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
loops . push_back ( uValue ( _signatures , iter -> first , ( Signature * ) 0 ));
2012-03-03 01:46:30 +00:00
}
}
}
}
}
if ( ! ignoreNeighborByLoopClosure )
{
// Check for child loop closure ids
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & childTopIds = sTop -> getChildLoopClosureIds ();
for ( std :: map < int , Transform >:: const_iterator iter = childTopIds . begin (); iter != childTopIds . end (); ++ iter )
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
if ( iter -> first > 0 && _stMem . find ( iter -> first ) == _stMem . end ())
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
loops . push_back ( uValue ( _signatures , iter -> first , ( Signature * ) 0 ));
2012-03-03 01:46:30 +00:00
}
}
while ( loops . size ())
{
Signature * s = * loops . begin ();
loops . pop_front ();
if ( s )
{
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & neighbors = s -> getNeighbors ();
2012-12-11 18:05:05 +00:00
links . insert ( neighbors . begin (), neighbors . end ());
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & childIds = s -> getChildLoopClosureIds ();
for ( std :: map < int , Transform >:: const_iterator iter = childIds . begin (); iter != childIds . end (); ++ iter )
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
if ( iter -> first > 0 && _stMem . find ( iter -> first ) == _stMem . end ())
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
loops . push_back ( uValue ( _signatures , iter -> first , ( Signature * ) 0 ));
2012-03-03 01:46:30 +00:00
}
}
}
}
}
}
else if ( lookInDatabase && _dbDriver )
{
2013-12-11 00:12:44 +00:00
std :: map < int , Transform > neighbors ;
2012-03-03 01:46:30 +00:00
_dbDriver -> loadNeighbors ( signatureId , neighbors );
2012-12-11 18:05:05 +00:00
links . insert ( neighbors . begin (), neighbors . end ());
2012-03-03 01:46:30 +00:00
}
else
{
2012-12-11 18:05:05 +00:00
UWARN ( "Cannot find signature %d in memory" , signatureId );
2012-03-03 01:46:30 +00:00
}
return links ;
}
// return map<Id,Margin>, including signatureId
// maxCheckedInDatabase = -1 means no limit to check in database (default)
// maxCheckedInDatabase = 0 means don't check in database
2012-12-11 18:05:05 +00:00
std :: map < int , int > Memory :: getNeighborsId ( int signatureId ,
2014-01-22 19:49:28 +00:00
unsigned int margin , // 0 means infinite margin
2012-03-03 01:46:30 +00:00
int maxCheckedInDatabase , // default -1 (no limit)
bool incrementMarginOnLoop , // default false
2012-12-11 18:05:05 +00:00
bool ignoreLoopIds , // default false
double * dbAccessTime
2012-03-03 01:46:30 +00:00
) const
{
2013-12-11 00:12:44 +00:00
//UDEBUG("signatureId=%d, neighborsMargin=%d", signatureId, margin);
2012-12-11 18:05:05 +00:00
if ( dbAccessTime )
{
* dbAccessTime = 0 ;
}
2012-03-03 01:46:30 +00:00
std :: map < int , int > ids ;
if ( signatureId <= 0 )
{
return ids ;
}
int nbLoadedFromDb = 0 ;
2012-12-11 18:05:05 +00:00
std :: list < int > curentMarginList ;
std :: set < int > currentMargin ;
std :: set < int > nextMargin ;
nextMargin . insert ( signatureId );
2012-03-03 01:46:30 +00:00
unsigned int m = 0 ;
2014-01-22 19:49:28 +00:00
while (( margin == 0 || m < margin ) && nextMargin . size ())
2012-03-03 01:46:30 +00:00
{
2012-12-11 18:05:05 +00:00
curentMarginList = std :: list < int > ( nextMargin . begin (), nextMargin . end ());
2012-03-03 01:46:30 +00:00
nextMargin . clear ();
2012-06-24 17:19:34 +00:00
// first pass: count number of node in current margin in database
2012-12-11 18:05:05 +00:00
for ( std :: list < int >:: iterator jter = curentMarginList . begin (); jter != curentMarginList . end (); ++ jter )
2012-06-24 17:19:34 +00:00
{
if ( ! uContains ( ids , * jter ))
{
const Signature * s = this -> getSignature ( * jter );
if ( ! s )
{
++ nbLoadedFromDb ;
}
}
}
2012-12-11 18:05:05 +00:00
for ( std :: list < int >:: iterator jter = curentMarginList . begin (); jter != curentMarginList . end (); ++ jter )
2012-03-03 01:46:30 +00:00
{
if ( ids . insert ( std :: pair < int , int > ( * jter , m )). second )
{
2012-12-11 18:05:05 +00:00
//UDEBUG("Added %d with margin %d", *jter, m);
// Look up in STM/WM if all ids are here, if not... load them from the database
2012-03-03 01:46:30 +00:00
const Signature * s = this -> getSignature ( * jter );
2013-12-11 00:12:44 +00:00
std :: map < int , Transform > tmpNeighborIds ;
std :: map < int , Transform > tmpLoopClosureIds ;
std :: map < int , Transform > tmpChildLoopClosureIds ;
const std :: map < int , Transform > * neighborIds = & tmpNeighborIds ;
const std :: map < int , Transform > * loopClosureIds = & tmpLoopClosureIds ;
const std :: map < int , Transform > * childLoopClosureIds = & tmpChildLoopClosureIds ;
2012-03-03 01:46:30 +00:00
if ( s )
{
2012-12-11 18:05:05 +00:00
neighborIds = & s -> getNeighbors ();
2012-03-03 01:46:30 +00:00
if ( ! ignoreLoopIds )
{
2012-06-24 17:19:34 +00:00
loopClosureIds = & s -> getLoopClosureIds ();
childLoopClosureIds = & s -> getChildLoopClosureIds ();
2012-03-03 01:46:30 +00:00
}
}
else if ( maxCheckedInDatabase == - 1 || ( maxCheckedInDatabase > 0 && _dbDriver && nbLoadedFromDb < maxCheckedInDatabase ))
{
2012-06-24 17:19:34 +00:00
UTimer timer ;
2013-12-11 00:12:44 +00:00
_dbDriver -> loadNeighbors ( * jter , tmpNeighborIds );
2012-03-03 01:46:30 +00:00
if ( ! ignoreLoopIds )
{
2013-12-11 00:12:44 +00:00
_dbDriver -> loadLoopClosures ( * jter , tmpLoopClosureIds , tmpChildLoopClosureIds );
2012-03-03 01:46:30 +00:00
}
2012-12-11 18:05:05 +00:00
if ( dbAccessTime )
{
* dbAccessTime += timer . getElapsedTime ();
}
2012-06-24 17:19:34 +00:00
}
// Neighbor links
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: const_iterator iter = neighborIds -> begin (); iter != neighborIds -> end (); ++ iter )
2012-06-24 17:19:34 +00:00
{
2013-12-11 00:12:44 +00:00
if ( ( ignoreLoopIds || ( loopClosureIds -> find ( iter -> first ) == loopClosureIds -> end () && childLoopClosureIds -> find ( iter -> first ) == childLoopClosureIds -> end ())) &&
! uContains ( ids , iter -> first ) &&
nextMargin . find ( iter -> first ) == nextMargin . end ())
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
nextMargin . insert ( iter -> first );
2012-03-03 01:46:30 +00:00
}
2012-06-24 17:19:34 +00:00
}
// Parent links
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: const_iterator iter = loopClosureIds -> begin (); iter != loopClosureIds -> end (); ++ iter )
2012-06-24 17:19:34 +00:00
{
2013-12-11 00:12:44 +00:00
if ( iter -> first && ! uContains ( ids , iter -> first ) /* && isInNeighborLimits(iter->first, limits)*/ )
2012-03-03 01:46:30 +00:00
{
2012-06-24 17:19:34 +00:00
if ( incrementMarginOnLoop )
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
nextMargin . insert ( iter -> first );
//UDEBUG("next of %d + %d", *jter, iter->first);
2012-03-03 01:46:30 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
if ( currentMargin . insert ( iter -> first ). second )
2012-06-24 17:19:34 +00:00
{
2013-12-11 00:12:44 +00:00
const Signature * s = this -> getSignature ( iter -> first );
2012-12-11 18:05:05 +00:00
if ( ! s )
{
// update db count because it's on current margin
++ nbLoadedFromDb ;
}
2013-12-11 00:12:44 +00:00
curentMarginList . push_back ( iter -> first );
//UDEBUG("current of %d + %d", *jter, iter->first);
2012-06-24 17:19:34 +00:00
}
2012-03-03 01:46:30 +00:00
}
}
}
2012-06-24 17:19:34 +00:00
//Child links
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: const_iterator iter = childLoopClosureIds -> begin (); iter != childLoopClosureIds -> end (); ++ iter )
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
if ( iter -> first && ! uContains ( ids , iter -> first ) /* && isInNeighborLimits(iter->first, limits)*/ )
2012-06-24 17:19:34 +00:00
{
if ( incrementMarginOnLoop )
{
2013-12-11 00:12:44 +00:00
nextMargin . insert ( iter -> first );
//UDEBUG("next of %d + %d", *jter, iter->first);
2012-06-24 17:19:34 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
if ( currentMargin . insert ( iter -> first ). second )
2012-06-24 17:19:34 +00:00
{
2013-12-11 00:12:44 +00:00
const Signature * s = this -> getSignature ( iter -> first );
2012-12-11 18:05:05 +00:00
if ( ! s )
{
// update db count because it's on current margin
++ nbLoadedFromDb ;
}
2013-12-11 00:12:44 +00:00
curentMarginList . push_back ( iter -> first );
//UDEBUG("current of %d + %d", *jter, iter->first);
2012-06-24 17:19:34 +00:00
}
}
}
2012-03-03 01:46:30 +00:00
}
}
}
++ m ;
2011-06-05 14:45:39 +00:00
}
return ids ;
}
2013-12-11 00:12:44 +00:00
void Memory :: getLoopClosureIds ( int signatureId , std :: map < int , Transform > & loopClosureIds , std :: map < int , Transform > & childLoopClosureIds , bool lookInDatabase ) const
2012-03-03 01:46:30 +00:00
{
const Signature * s = this -> getSignature ( signatureId );
loopClosureIds . clear ();
childLoopClosureIds . clear ();
if ( s )
{
loopClosureIds = s -> getLoopClosureIds ();
childLoopClosureIds = s -> getChildLoopClosureIds ();
}
else if ( lookInDatabase && _dbDriver )
{
2013-12-11 00:12:44 +00:00
_dbDriver -> loadLoopClosures ( signatureId , loopClosureIds , childLoopClosureIds );
2012-03-03 01:46:30 +00:00
}
}
2011-06-05 14:45:39 +00:00
int Memory :: getNextId ()
{
2013-06-10 18:54:11 +00:00
return ++ _idCount ;
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
int Memory :: incrementMapId ()
{
//don't increment if there is no location in the current map
const Signature * s = getLastWorkingSignature ();
if ( s && s -> mapId () == _idMapCount )
{
return ++ _idMapCount ;
}
return _idMapCount ;
}
2011-06-05 14:45:39 +00:00
int Memory :: getDatabaseMemoryUsed () const
{
int memoryUsed = 0 ;
if ( _dbDriver )
{
memoryUsed = _dbDriver -> getMemoryUsed () / ( 1024 * 1024 ); //Byte to MB
}
return memoryUsed ;
}
double Memory :: getDbSavingTime () const
{
return _dbDriver ? _dbDriver -> getEmptyTrashesTime () : 0 ;
}
std :: set < int > Memory :: getAllSignatureIds () const
{
std :: set < int > ids ;
if ( _dbDriver )
{
2012-06-24 17:19:34 +00:00
_dbDriver -> getAllNodeIds ( ids );
2013-12-11 00:12:44 +00:00
}
for ( std :: map < int , Signature *>:: const_iterator iter = _signatures . begin (); iter != _signatures . end (); ++ iter )
{
ids . insert ( iter -> first );
2011-06-05 14:45:39 +00:00
}
return ids ;
}
void Memory :: clear ()
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
2012-12-12 18:40:54 +00:00
this -> cleanUnusedWords ();
2011-06-05 14:45:39 +00:00
if ( _dbDriver )
{
_dbDriver -> emptyTrashes ();
2012-03-03 01:46:30 +00:00
_dbDriver -> join ();
2011-06-05 14:45:39 +00:00
}
// Save some stats to the db, save only when the mem is not empty
if ( _dbDriver && ( _stMem . size () || _workingMem . size ()))
{
unsigned int memSize = _workingMem . size () + _stMem . size ();
2012-06-24 17:19:34 +00:00
if ( _workingMem . size () && * _workingMem . begin () < 0 )
{
-- memSize ;
}
2011-06-05 14:45:39 +00:00
2013-12-11 00:12:44 +00:00
// this is only a safe check...not supposed to occur.
UASSERT_MSG ( memSize == _signatures . size (),
uFormat ( "The number of signatures don't match! _workingMem=%d, _stMem=%d, _signatures=%d" ,
_workingMem . size (), _stMem . size (), _signatures . size ()). c_str ());
UDEBUG ( "Adding statistics after run..." );
_dbDriver -> addStatisticsAfterRun ( memSize ,
_lastSignature ? _lastSignature -> id () : 0 ,
UProcessInfo :: getMemoryUsage (),
_dbDriver -> getMemoryUsed (),
_vwd -> getVisualWords (). size ());
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
//Get the tree root (parents)
std :: map < int , Signature *> mem = _signatures ;
for ( std :: map < int , Signature *>:: iterator i = mem . begin (); i != mem . end (); ++ i )
{
if ( i -> second )
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "deleting from the working and the short-term memory: %d" , i -> first );
2011-06-05 14:45:39 +00:00
this -> moveToTrash ( i -> second );
}
}
2012-06-24 17:19:34 +00:00
if ( _workingMem . size () != 0 && ! ( _workingMem . size () == 1 && * _workingMem . begin () == kIdVirtual ))
2011-06-05 14:45:39 +00:00
{
ULOGGER_ERROR ( "_workingMem must be empty here, size=%d" , _workingMem . size ());
}
_workingMem . clear ();
if ( _stMem . size () != 0 )
{
ULOGGER_ERROR ( "_stMem must be empty here, size=%d" , _stMem . size ());
}
_stMem . clear ();
2012-12-12 16:40:18 +00:00
if ( _signatures . size () != 0 )
{
ULOGGER_ERROR ( "_signatures must be empty here, size=%d" , _signatures . size ());
}
_signatures . clear ();
2011-06-05 14:45:39 +00:00
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
// Wait until the db trash has finished cleaning the memory
if ( _dbDriver )
{
_dbDriver -> emptyTrashes ();
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
_lastSignature = 0 ;
2014-01-22 19:49:28 +00:00
_lastGlobalLoopClosureParentId = 0 ;
_lastGlobalLoopClosureChildId = 0 ;
2011-06-05 14:45:39 +00:00
_idCount = kIdStart ;
2013-12-11 00:12:44 +00:00
_idMapCount = kIdStart ;
2011-06-05 14:45:39 +00:00
_memoryChanged = false ;
2012-12-11 18:05:05 +00:00
if ( _dbDriver )
{
_dbDriver -> join ( true );
cleanUnusedWords ();
_dbDriver -> emptyTrashes ();
}
else
{
cleanUnusedWords ();
}
if ( _vwd )
{
_vwd -> clear ();
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
}
/**
2012-03-03 01:46:30 +00:00
* Compute the likelihood of the signature with some others in the memory.
2012-06-24 17:19:34 +00:00
* Important: Assuming that all other ids are under 'signature' id.
2011-06-05 14:45:39 +00:00
* If an error occurs, the result is empty.
*/
2012-12-11 18:05:05 +00:00
std :: map < int , float > Memory :: computeLikelihood ( const Signature * signature , const std :: list < int > & ids )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
if ( ! _tfIdfLikelihoodUsed )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
UTimer timer ;
timer . start ();
std :: map < int , float > likelihood ;
if ( ! signature )
{
ULOGGER_ERROR ( "The signature is null" );
return likelihood ;
}
else if ( ids . empty ())
{
UWARN ( "ids list is empty" );
return likelihood ;
}
for ( std :: list < int >:: const_iterator iter = ids . begin (); iter != ids . end (); ++ iter )
{
float sim = 0.0f ;
if ( * iter > 0 )
{
const Signature * sB = this -> getSignature ( * iter );
if ( ! sB )
{
UFATAL ( "Signature %d not found in WM ?!?" , * iter );
}
sim = signature -> compareTo ( sB );
}
likelihood . insert ( likelihood . end (), std :: pair < int , float > ( * iter , sim ));
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "compute likelihood... %f s" , timer . ticks ());
2011-06-05 14:45:39 +00:00
return likelihood ;
}
2012-12-11 18:05:05 +00:00
else
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
// TODO cleanup , old way...
UTimer timer ;
timer . start ();
std :: map < int , float > likelihood ;
std :: map < int , float > calculatedWordsRatio ;
if ( ! signature )
{
ULOGGER_ERROR ( "The signature is null" );
return likelihood ;
}
else if ( ids . empty ())
{
UWARN ( "ids list is empty" );
return likelihood ;
}
for ( std :: list < int >:: const_iterator iter = ids . begin (); iter != ids . end (); ++ iter )
{
likelihood . insert ( likelihood . end (), std :: pair < int , float > ( * iter , 0.0f ));
}
const std :: list < int > & wordIds = uUniqueKeys ( signature -> getWords ());
float nwi ; // nwi is the number of a specific word referenced by a place
float ni ; // ni is the total of words referenced by a place
float nw ; // nw is the number of places referenced by a specific word
float N ; // N is the total number of places
float logNnw ;
const VisualWord * vw ;
N = this -> getSignatures (). size ();
if ( N )
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "processing... " );
2012-12-11 18:05:05 +00:00
// Pour chaque mot dans la signature SURF
for ( std :: list < int >:: const_iterator i = wordIds . begin (); i != wordIds . end (); ++ i )
{
// "Inverted index" - Pour chaque endroit contenu dans chaque mot
vw = _vwd -> getWord ( * i );
if ( vw )
{
const std :: map < int , int > & refs = vw -> getReferences ();
nw = refs . size ();
if ( nw )
{
logNnw = log10 ( N / nw );
if ( logNnw )
{
for ( std :: map < int , int >:: const_iterator j = refs . begin (); j != refs . end (); ++ j )
{
std :: map < int , float >:: iterator iter = likelihood . find ( j -> first );
if ( iter != likelihood . end ())
{
nwi = j -> second ;
ni = this -> getNi ( j -> first );
if ( ni != 0 )
{
2013-12-11 00:12:44 +00:00
//UDEBUG("%d, %f %f %f %f", vw->id(), logNnw, nwi, ni, ( nwi * logNnw ) / ni);
2012-12-11 18:05:05 +00:00
iter -> second += ( nwi * logNnw ) / ni ;
}
}
}
}
}
}
}
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "compute likelihood %f s" , timer . ticks ());
2012-03-03 01:46:30 +00:00
return likelihood ;
}
2011-06-05 14:45:39 +00:00
}
// Weights of the signatures in the working memory <signature id, weight>
std :: map < int , int > Memory :: getWeights () const
{
std :: map < int , int > weights ;
2012-03-03 01:46:30 +00:00
for ( std :: set < int >:: const_iterator iter = _workingMem . begin (); iter != _workingMem . end (); ++ iter )
2011-06-05 14:45:39 +00:00
{
2012-06-24 17:19:34 +00:00
if ( * iter > 0 )
2012-03-03 01:46:30 +00:00
{
2012-06-24 17:19:34 +00:00
const Signature * s = this -> getSignature ( * iter );
if ( ! s )
{
UFATAL ( "Location %d must exist in memory" , * iter );
}
weights . insert ( weights . end (), std :: make_pair ( * iter , s -> getWeight ()));
2012-03-03 01:46:30 +00:00
}
2012-12-11 18:05:05 +00:00
else
{
weights . insert ( weights . end (), std :: make_pair ( * iter , - 1 ));
}
2011-06-05 14:45:39 +00:00
}
return weights ;
}
2013-12-11 00:12:44 +00:00
std :: list < int > Memory :: forget ( const std :: set < int > & ignoredIds )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
std :: list < int > signaturesRemoved ;
2012-12-11 18:05:05 +00:00
if ( _vwd -> isIncremental ())
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
int newWords = 0 ;
int wordsRemoved = 0 ;
// Get how many new words added for the last run...
newWords = _vwd -> getNotIndexedWordsCount ();
// So we need to remove at least "newWords" words from the
// dictionary to respect the limit.
while ( wordsRemoved < newWords )
{
std :: list < Signature *> signatures = this -> getRemovableSignatures ( 1 , ignoredIds );
if ( signatures . size ())
{
Signature * s = dynamic_cast < Signature *> ( signatures . front ());
if ( s )
{
2013-12-11 00:12:44 +00:00
signaturesRemoved . push_back ( s -> id ());
2012-12-11 18:05:05 +00:00
this -> moveToTrash ( s );
wordsRemoved = _vwd -> getUnusedWordsSize ();
}
else
{
break ;
}
}
else
{
break ;
}
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "newWords=%d, wordsRemoved=%d" , newWords , wordsRemoved );
2011-06-05 14:45:39 +00:00
}
2012-12-11 18:05:05 +00:00
else
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2012-12-11 18:05:05 +00:00
// Remove one more than total added during the iteration
std :: list < Signature *> signatures = getRemovableSignatures ( _signaturesAdded + 1 , ignoredIds );
for ( std :: list < Signature *>:: iterator iter = signatures . begin (); iter != signatures . end (); ++ iter )
{
2013-12-11 00:12:44 +00:00
signaturesRemoved . push_back (( * iter ) -> id ());
2012-12-11 18:05:05 +00:00
// When a signature is deleted, it notifies the memory
// and it is removed from the memory list
this -> moveToTrash ( * iter );
}
UDEBUG ( "signaturesRemoved=%d, _signaturesAdded=%d" , ( int ) signatures . size (), _signaturesAdded );
}
return signaturesRemoved ;
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
std :: list < int > Memory :: cleanup ( const std :: list < int > & ignoredIds )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
std :: list < int > signaturesRemoved ;
2012-03-03 01:46:30 +00:00
// bad signature
2014-01-15 20:41:58 +00:00
if (( _lastSignature -> isBadSignature () && _badSignaturesIgnored ) || ! _incrementalMemory )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
if ( _lastSignature -> isBadSignature ())
{
UDEBUG ( "Bad signature! %d" , _lastSignature -> id ());
}
signaturesRemoved . push_back ( _lastSignature -> id ());
2013-06-06 13:41:49 +00:00
moveToTrash ( _lastSignature , _incrementalMemory );
2011-06-05 14:45:39 +00:00
}
return signaturesRemoved ;
}
void Memory :: emptyTrash ()
{
if ( _dbDriver )
{
_dbDriver -> emptyTrashes ( true );
}
}
void Memory :: joinTrashThread ()
{
if ( _dbDriver )
{
2012-06-24 17:19:34 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
_dbDriver -> join ();
2012-06-24 17:19:34 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
}
}
2012-03-03 01:46:30 +00:00
class WeightIdKey
{
public :
WeightIdKey ( int w , int i ) :
weight ( w ),
id ( i ) {}
bool operator < ( const WeightIdKey & k ) const
{
if ( weight < k . weight )
{
return true ;
}
else if ( weight == k . weight )
{
if ( id < k . id )
{
return true ;
}
}
return false ;
}
int weight , id ;
};
std :: list < Signature *> Memory :: getRemovableSignatures ( int count , const std :: set < int > & ignoredIds )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
//UDEBUG("");
2012-03-03 01:46:30 +00:00
std :: list < Signature *> removableSignatures ;
std :: map < WeightIdKey , Signature *> signatureMap ;
2011-06-05 14:45:39 +00:00
// Find the last index to check...
2012-03-03 01:46:30 +00:00
const std :: set < int > & wm = _workingMem ;
2013-12-11 00:12:44 +00:00
UDEBUG ( "mem.size()=%d, ignoredIds.size()=%d" , wm . size (), ignoredIds . size ());
2011-06-05 14:45:39 +00:00
if ( wm . size ())
{
int recentWmMaxSize = _recentWmRatio * float ( wm . size ());
bool recentWmImmunized = false ;
// look for the position of the lastLoopClosureId in WM
int currentRecentWmSize = 0 ;
2014-01-22 19:49:28 +00:00
if ( _lastGlobalLoopClosureParentId > 0 && _stMem . find ( _lastGlobalLoopClosureParentId ) == _stMem . end ())
2011-06-05 14:45:39 +00:00
{
// If set, it must be in WM
2014-01-22 19:49:28 +00:00
std :: set < int >:: const_iterator iter = _workingMem . find ( _lastGlobalLoopClosureParentId );
2011-06-05 14:45:39 +00:00
while ( iter != _workingMem . end ())
{
++ currentRecentWmSize ;
++ iter ;
}
2012-03-03 01:46:30 +00:00
if ( currentRecentWmSize > 1 && currentRecentWmSize < recentWmMaxSize )
2011-06-05 14:45:39 +00:00
{
recentWmImmunized = true ;
}
else if ( currentRecentWmSize == 0 && _workingMem . size () > 1 )
{
2014-01-22 19:49:28 +00:00
UERROR ( "Last loop closure id not found in WM (%d)" , _lastGlobalLoopClosureParentId );
2011-06-05 14:45:39 +00:00
}
2014-01-22 19:49:28 +00:00
UDEBUG ( "currentRecentWmSize=%d, recentWmMaxSize=%d, _recentWmRatio=%f, end recent wM = %d" , currentRecentWmSize , recentWmMaxSize , _recentWmRatio , _lastGlobalLoopClosureParentId );
2011-06-05 14:45:39 +00:00
}
2012-06-24 17:19:34 +00:00
// Ignore neighbor of the last location in STM (for neighbor links redirection issue during Rehearsal).
Signature * lastInSTM = 0 ;
if ( _stMem . size ())
{
lastInSTM = _signatures . at ( * _stMem . begin ());
}
2012-03-03 01:46:30 +00:00
for ( std :: set < int >:: const_iterator memIter = wm . begin (); memIter != wm . end (); ++ memIter )
2011-06-05 14:45:39 +00:00
{
2014-01-22 19:49:28 +00:00
if ( ( recentWmImmunized && * memIter > _lastGlobalLoopClosureParentId ) ||
* memIter == _lastGlobalLoopClosureParentId )
2011-06-05 14:45:39 +00:00
{
2012-03-03 01:46:30 +00:00
// ignore recent memory
2011-06-05 14:45:39 +00:00
}
2012-06-24 17:19:34 +00:00
else if ( * memIter > 0 && ignoredIds . find ( * memIter ) == ignoredIds . end () && ( ! lastInSTM || ! lastInSTM -> hasNeighbor ( * memIter )))
2011-06-05 14:45:39 +00:00
{
2012-03-03 01:46:30 +00:00
Signature * s = this -> _getSignature ( * memIter );
2011-06-05 14:45:39 +00:00
if ( s )
{
2012-03-03 01:46:30 +00:00
// Its loop closures must not be in STM to be removable, rehearsal issue
bool foundInSTM = false ;
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: const_iterator iter = s -> getLoopClosureIds (). begin (); iter != s -> getLoopClosureIds (). end (); ++ iter )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
if ( _stMem . find ( iter -> first ) != _stMem . end ())
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "Ignored %d because it has a parent (%d) in STM" , s -> id (), iter -> first );
2012-03-03 01:46:30 +00:00
foundInSTM = true ;
2011-06-05 14:45:39 +00:00
break ;
}
}
2012-06-24 17:19:34 +00:00
// Its neighbors must not be in STM to be removable, rehearsal issue
if ( ! foundInSTM )
{
for ( std :: set < int >:: iterator iter = _stMem . begin (); iter != _stMem . end (); ++ iter )
{
if ( s -> hasNeighbor ( * iter ))
{
2012-12-11 18:05:05 +00:00
UDEBUG ( "Ignored %d because it has a neighbor (%d) in STM" , s -> id (), * iter );
2012-06-24 17:19:34 +00:00
foundInSTM = true ;
break ;
}
}
}
2012-03-03 01:46:30 +00:00
if ( ! foundInSTM )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
// less weighted signature priority to be transferred
2012-03-03 01:46:30 +00:00
signatureMap . insert ( std :: make_pair ( WeightIdKey ( s -> getWeight (), s -> id ()), s ));
2011-06-05 14:45:39 +00:00
}
}
else
{
ULOGGER_ERROR ( "Not supposed to occur!!!" );
}
}
else
{
2013-12-11 00:12:44 +00:00
//UDEBUG("Ignoring id %d", memIter->first);
2011-06-05 14:45:39 +00:00
}
}
2012-03-03 01:46:30 +00:00
int recentWmCount = 0 ;
std :: set < int > addedSignatures ;
// make the list of removable signatures
// Criteria : Weight -> ID
UDEBUG ( "signatureMap.size()=%d" , ( int ) signatureMap . size ());
for ( std :: map < WeightIdKey , Signature *>:: iterator iter = signatureMap . begin ();
iter != signatureMap . end ();
++ iter )
{
bool removable = true ;
if ( removable )
{
if ( ! recentWmImmunized )
{
UDEBUG ( "weight=%d, id=%d, lcCount=%d, lcId=%d, childId=%d" ,
iter -> first . weight ,
iter -> second -> id (),
int ( iter -> second -> getLoopClosureIds (). size ()),
2013-12-11 00:12:44 +00:00
iter -> second -> getLoopClosureIds (). size () ? iter -> second -> getLoopClosureIds (). rbegin () -> first : 0 ,
iter -> second -> getChildLoopClosureIds (). size () ? iter -> second -> getChildLoopClosureIds (). rbegin () -> first : 0 );
2012-03-03 01:46:30 +00:00
removableSignatures . push_back ( iter -> second );
addedSignatures . insert ( iter -> second -> id ());
2014-01-22 19:49:28 +00:00
if ( iter -> second -> id () > _lastGlobalLoopClosureParentId )
2012-03-03 01:46:30 +00:00
{
++ recentWmCount ;
if ( currentRecentWmSize - recentWmCount < recentWmMaxSize )
{
UDEBUG ( "switched recentWmImmunized" );
recentWmImmunized = true ;
}
}
}
2014-01-22 19:49:28 +00:00
else if ( iter -> second -> id () < _lastGlobalLoopClosureParentId )
2012-03-03 01:46:30 +00:00
{
UDEBUG ( "weight=%d, id=%d, lcCount=%d, lcId=%d, childId=%d" ,
iter -> first . weight ,
iter -> second -> id (),
int ( iter -> second -> getLoopClosureIds (). size ()),
2013-12-11 00:12:44 +00:00
iter -> second -> getLoopClosureIds (). size () ? iter -> second -> getLoopClosureIds (). rbegin () -> first : 0 ,
iter -> second -> getChildLoopClosureIds (). size () ? iter -> second -> getChildLoopClosureIds (). rbegin () -> first : 0 );
2012-03-03 01:46:30 +00:00
removableSignatures . push_back ( iter -> second );
addedSignatures . insert ( iter -> second -> id ());
}
if ( removableSignatures . size () >= ( unsigned int ) count )
{
break ;
}
}
}
2011-06-05 14:45:39 +00:00
}
else
{
ULOGGER_WARN ( "not enough signatures to get an old one..." );
}
2012-03-03 01:46:30 +00:00
return removableSignatures ;
2011-06-05 14:45:39 +00:00
}
2013-02-17 22:27:31 +00:00
void Memory :: moveToTrash ( Signature * s , bool saveToDatabase )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "id=%d" , s ? s -> id () : 0 );
2011-06-05 14:45:39 +00:00
if ( s )
{
2014-01-22 20:42:14 +00:00
// If not saved to database or it is a bad signature (not saved), remove links!
if ( ! saveToDatabase || ( ! s -> isSaved () && s -> isBadSignature () && _badSignaturesIgnored ))
2013-12-11 00:12:44 +00:00
{
UASSERT_MSG ( this -> isInSTM ( s -> id ()),
uFormat ( "Deleting location (%d) outside the STM is not implemented!" , s -> id ()). c_str ());
const std :: map < int , Transform > & neighbors = s -> getNeighbors ();
for ( std :: map < int , Transform >:: const_iterator iter = neighbors . begin (); iter != neighbors . end (); ++ iter )
{
Signature * n = this -> _getSignature ( iter -> first );
// neighbor to s
if ( n )
{
if ( iter -> first > s -> id () && ( n -> getNeighbors (). size () > 1 || ! n -> hasNeighbor ( s -> id ())))
{
UWARN ( "Neighbor %d of %d is newer, removing neighbor link may split the map!" , iter -> first , s -> id ());
}
n -> removeNeighbor ( s -> id ());
if ( s == _lastSignature )
{
_lastSignature = n ;
}
}
else
{
UERROR ( "neighbor %d of %d not in WM/STM?!?" , iter -> first , s -> id ());
}
}
s -> removeNeighbors ();
std :: map < int , Transform > children = s -> getChildLoopClosureIds ();
for ( std :: map < int , Transform >:: const_iterator iter = children . begin (); iter != children . end (); ++ iter )
{
Signature * child = _getSignature ( iter -> first );
if ( child )
{
child -> removeLoopClosureId ( s -> id ());
child -> setWeight ( child -> getWeight () + s -> getWeight ()); // copy weight
}
else
{
UERROR ( "loop child %d of %d not in WM/STM?!?" , iter -> first , s -> id ());
}
s -> removeChildLoopClosureId ( iter -> first );
}
std :: map < int , Transform > parents = s -> getLoopClosureIds ();
for ( std :: map < int , Transform >:: const_iterator iter = parents . begin (); iter != parents . end (); ++ iter )
{
Signature * p = _getSignature ( iter -> first );
if ( p )
{
p -> removeChildLoopClosureId ( s -> id ());
}
else
{
UERROR ( "loop parent %d of %d not in WM/STM?!?" , iter -> first , s -> id ());
}
s -> removeLoopClosureId ( iter -> first );
}
s -> setWeight ( 0 );
}
2013-03-02 21:53:47 +00:00
this -> disableWordsRef ( s -> id (), saveToDatabase );
2012-12-11 18:05:05 +00:00
2011-06-05 14:45:39 +00:00
_workingMem . erase ( s -> id ());
_stMem . erase ( s -> id ());
_signatures . erase ( s -> id ());
2012-03-03 01:46:30 +00:00
if ( _lastSignature == s )
2011-06-05 14:45:39 +00:00
{
2012-03-03 01:46:30 +00:00
_lastSignature = 0 ;
2013-12-11 00:12:44 +00:00
if ( _stMem . size ())
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
_lastSignature = this -> _getSignature ( * _stMem . rbegin ());
2011-06-05 14:45:39 +00:00
}
}
2013-02-17 22:27:31 +00:00
if ( saveToDatabase &&
_dbDriver &&
2012-03-03 01:46:30 +00:00
s -> id () > 0 )
2011-06-05 14:45:39 +00:00
{
_dbDriver -> asyncSave ( s );
}
else
{
delete s ;
}
}
}
2013-06-10 18:54:11 +00:00
int Memory :: getLastSignatureId () const
{
return _idCount ;
}
const Signature * Memory :: getLastWorkingSignature () const
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2011-06-05 14:45:39 +00:00
return _lastSignature ;
}
2013-08-20 20:37:24 +00:00
void Memory :: deleteLocation ( int locationId )
{
2013-12-11 00:12:44 +00:00
UINFO ( "Deleting location %d" , locationId );
2013-08-20 20:37:24 +00:00
Signature * location = _getSignature ( locationId );
if ( location )
{
this -> moveToTrash ( location , false );
2013-01-28 18:13:56 +00:00
}
}
2013-12-11 00:12:44 +00:00
void Memory :: rejectLoopClosure ( int oldId , int newId )
2013-01-29 15:48:36 +00:00
{
2013-12-11 00:12:44 +00:00
Signature * oldS = this -> _getSignature ( oldId );
Signature * newS = this -> _getSignature ( newId );
if ( oldS && newS )
2013-01-29 15:48:36 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "removing loop closure from location %d" , newS -> id ());
2013-01-29 15:48:36 +00:00
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & children = newS -> getChildLoopClosureIds ();
for ( std :: map < int , Transform >:: const_iterator iter = children . begin (); iter != children . end (); ++ iter )
2013-01-29 15:48:36 +00:00
{
2013-12-11 00:12:44 +00:00
if ( iter -> first == oldId )
2013-01-29 15:48:36 +00:00
{
2013-12-11 00:12:44 +00:00
oldS -> removeLoopClosureId ( newS -> id ());
oldS -> setWeight ( oldS -> getWeight () + 1 );
newS -> removeChildLoopClosureId ( iter -> first );
newS -> setWeight ( newS -> getWeight () > 0 ? newS -> getWeight () - 1 : 0 );
break ;
2013-01-29 15:48:36 +00:00
}
}
2014-01-22 19:49:28 +00:00
if ( newS -> getChildLoopClosureIds (). size () == 0 && newId == _lastGlobalLoopClosureParentId )
2013-12-11 00:12:44 +00:00
{
2014-01-22 19:49:28 +00:00
_lastGlobalLoopClosureParentId = 0 ;
_lastGlobalLoopClosureChildId = 0 ;
2013-12-11 00:12:44 +00:00
}
}
else
{
if ( ! newS )
{
UERROR ( "Signature %d is not in working memory... cannot remove loop closure links." , newS -> id ());
}
if ( ! oldS )
{
UERROR ( "Signature %d is not in working memory... cannot remove loop closure links." , oldS -> id ());
}
2013-01-29 15:48:36 +00:00
}
}
2013-12-11 00:12:44 +00:00
// compute transform newId -> oldId
Transform Memory :: computeVisualTransform ( int oldId , int newId ) const
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
const Signature * oldS = this -> getSignature ( oldId );
const Signature * newS = this -> getSignature ( newId );
Transform transform ;
if ( oldS && newId )
{
return computeVisualTransform ( * oldS , * newS );
}
return Transform ();
}
// compute transform newId -> oldId
Transform Memory :: computeVisualTransform ( const Signature & oldS , const Signature & newS ) const
{
Transform transform ;
// Guess transform from visual words
if ( ! oldS . getWords3 (). empty () && ! newS . getWords3 (). empty ())
{
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr inliersOld ( new pcl :: PointCloud < pcl :: PointXYZ > );
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr inliersNew ( new pcl :: PointCloud < pcl :: PointXYZ > );
util3d :: findCorrespondences (
oldS . getWords3 (),
newS . getWords3 (),
* inliersOld ,
* inliersNew ,
_bowMaxDepth );
if (( int ) inliersOld -> size () >= _bowMinInliers )
{
UDEBUG ( "Correspondences = %d" , ( int ) inliersOld -> size ());
2014-01-22 19:49:28 +00:00
2013-12-11 00:12:44 +00:00
int inliersCount = 0 ;
Transform t = util3d :: transformFromXYZCorrespondences (
inliersOld ,
inliersNew ,
_bowInlierDistance ,
_bowIterations ,
& inliersCount );
if ( ! t . isNull () && inliersCount >= _bowMinInliers )
{
transform = t ;
}
else if ( inliersCount < _bowMinInliers )
{
2014-01-08 16:11:00 +00:00
UINFO ( "Not enough inliers %d/%d between %d and %d" , inliersCount , _bowMinInliers , oldS . id (), newS . id ());
2013-12-11 00:12:44 +00:00
}
}
else
{
2014-01-08 16:11:00 +00:00
UDEBUG ( "Not enough inliers %d/%d between %d and %d" , ( int ) inliersOld -> size (), _bowMinInliers , oldS . id (), newS . id ());
2013-12-11 00:12:44 +00:00
}
}
else if ( ! oldS . isBadSignature () && ! newS . isBadSignature ())
{
UERROR ( "Words 3D empty?!?" );
}
return transform ;
}
// compute transform newId -> oldId
2014-01-22 19:49:28 +00:00
Transform Memory :: computeIcpTransform ( int oldId , int newId , Transform guess , bool icp3D )
2013-12-11 00:12:44 +00:00
{
Signature * oldS = this -> _getSignature ( oldId );
Signature * newS = this -> _getSignature ( newId );
if ( oldS && newS && _dbDriver )
{
std :: list < Signature *> depthToLoad ;
std :: set < int > added ;
2014-01-22 19:49:28 +00:00
if ( icp3D )
2013-12-11 00:12:44 +00:00
{
//Depth required, if not in RAM, load it from LTM
if ( oldS -> getDepth (). empty ())
{
depthToLoad . push_back ( oldS );
added . insert ( oldS -> id ());
}
if ( newS -> getDepth (). empty ())
{
depthToLoad . push_back ( newS );
added . insert ( newS -> id ());
}
}
2014-01-22 19:49:28 +00:00
else
2013-12-11 00:12:44 +00:00
{
//Depth required, if not in RAM, load it from LTM
if ( oldS -> getDepth2D (). size () == 0 && added . find ( oldS -> id ()) == added . end ())
{
depthToLoad . push_back ( oldS );
}
if ( newS -> getDepth2D (). size () == 0 && added . find ( newS -> id ()) == added . end ())
{
depthToLoad . push_back ( newS );
}
}
if ( depthToLoad . size ())
{
_dbDriver -> loadNodeData ( depthToLoad , true );
}
}
Transform t ;
if ( oldS && newS )
{
2014-01-22 19:49:28 +00:00
t = computeIcpTransform ( * oldS , * newS , guess , icp3D );
2013-12-11 00:12:44 +00:00
}
return t ;
}
// get transform from the new to old node
2014-01-22 19:49:28 +00:00
Transform Memory :: computeIcpTransform ( const Signature & oldS , const Signature & newS , Transform guess , bool icp3D ) const
2013-12-11 00:12:44 +00:00
{
if ( guess . isNull ())
{
//Make a guess using odometry
guess = oldS . getPose (). inverse () * newS . getPose ();
UASSERT_MSG ( oldS . mapId () == newS . mapId (), "Compute ICP from two different maps is not implemented!" );
}
else
{
guess = guess . inverse (); // from pose to cloud data
}
UDEBUG ( "Guess transform = %s" , guess . prettyPrint (). c_str ());
Transform transform ;
// ICP with guess transform
2014-01-22 19:49:28 +00:00
if ( icp3D )
2013-12-11 00:12:44 +00:00
{
UDEBUG ( "3D ICP" );
util3d :: CompressionThread ctOld ( oldS . getDepth (), true );
util3d :: CompressionThread ctNew ( newS . getDepth (), true );
ctOld . start ();
ctNew . start ();
ctOld . join ();
ctNew . join ();
cv :: Mat oldDepth = ctOld . getUncompressedData ();
cv :: Mat newDepth = ctNew . getUncompressedData ();
if ( ! oldDepth . empty () && ! newDepth . empty ())
{
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr oldCloudXYZ = util3d :: getICPReadyCloud (
oldDepth ,
oldS . getDepthConstant (),
_icpDecimation ,
_icpMaxDepth ,
_icpVoxelSize ,
_icpSamples ,
oldS . getLocalTransform ());
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr newCloudXYZ = util3d :: getICPReadyCloud (
newDepth ,
newS . getDepthConstant (),
_icpDecimation ,
_icpMaxDepth ,
_icpVoxelSize ,
_icpSamples ,
guess * newS . getLocalTransform ());
pcl :: PointCloud < pcl :: PointNormal >:: Ptr oldCloud = util3d :: computeNormals ( oldCloudXYZ );
pcl :: PointCloud < pcl :: PointNormal >:: Ptr newCloud = util3d :: computeNormals ( newCloudXYZ );
std :: vector < int > indices ;
newCloud = util3d :: removeNaNNormalsFromPointCloud ( newCloud );
oldCloud = util3d :: removeNaNNormalsFromPointCloud ( oldCloud );
// 3D
double fitness = 0 ;
bool hasConverged = false ;
Transform icpT ;
if ( newCloud -> size () && oldCloud -> size ())
{
icpT = util3d :: icpPointToPlane ( newCloud ,
oldCloud ,
_icpMaxCorrespondenceDistance ,
_icpMaxIterations ,
hasConverged ,
fitness );
}
else
{
UWARN ( "Clouds empty ?!?" );
}
//pcl::io::savePCDFile("old.pcd", *oldCloud);
//pcl::io::savePCDFile("newguess.pcd", *newCloud);
//newCloud = util3d::transformPointCloud(newCloud, icpT);
//pcl::io::savePCDFile("newicp.pcd", *newCloud);
UDEBUG ( "fitness=%f" , fitness );
if ( hasConverged && ( _icpMaxFitness == 0 || fitness < _icpMaxFitness ))
{
2014-01-22 19:49:28 +00:00
transform = icpT * guess ;
2013-12-11 00:12:44 +00:00
transform = transform . inverse ();
}
else
{
UWARN ( "Cannot compute transform (hasConverged=%s fitness=%f/%f)" ,
hasConverged ? "true" : "false" , fitness , _icpMaxFitness );
}
}
else
{
UERROR ( "Depths 3D empty?!?" );
}
}
2014-01-22 19:49:28 +00:00
else // icp 2D
2013-12-11 00:12:44 +00:00
{
UDEBUG ( "2D ICP" );
// We are 2D here, make sure the guess has only YAW rotation
float x , y , z , r , p , yaw ;
guess . getTranslationAndEulerAngles ( x , y , z , r , p , yaw );
guess = util3d :: transformFromEigen3f ( pcl :: getTransformation ( x , y , 0 , 0 , 0 , yaw ));
if ( r != 0 || p != 0 )
{
2014-02-19 19:07:49 +00:00
UINFO ( "2D ICP: Dropping z (%f), roll (%f) and pitch (%f) rotation!" , z , r , p );
2013-12-11 00:12:44 +00:00
}
util3d :: CompressionThread ctOld ( oldS . getDepth2D (), false );
util3d :: CompressionThread ctNew ( newS . getDepth2D (), false );
ctOld . start ();
ctNew . start ();
ctOld . join ();
ctNew . join ();
cv :: Mat oldDepth2D = ctOld . getUncompressedData ();
cv :: Mat newDepth2D = ctNew . getUncompressedData ();
if ( ! oldDepth2D . empty () && ! newDepth2D . empty ())
{
// 2D
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr oldCloud = util3d :: cvMat2Cloud ( oldDepth2D );
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr newCloud = util3d :: cvMat2Cloud ( newDepth2D , guess );
2014-01-22 19:49:28 +00:00
//voxelize
if ( _icp2VoxelSize > 0.0f )
{
oldCloud = util3d :: voxelize ( oldCloud , _icp2VoxelSize );
newCloud = util3d :: voxelize ( newCloud , _icp2VoxelSize );
}
2013-12-11 00:12:44 +00:00
double fitness = 0.0f ;
bool hasConverged = false ;
Transform icpT ;
float correspondencesRatio = - 1.0f ;
if ( newCloud -> size () && oldCloud -> size ())
{
icpT = util3d :: icp2D ( newCloud ,
oldCloud ,
_icp2MaxCorrespondenceDistance ,
_icp2MaxIterations ,
hasConverged ,
fitness );
2014-01-22 19:49:28 +00:00
//pcl::io::savePCDFile("lccold.pcd", *oldCloud);
//pcl::io::savePCDFile("lccnewguess.pcd", *newCloud);
2013-12-11 00:12:44 +00:00
newCloud = util3d :: transformPointCloud ( newCloud , icpT );
2014-01-22 19:49:28 +00:00
//pcl::io::savePCDFile("lccnewicp.pcd", *newCloud);
2013-12-11 00:12:44 +00:00
// verify if there are enough correspondences
int correspondences = util3d :: getCorrespondencesCount ( newCloud , oldCloud , _icp2MaxCorrespondenceDistance );
2014-02-11 23:04:22 +00:00
correspondencesRatio = float ( correspondences ) / float ( oldCloud -> size () > newCloud -> size () ? oldCloud -> size () : newCloud -> size ());
2013-12-11 00:12:44 +00:00
UDEBUG ( "hasConverged=%s, fitness=%f, correspondences=%d/%d (%f%%)" ,
hasConverged ? "true" : "false" ,
fitness ,
correspondences ,
( int ) oldCloud -> size (),
correspondencesRatio * 100.0f );
}
else
{
UWARN ( "Clouds empty ?!?" );
}
if ( hasConverged &&
( _icp2MaxFitness == 0 || fitness < _icp2MaxFitness ) &&
correspondencesRatio >= _icp2CorrespondenceRatio )
{
2014-01-22 19:49:28 +00:00
transform = icpT * guess ;
2013-12-11 00:12:44 +00:00
transform = transform . inverse ();
}
else
{
UWARN ( "Cannot compute transform (hasConverged=%s fitness=%f/%f correspondencesRatio=%f/%f)" ,
hasConverged ? "true" : "false" , fitness , _icpMaxFitness , correspondencesRatio , _icp2CorrespondenceRatio );
}
}
else
{
UERROR ( "Depths 2D empty?!?" );
}
}
return transform ;
}
2014-01-22 19:49:28 +00:00
// poses of newId and oldId must be in "poses"
2013-12-11 00:12:44 +00:00
Transform Memory :: computeScanMatchingTransform (
int newId ,
int oldId ,
const std :: map < int , Transform > & poses )
{
// make sure that all depth2D are loaded
std :: list < Signature *> depthToLoad ;
for ( std :: map < int , Transform >:: const_iterator iter = poses . begin (); iter != poses . end (); ++ iter )
{
Signature * s = _getSignature ( iter -> first );
UASSERT ( s != 0 );
if ( s -> getDepth2D (). size () == 0 )
{
depthToLoad . push_back ( s );
}
}
if ( depthToLoad . size () && _dbDriver )
{
_dbDriver -> loadNodeData ( depthToLoad , true );
}
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr assembledOldClouds ( new pcl :: PointCloud < pcl :: PointXYZ > );
for ( std :: map < int , Transform >:: const_iterator iter = poses . begin (); iter != poses . end (); ++ iter )
{
if ( iter -> first != newId )
{
const Signature * s = this -> getSignature ( iter -> first );
if ( s -> getDepth2D (). size ())
{
* assembledOldClouds += * util3d :: cvMat2Cloud ( util3d :: uncompressData ( s -> getDepth2D ()), iter -> second );
}
else
{
UWARN ( "Depth2D not found for signature %d" , iter -> first );
}
}
}
//voxelize
2014-01-22 19:49:28 +00:00
if ( assembledOldClouds -> size () && _icp2VoxelSize > 0.0f )
2013-12-11 00:12:44 +00:00
{
2014-01-22 19:49:28 +00:00
assembledOldClouds = util3d :: voxelize ( assembledOldClouds , _icp2VoxelSize );
2013-12-11 00:12:44 +00:00
}
// get the new cloud
const Signature * newS = getSignature ( newId );
pcl :: PointCloud < pcl :: PointXYZ >:: Ptr newCloud ;
UASSERT ( uContains ( poses , newId ));
newCloud = util3d :: cvMat2Cloud ( util3d :: uncompressData ( newS -> getDepth2D ()), poses . at ( newId ));
//voxelize
2014-01-22 19:49:28 +00:00
if ( newCloud -> size () && _icp2VoxelSize > 0.0f )
2013-12-11 00:12:44 +00:00
{
2014-01-22 19:49:28 +00:00
newCloud = util3d :: voxelize ( newCloud , _icp2VoxelSize );
2013-12-11 00:12:44 +00:00
}
//pcl::io::savePCDFile("old.pcd", *assembledOldClouds);
//pcl::io::savePCDFile("new.pcd", *newCloud);
Transform transform ;
if ( assembledOldClouds -> size () && newCloud -> size ())
{
double fitness = 0.0f ;
bool hasConverged = false ;
Transform icpT = util3d :: icp2D ( newCloud ,
assembledOldClouds ,
_icp2MaxCorrespondenceDistance ,
_icp2MaxIterations ,
hasConverged ,
fitness );
UDEBUG ( "icpT=%s" , icpT . prettyPrint (). c_str ());
newCloud = util3d :: transformPointCloud ( newCloud , icpT );
//pcl::io::savePCDFile("newCorrected.pcd", *newCloud);
// verify if there enough correspondences
int correspondences = util3d :: getCorrespondencesCount ( newCloud , assembledOldClouds , _icp2MaxCorrespondenceDistance );
float correspondencesRatio = float ( correspondences ) / float ( newCloud -> size ());
UDEBUG ( "fitness=%f, correspondences=%d/%d (%f%%)" ,
fitness ,
correspondences ,
( int ) newCloud -> size (),
correspondencesRatio );
if ( hasConverged &&
( _icp2MaxFitness == 0 || fitness < _icp2MaxFitness ) &&
correspondencesRatio >= _icp2CorrespondenceRatio )
{
transform = poses . at ( newId ). inverse () * icpT . inverse () * poses . at ( oldId );
//newCloud = util3d::cvMat2Cloud(util3d::uncompressData(newS->getDepth2D()), poses.at(oldId)*transform.inverse());
//pcl::io::savePCDFile("newFinal.pcd", *newCloud);
}
else
{
UWARN ( "Constraints failed... hasConverged=%s, fitness=%f, correspondences=%d/%d (%f%%)" ,
hasConverged ? "true" : "false" ,
fitness ,
correspondences ,
( int ) newCloud -> size (),
correspondencesRatio );
}
}
return transform ;
}
// Transform from new to old
2014-01-22 19:49:28 +00:00
bool Memory :: addLoopClosureLink ( int oldId , int newId , const Transform & transform , bool global )
2013-12-11 00:12:44 +00:00
{
ULOGGER_INFO ( "old=%d, new=%d transform: %s" , oldId , newId , transform . prettyPrint (). c_str ());
2011-06-05 14:45:39 +00:00
Signature * oldS = _getSignature ( oldId );
Signature * newS = _getSignature ( newId );
2013-12-11 00:12:44 +00:00
if ( oldS && newS )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & oldLoopclosureIds = oldS -> getLoopClosureIds ();
2012-03-03 01:46:30 +00:00
if ( oldLoopclosureIds . size () && oldLoopclosureIds . find ( newS -> id ()) != oldLoopclosureIds . end ())
2011-06-05 14:45:39 +00:00
{
// do nothing, already merged
2012-03-03 01:46:30 +00:00
UDEBUG ( "already merged, old=%d, new=%d" , oldId , newId );
return true ;
2011-06-05 14:45:39 +00:00
}
2012-03-03 01:46:30 +00:00
UDEBUG ( "Add loop closure link between %d and %d" , oldS -> id (), newS -> id ());
2013-12-11 00:12:44 +00:00
oldS -> addLoopClosureId ( newS -> id (), transform . inverse ());
newS -> addChildLoopClosureId ( oldS -> id (), transform );
2014-01-22 19:49:28 +00:00
if ( _incrementalMemory && global )
2013-12-11 00:12:44 +00:00
{
2014-01-22 19:49:28 +00:00
_lastGlobalLoopClosureParentId = newS -> id ();
_lastGlobalLoopClosureChildId = oldS -> id ();
2013-12-11 00:12:44 +00:00
// udpate weights only if the memory is incremental
2012-03-03 01:46:30 +00:00
newS -> setWeight ( newS -> getWeight () + oldS -> getWeight ());
oldS -> setWeight ( 0 );
2011-06-05 14:45:39 +00:00
}
2012-03-03 01:46:30 +00:00
return true ;
2011-06-05 14:45:39 +00:00
}
else
{
if ( ! newS )
{
2012-03-03 01:46:30 +00:00
UERROR ( "newId=%d, oldId=%d, Signature %d not found in working/st memories" , newId , oldId , newId );
2011-06-05 14:45:39 +00:00
}
if ( ! oldS )
{
2012-03-03 01:46:30 +00:00
UERROR ( "newId=%d, oldId=%d, Signature %d not found in working/st memories" , newId , oldId , oldId );
2011-06-05 14:45:39 +00:00
}
}
2012-03-03 01:46:30 +00:00
return false ;
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
void Memory :: updateNeighborLink ( int fromId , int toId , const Transform & transform )
{
Signature * fromS = this -> _getSignature ( fromId );
Signature * toS = this -> _getSignature ( toId );
if ( fromS -> hasNeighbor ( toId ) && toS -> hasNeighbor ( fromId ))
{
fromS -> removeNeighbor ( toId );
toS -> removeNeighbor ( fromId );
fromS -> addNeighbor ( toId , transform );
toS -> addNeighbor ( fromId , transform . inverse ());
}
else
{
UERROR ( "fromId=%d and toId=%d are not neighbors!" , fromId , toId );
}
}
2011-06-05 14:45:39 +00:00
void Memory :: dumpMemory ( std :: string directory ) const
{
2013-06-05 19:25:16 +00:00
UINFO ( "Dumping memory to directory \" %s \" " , directory . c_str ());
2012-12-11 18:05:05 +00:00
this -> dumpDictionary (( directory + "DumpMemoryWordRef.txt" ). c_str (), ( directory + "DumpMemoryWordDesc.txt" ). c_str ());
2014-01-22 19:49:28 +00:00
this -> dumpSignatures (( directory + "DumpMemorySign.txt" ). c_str (), false );
this -> dumpSignatures (( directory + "DumpMemorySign3.txt" ). c_str (), true );
2011-06-05 14:45:39 +00:00
this -> dumpMemoryTree (( directory + "DumpMemoryTree.txt" ). c_str ());
}
2012-12-11 18:05:05 +00:00
void Memory :: dumpDictionary ( const char * fileNameRef , const char * fileNameDesc ) const
{
if ( _vwd )
{
_vwd -> exportDictionary ( fileNameRef , fileNameDesc );
}
}
2014-01-22 19:49:28 +00:00
void Memory :: dumpSignatures ( const char * fileNameSign , bool words3D ) const
2012-12-11 18:05:05 +00:00
{
FILE * foutSign = 0 ;
#ifdef _MSC_VER
fopen_s ( & foutSign , fileNameSign , "w" );
#else
foutSign = fopen ( fileNameSign , "w" );
#endif
if ( foutSign )
{
2014-01-22 19:49:28 +00:00
if ( words3D )
{
fprintf ( foutSign , "SignatureID WordsID... (Max features depth=%f) \n " , _bowMaxDepth );
}
else
{
fprintf ( foutSign , "SignatureID WordsID... \n " );
}
2012-12-11 18:05:05 +00:00
const std :: map < int , Signature *> & signatures = this -> getSignatures ();
for ( std :: map < int , Signature *>:: const_iterator iter = signatures . begin (); iter != signatures . end (); ++ iter )
{
fprintf ( foutSign , "%d " , iter -> first );
const Signature * ss = dynamic_cast < const Signature *> ( iter -> second );
if ( ss )
{
2014-01-22 19:49:28 +00:00
if ( words3D )
2012-12-11 18:05:05 +00:00
{
2014-01-22 19:49:28 +00:00
const std :: multimap < int , pcl :: PointXYZ > & ref = ss -> getWords3 ();
for ( std :: multimap < int , pcl :: PointXYZ >:: const_iterator jter = ref . begin (); jter != ref . end (); ++ jter )
{
//show only valid point according to current parameters
if ( pcl :: isFinite ( jter -> second ) &&
( jter -> second . x != 0 || jter -> second . y != 0 || jter -> second . z != 0 ) &&
( _bowMaxDepth <= 0 || jter -> second . x <= _bowMaxDepth ))
{
fprintf ( foutSign , "%d " , ( * jter ). first );
}
}
}
else
{
const std :: multimap < int , cv :: KeyPoint > & ref = ss -> getWords ();
for ( std :: multimap < int , cv :: KeyPoint >:: const_iterator jter = ref . begin (); jter != ref . end (); ++ jter )
{
fprintf ( foutSign , "%d " , ( * jter ). first );
}
2012-12-11 18:05:05 +00:00
}
}
fprintf ( foutSign , " \n " );
}
fclose ( foutSign );
}
}
2011-06-05 14:45:39 +00:00
void Memory :: dumpMemoryTree ( const char * fileNameTree ) const
{
FILE * foutTree = 0 ;
#ifdef _MSC_VER
fopen_s ( & foutTree , fileNameTree , "w" );
#else
foutTree = fopen ( fileNameTree , "w" );
#endif
if ( foutTree )
{
2012-03-03 01:46:30 +00:00
fprintf ( foutTree , "SignatureID Weight NbLoopClosureIds LoopClosureIds... NbChildLoopClosureIds ChildLoopClosureIds... \n " );
2011-06-05 14:45:39 +00:00
for ( std :: map < int , Signature *>:: const_iterator i = _signatures . begin (); i != _signatures . end (); ++ i )
{
2012-03-03 01:46:30 +00:00
fprintf ( foutTree , "%d %d" , i -> first , i -> second -> getWeight ());
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & loopIds = i -> second -> getLoopClosureIds ();
2012-03-03 01:46:30 +00:00
fprintf ( foutTree , " %d" , ( int ) loopIds . size ());
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: const_iterator j = loopIds . begin (); j != loopIds . end (); ++ j )
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
fprintf ( foutTree , " %d" , j -> first );
2012-03-03 01:46:30 +00:00
}
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & childIds = i -> second -> getChildLoopClosureIds ();
2012-03-03 01:46:30 +00:00
fprintf ( foutTree , " %d" , ( int ) childIds . size ());
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: const_iterator j = childIds . begin (); j != childIds . end (); ++ j )
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
fprintf ( foutTree , " %d" , j -> first );
2012-03-03 01:46:30 +00:00
}
fprintf ( foutTree , " \n " );
2011-06-05 14:45:39 +00:00
}
fclose ( foutTree );
}
}
2013-12-11 00:12:44 +00:00
void Memory :: rehearsal ( Signature * signature , Statistics * stats )
2011-06-05 14:45:39 +00:00
{
UTimer timer ;
2013-12-11 00:12:44 +00:00
if ( signature -> getNeighbors (). size () != 1 )
2012-03-03 01:46:30 +00:00
{
return ;
}
2013-12-11 00:12:44 +00:00
//============================================================
// Compare with the last
//============================================================
int id = signature -> getNeighbors (). begin () -> first ;
UDEBUG ( "Comparing with last signature (%d)..." , id );
const Signature * sB = this -> getSignature ( id );
if ( ! sB )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
UFATAL ( "Signature %d null?!?" , id );
2012-03-03 01:46:30 +00:00
}
2013-12-11 00:12:44 +00:00
float sim = signature -> compareTo ( sB );
2011-06-05 14:45:39 +00:00
2013-12-11 00:12:44 +00:00
int merged = 0 ;
if ( sim >= _similarityThreshold )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
if ( _incrementalMemory )
2013-01-15 17:14:33 +00:00
{
2013-12-11 00:12:44 +00:00
if ( this -> rehearsalMerge ( id , signature -> id ()))
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
merged = id ;
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
}
else
{
signature -> setWeight ( signature -> getWeight () + 1 + sB -> getWeight ());
}
}
if ( stats ) stats -> addStatistic ( Statistics :: kMemoryRehearsal_merged (), merged );
if ( stats ) stats -> addStatistic ( Statistics :: kMemoryRehearsal_sim (), sim );
UDEBUG ( "merged=%d, sim=%f t=%fs" , merged , sim , timer . ticks ());
}
bool Memory :: rehearsalMerge ( int oldId , int newId )
{
ULOGGER_INFO ( "old=%d, new=%d" , oldId , newId );
Signature * oldS = _getSignature ( oldId );
Signature * newS = _getSignature ( newId );
if ( oldS && newS && _incrementalMemory )
{
const std :: map < int , Transform > & oldLoopclosureIds = oldS -> getLoopClosureIds ();
if ( oldLoopclosureIds . size () && oldLoopclosureIds . find ( newS -> id ()) != oldLoopclosureIds . end ())
{
// do nothing, already merged
UWARN ( "already merged, old=%d, new=%d" , oldId , newId );
return false ;
}
UASSERT ( ! newS -> isSaved ());
UDEBUG ( "Rehearsal merge %d and %d" , oldS -> id (), newS -> id ());
// During rehearsal in STM
if ( _idUpdatedToNewOneRehearsal )
{
// update weight
newS -> setWeight ( newS -> getWeight () + 1 + oldS -> getWeight ());
oldS -> addLoopClosureId ( newS -> id ()); // to keep track of the merged location
2014-01-22 19:49:28 +00:00
if ( _lastGlobalLoopClosureParentId == oldS -> id ())
2011-06-05 14:45:39 +00:00
{
2014-01-22 19:49:28 +00:00
_lastGlobalLoopClosureParentId = newS -> id ();
2013-12-11 00:12:44 +00:00
}
}
else
{
// update weight
oldS -> setWeight ( newS -> getWeight () + 1 + oldS -> getWeight ());
newS -> addLoopClosureId ( oldS -> id ()); // to keep track of the merged location
if ( _lastSignature == newS )
{
_lastSignature = oldS ;
}
}
if ( _idUpdatedToNewOneRehearsal )
{
// redirect neighbor links
const std :: map < int , Transform > & neighbors = oldS -> getNeighbors ();
for ( std :: map < int , Transform >:: const_iterator iter = neighbors . begin (); iter != neighbors . end (); ++ iter )
{
int link = iter -> first ;
Transform t = iter -> second ;
if ( link != newS -> id () && link != oldS -> id ())
{
Signature * s = this -> _getSignature ( link );
if ( s )
{
// modify neighbor "from"
s -> changeNeighborIds ( oldS -> id (), newS -> id ());
if ( ! newS -> hasNeighbor ( link ))
{
newS -> addNeighbor ( link , t );
}
}
else
{
UERROR ( "Didn't find neighbor %d of %d in RAM..." , link , oldS -> id ());
}
}
}
oldS -> removeNeighbors ();
// redirect child loop closure links
std :: map < int , Transform > childIds = oldS -> getChildLoopClosureIds ();
for ( std :: map < int , Transform >:: const_iterator iter = childIds . begin (); iter != childIds . end (); ++ iter )
{
if ( iter -> first == newS -> id ())
{
UERROR ( "" );
}
newS -> addChildLoopClosureId ( iter -> first , iter -> second );
Signature * s = _getSignature ( iter -> first );
2012-06-24 17:19:34 +00:00
if ( s )
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "changed child Loop closure %d from %d to %d" , iter -> first , oldS -> id (), newS -> id ());
s -> changeLoopClosureId ( oldS -> id (), newS -> id ());
2012-06-24 17:19:34 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
UERROR ( "A location (%d, child of %d) in WM/STM cannot be transferred if its loop closure id is in STM" , iter -> first , oldS -> id ());
2012-06-24 17:19:34 +00:00
}
2013-12-11 00:12:44 +00:00
oldS -> removeChildLoopClosureId ( iter -> first );
2011-06-05 14:45:39 +00:00
}
2012-03-03 01:46:30 +00:00
2013-12-11 00:12:44 +00:00
// Set old image to new signature
this -> copyData ( oldS , newS );
}
//remove mutual links
oldS -> removeNeighbor ( newId );
newS -> removeNeighbor ( oldId );
// remove location
bool saveToDb = _keepRehearsedNodesInDb ;
moveToTrash ( _idUpdatedToNewOneRehearsal ? oldS : newS , saveToDb );
return true ;
}
else
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
if ( ! newS )
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
UERROR ( "newId=%d, oldId=%d, Signature %d not found in working/st memories" , newId , oldId , newId );
}
if ( ! oldS )
{
UERROR ( "newId=%d, oldId=%d, Signature %d not found in working/st memories" , newId , oldId , oldId );
2012-12-11 18:05:05 +00:00
}
}
2013-12-11 00:12:44 +00:00
return false ;
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
std :: vector < unsigned char > Memory :: getImage ( int signatureId ) const
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
std :: vector < unsigned char > image ;
2012-12-11 18:05:05 +00:00
const Signature * s = this -> getSignature ( signatureId );
if ( s )
2012-03-03 01:46:30 +00:00
{
2012-12-11 18:05:05 +00:00
image = s -> getImage ();
2012-03-03 01:46:30 +00:00
}
2012-12-11 18:05:05 +00:00
if ( image . empty () && this -> isRawDataKept () && _dbDriver )
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
_dbDriver -> getNodeData ( signatureId , image );
2011-06-05 14:45:39 +00:00
}
2012-12-11 18:05:05 +00:00
return image ;
2011-06-05 14:45:39 +00:00
}
2013-12-11 00:12:44 +00:00
void Memory :: getImageDepth (
int locationId ,
std :: vector < unsigned char > & rgb ,
std :: vector < unsigned char > & depth ,
std :: vector < unsigned char > & depth2d ,
float & depthConstant ,
Transform & localTransform ) const
{
const Signature * s = this -> getSignature ( locationId );
if ( s )
{
rgb = s -> getImage ();
depth = s -> getDepth ();
depth2d = s -> getDepth2D ();
depthConstant = s -> getDepthConstant ();
localTransform = s -> getLocalTransform ();
}
if ( rgb . empty () && this -> isRawDataKept () && _dbDriver )
{
_dbDriver -> getNodeData ( locationId , rgb , depth , depth2d , depthConstant , localTransform );
}
}
2011-06-05 14:45:39 +00:00
void Memory :: generateGraph ( const std :: string & fileName , std :: set < int > ids )
{
if ( ! _dbDriver )
{
UERROR ( "A database must must loaded first..." );
return ;
}
if ( ! fileName . empty ())
{
FILE * fout = 0 ;
#ifdef _MSC_VER
fopen_s ( & fout , fileName . c_str (), "w" );
#else
fout = fopen ( fileName . c_str (), "w" );
#endif
if ( ! fout )
{
UERROR ( "Cannot open file %s!" , fileName . c_str ());
return ;
}
if ( ids . size () == 0 )
{
2012-06-24 17:19:34 +00:00
_dbDriver -> getAllNodeIds ( ids );
UDEBUG ( "ids.size()=%d" , ids . size ());
2012-03-03 01:46:30 +00:00
for ( std :: map < int , Signature *>:: iterator iter = _signatures . begin (); iter != _signatures . end (); ++ iter )
{
ids . insert ( iter -> first );
}
2011-06-05 14:45:39 +00:00
}
2012-03-03 01:46:30 +00:00
const char * colorG = "green" ;
2012-12-11 18:05:05 +00:00
const char * colorP = "pink" ;
; UINFO ( "Generating map with %d locations" , ids . size ());
2011-06-05 14:45:39 +00:00
fprintf ( fout , "digraph G { \n " );
for ( std :: set < int >:: iterator i = ids . begin (); i != ids . end (); ++ i )
{
if ( _signatures . find ( * i ) == _signatures . end ())
{
int id = * i ;
2013-12-11 00:12:44 +00:00
std :: map < int , Transform > loopIds ;
std :: map < int , Transform > childIds ;
_dbDriver -> loadLoopClosures ( id , loopIds , childIds );
2012-12-11 18:05:05 +00:00
2013-12-11 00:12:44 +00:00
std :: map < int , Transform > neighbors ;
2012-12-11 18:05:05 +00:00
_dbDriver -> loadNeighbors ( id , neighbors );
int weight = 0 ;
_dbDriver -> getWeight ( id , weight );
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: iterator iter = neighbors . begin (); iter != neighbors . end (); ++ iter )
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
if ( id != iter -> first )
2012-12-11 18:05:05 +00:00
{
int weightNeighbor = 0 ;
2013-12-11 00:12:44 +00:00
if ( _signatures . find ( iter -> first ) == _signatures . end ())
2013-01-27 04:50:49 +00:00
{
2013-12-11 00:12:44 +00:00
_dbDriver -> getWeight ( iter -> first , weightNeighbor );
2013-01-27 04:50:49 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
weightNeighbor = _signatures . find ( iter -> first ) -> second -> getWeight ();
2013-01-27 04:50:49 +00:00
}
2014-01-22 19:49:28 +00:00
//UDEBUG("Add neighbor link from %d to %d", id, iter->first);
2012-12-11 18:05:05 +00:00
fprintf ( fout , " \" %d \\ n%d \" -> \" %d \\ n%d \"\n " ,
id ,
weight ,
2013-12-11 00:12:44 +00:00
iter -> first ,
2012-12-11 18:05:05 +00:00
weightNeighbor );
}
}
// loop closure links...
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: iterator iter = loopIds . begin (); iter != loopIds . end (); ++ iter )
2012-03-03 01:46:30 +00:00
{
int weightNeighbor = 0 ;
2013-12-11 00:12:44 +00:00
if ( _signatures . find ( iter -> first ) == _signatures . end ())
2012-03-03 01:46:30 +00:00
{
2013-12-11 00:12:44 +00:00
_dbDriver -> getWeight ( iter -> first , weightNeighbor );
2012-03-03 01:46:30 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
weightNeighbor = _signatures . find ( iter -> first ) -> second -> getWeight ();
2012-03-03 01:46:30 +00:00
}
2014-01-22 19:49:28 +00:00
//UDEBUG("Add loop link from %d to %d", id, iter->first);
2012-12-11 18:05:05 +00:00
fprintf ( fout , " \" %d \\ n%d \" -> \" %d \\ n%d \" [label= \" L \" , fontcolor=%s, fontsize=8]; \n " ,
2012-03-03 01:46:30 +00:00
id ,
weight ,
2013-12-11 00:12:44 +00:00
iter -> first ,
2012-03-03 01:46:30 +00:00
weightNeighbor ,
colorG );
}
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: iterator iter = childIds . begin (); iter != childIds . end (); ++ iter )
2011-06-05 14:45:39 +00:00
{
int weightNeighbor = 0 ;
2013-12-11 00:12:44 +00:00
if ( _signatures . find ( iter -> first ) == _signatures . end ())
2011-06-05 14:45:39 +00:00
{
2013-12-11 00:12:44 +00:00
_dbDriver -> getWeight ( iter -> first , weightNeighbor );
2011-06-05 14:45:39 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
weightNeighbor = _signatures . find ( iter -> first ) -> second -> getWeight ();
2011-06-05 14:45:39 +00:00
}
2014-01-22 19:49:28 +00:00
//UDEBUG("Add child link from %d to %d", id, iter->first);
2012-12-11 18:05:05 +00:00
fprintf ( fout , " \" %d \\ n%d \" -> \" %d \\ n%d \" [label= \" C \" , fontcolor=%s, fontsize=8]; \n " ,
2011-06-05 14:45:39 +00:00
id ,
weight ,
2013-12-11 00:12:44 +00:00
iter -> first ,
2011-06-05 14:45:39 +00:00
weightNeighbor ,
2012-12-11 18:05:05 +00:00
colorP );
}
}
}
for ( std :: map < int , Signature *>:: iterator i = _signatures . begin (); i != _signatures . end (); ++ i )
{
if ( ids . find ( i -> first ) != ids . end ())
{
int id = i -> second -> id ();
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & loopIds = i -> second -> getLoopClosureIds ();
2012-12-11 18:05:05 +00:00
//don't show children when _loopClosuresMerged is on
//if(!_loopClosuresMerged || (loopIds.size() == 0))
{
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & neighbors = i -> second -> getNeighbors ();
2012-12-11 18:05:05 +00:00
int weight = i -> second -> getWeight ();
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: const_iterator iter = neighbors . begin (); iter != neighbors . end (); ++ iter )
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
if ( id != iter -> first )
2012-12-11 18:05:05 +00:00
{
int weightNeighbor = 0 ;
2013-12-11 00:12:44 +00:00
const Signature * s = this -> getSignature ( iter -> first );
2012-12-11 18:05:05 +00:00
if ( s )
{
weightNeighbor = s -> getWeight ();
}
else
{
2013-12-11 00:12:44 +00:00
_dbDriver -> getWeight ( iter -> first , weightNeighbor );
2012-12-11 18:05:05 +00:00
}
2014-01-22 19:49:28 +00:00
//UDEBUG("Add neighbor link from %d to %d", id, iter->first);
2012-12-11 18:05:05 +00:00
fprintf ( fout , " \" %d \\ n%d \" -> \" %d \\ n%d \" ; \n " ,
id ,
weight ,
2013-12-11 00:12:44 +00:00
iter -> first ,
2012-12-11 18:05:05 +00:00
weightNeighbor );
}
}
// loop closure link
2013-12-11 00:12:44 +00:00
for ( std :: map < int , Transform >:: const_iterator iter = loopIds . begin (); iter != loopIds . end (); ++ iter )
2012-12-11 18:05:05 +00:00
{
int weightNeighbor = 0 ;
2013-12-11 00:12:44 +00:00
if ( _signatures . find ( iter -> first ) == _signatures . end ())
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
_dbDriver -> getWeight ( iter -> first , weightNeighbor );
2012-12-11 18:05:05 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
weightNeighbor = _signatures . find ( iter -> first ) -> second -> getWeight ();
2012-12-11 18:05:05 +00:00
}
2014-01-22 19:49:28 +00:00
//UDEBUG("Add loop link from %d to %d", id, iter->first);
2012-12-11 18:05:05 +00:00
fprintf ( fout , " \" %d \\ n%d \" -> \" %d \\ n%d \" [label= \" L \" , fontcolor=%s, fontsize=8]; \n " ,
id ,
weight ,
2013-12-11 00:12:44 +00:00
iter -> first ,
2012-12-11 18:05:05 +00:00
weightNeighbor ,
colorG );
}
// child loop closure link
2013-12-11 00:12:44 +00:00
const std :: map < int , Transform > & childIds = i -> second -> getChildLoopClosureIds ();
for ( std :: map < int , Transform >:: const_iterator iter = childIds . begin (); iter != childIds . end (); ++ iter )
2012-12-11 18:05:05 +00:00
{
int weightNeighbor = 0 ;
2013-12-11 00:12:44 +00:00
if ( _signatures . find ( iter -> first ) == _signatures . end ())
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
_dbDriver -> getWeight ( iter -> first , weightNeighbor );
2012-12-11 18:05:05 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
weightNeighbor = _signatures . find ( iter -> first ) -> second -> getWeight ();
2012-12-11 18:05:05 +00:00
}
2014-01-22 19:49:28 +00:00
//UDEBUG("Add child link from %d to %d", id, iter->first);
2012-12-11 18:05:05 +00:00
fprintf ( fout , " \" %d \\ n%d \" -> \" %d \\ n%d \" [label= \" C \" , fontcolor=%s, fontsize=8]; \n " ,
id ,
weight ,
2013-12-11 00:12:44 +00:00
iter -> first ,
2012-12-11 18:05:05 +00:00
weightNeighbor ,
colorP );
}
2011-06-05 14:45:39 +00:00
}
}
}
fprintf ( fout , "} \n " );
fclose ( fout );
2012-12-11 18:05:05 +00:00
UINFO ( "Graph saved to \" %s \" " , fileName . c_str ());
2011-06-05 14:45:39 +00:00
}
}
2012-12-11 18:05:05 +00:00
// Only used to generate a .dot file
class GraphNode
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
public :
GraphNode ( int id , GraphNode * parent = 0 ) :
_parent ( parent ),
_id ( id )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
if ( _parent )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
_parent -> addChild ( this );
2011-06-05 14:45:39 +00:00
}
2012-12-11 18:05:05 +00:00
}
virtual ~ GraphNode ()
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
//We copy the set because when a child is destroyed, it is removed from its parent.
std :: set < GraphNode *> children = _children ;
_children . clear ();
for ( std :: set < GraphNode *>:: iterator iter = children . begin (); iter != children . end (); ++ iter )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
delete * iter ;
}
children . clear ();
if ( _parent )
{
_parent -> removeChild ( this );
}
}
int id () const { return _id ;}
bool isAncestor ( int id ) const
{
if ( _parent )
{
if ( _parent -> id () == id )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
return true ;
2011-06-05 14:45:39 +00:00
}
2012-12-11 18:05:05 +00:00
return _parent -> isAncestor ( id );
}
return false ;
}
void expand ( std :: list < std :: list < int > > & paths , std :: list < int > currentPath = std :: list < int > ()) const
{
currentPath . push_back ( _id );
if ( _children . size () == 0 )
{
paths . push_back ( currentPath );
return ;
}
for ( std :: set < GraphNode *>:: const_iterator iter = _children . begin (); iter != _children . end (); ++ iter )
{
( * iter ) -> expand ( paths , currentPath );
2011-06-05 14:45:39 +00:00
}
}
2012-12-11 18:05:05 +00:00
private :
void addChild ( GraphNode * child )
2011-06-05 14:45:39 +00:00
{
2012-12-11 18:05:05 +00:00
_children . insert ( child );
}
void removeChild ( GraphNode * child )
{
_children . erase ( child );
2011-06-05 14:45:39 +00:00
}
2012-12-11 18:05:05 +00:00
private :
std :: set < GraphNode *> _children ;
GraphNode * _parent ;
int _id ;
};
2011-06-05 14:45:39 +00:00
//recursive
2012-12-11 18:05:05 +00:00
void Memory :: createGraph ( GraphNode * parent , unsigned int maxDepth , const std :: set < int > & endIds )
2011-06-05 14:45:39 +00:00
{
if ( maxDepth == 0 || ! parent )
{
return ;
}
2012-12-11 18:05:05 +00:00
std :: map < int , int > neighbors = this -> getNeighborsId ( parent -> id (), 1 , - 1 , false );
2011-06-05 14:45:39 +00:00
for ( std :: map < int , int >:: iterator iter = neighbors . begin (); iter != neighbors . end (); ++ iter )
{
if ( ! parent -> isAncestor ( iter -> first ))
{
2012-12-11 18:05:05 +00:00
GraphNode * n = new GraphNode ( iter -> first , parent );
2011-06-05 14:45:39 +00:00
if ( endIds . find ( iter -> first ) == endIds . end ())
{
this -> createGraph ( n , maxDepth - 1 , endIds );
}
}
}
}
2012-12-11 18:05:05 +00:00
// Keypoint stuff
std :: multimap < int , cv :: KeyPoint > Memory :: getWords ( int signatureId ) const
{
std :: multimap < int , cv :: KeyPoint > words ;
if ( signatureId > 0 )
{
const Signature * s = this -> getSignature ( signatureId );
if ( s )
{
const Signature * ks = dynamic_cast < const Signature *> ( s );
if ( ks )
{
words = ks -> getWords ();
}
}
else if ( _dbDriver )
{
std :: list < int > ids ;
ids . push_back ( signatureId );
std :: list < Signature *> signatures ;
_dbDriver -> loadSignatures ( ids , signatures );
if ( signatures . size ())
{
const Signature * ks = dynamic_cast < const Signature *> ( signatures . front ());
if ( ks )
{
words = ks -> getWords ();
}
}
for ( std :: list < Signature *>:: iterator iter = signatures . begin (); iter != signatures . end (); ++ iter )
{
delete * iter ;
}
}
}
return words ;
}
int Memory :: getNi ( int signatureId ) const
{
int ni = 0 ;
const Signature * s = this -> getSignature ( signatureId );
if ( s ) // Must be a SurfSignature
{
ni = (( Signature * ) s ) -> getWords (). size ();
}
else
{
_dbDriver -> getInvertedIndexNi ( signatureId , ni );
}
return ni ;
}
void Memory :: copyData ( const Signature * from , Signature * to )
{
// The signatures must be KeypointSignature
UTimer timer ;
timer . start ();
2013-12-11 00:12:44 +00:00
if ( from && to )
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
// words 2d
this -> disableWordsRef ( to -> id ());
to -> setWords ( from -> getWords ());
2012-12-11 18:05:05 +00:00
std :: list < int > id ;
2013-12-11 00:12:44 +00:00
id . push_back ( to -> id ());
2012-12-11 18:05:05 +00:00
this -> enableWordsRef ( id );
2013-12-11 00:12:44 +00:00
if ( from -> isSaved () && _dbDriver )
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
std :: vector < unsigned char > image ;
std :: vector < unsigned char > depth ;
std :: vector < unsigned char > depth2d ;
float depthConstant ;
Transform localTransform ;
_dbDriver -> getNodeData ( from -> id (), image , depth , depth2d , depthConstant , localTransform );
to -> setImage ( image );
to -> setDepth ( depth , depthConstant );
to -> setDepth2D ( depth2d );
to -> setLocalTransform ( localTransform );
UDEBUG ( "Loaded image data from database" );
2012-12-11 18:05:05 +00:00
}
2013-12-11 00:12:44 +00:00
else
{
to -> setImage ( from -> getImage ());
to -> setDepth ( from -> getDepth (), from -> getDepthConstant ());
to -> setDepth2D ( from -> getDepth2D ());
to -> setLocalTransform ( from -> getLocalTransform ());
}
to -> setPose ( from -> getPose ());
to -> setWords3 ( from -> getWords3 ());
2012-12-11 18:05:05 +00:00
}
else
{
ULOGGER_ERROR ( "Can't merge the signatures because there are not same type." );
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "Merging time = %fs" , timer . ticks ());
}
void Memory :: extractKeypointsAndDescriptors (
const cv :: Mat & image ,
std :: vector < cv :: KeyPoint > & keypoints ,
cv :: Mat & descriptors )
{
if ( _wordsPerImageTarget >= 0 )
{
UTimer timer ;
if ( _keypointDetector )
{
cv :: Rect roi = KeypointDetector :: computeRoi ( image , _roiRatios );
keypoints = _keypointDetector -> generateKeypoints ( image , _wordsPerImageTarget , roi );
UDEBUG ( "time keypoints (%d) = %fs" , ( int ) keypoints . size (), timer . ticks ());
}
if ( keypoints . size ())
{
descriptors = _keypointDescriptor -> generateDescriptors ( image , keypoints );
UDEBUG ( "time descriptors (%d) = %fs" , descriptors . rows , timer . ticks ());
}
}
else
{
UDEBUG ( "_wordsPerImageTarget(%d)<0 so don't extract any descriptors..." , _wordsPerImageTarget );
}
2012-12-11 18:05:05 +00:00
}
class PreUpdateThread : public UThreadNode
{
public :
PreUpdateThread ( VWDictionary * vwp ) : _vwp ( vwp ) {}
virtual ~ PreUpdateThread () {}
private :
void mainLoop () {
if ( _vwp )
{
_vwp -> update ();
}
this -> kill ();
}
VWDictionary * _vwp ;
};
2013-01-21 18:55:25 +00:00
Signature * Memory :: createSignature ( const Image & image , bool keepRawData )
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
UASSERT ( image . image (). empty () || image . image (). type () == CV_8UC1 || image . image (). type () == CV_8UC3 );
UASSERT ( image . depth (). empty () || image . depth (). type () == CV_16UC1 );
UASSERT ( image . depth2d (). empty () || image . depth2d (). type () == CV_32FC2 );
2012-12-11 18:05:05 +00:00
PreUpdateThread preUpdateThread ( _vwd );
UTimer timer ;
timer . start ();
std :: vector < cv :: KeyPoint > keypoints ;
cv :: Mat descriptors ;
2013-01-21 18:55:25 +00:00
int id = image . id ();
2013-12-11 00:12:44 +00:00
if ( _generateIds )
2013-01-21 18:55:25 +00:00
{
id = this -> getNextId ();
}
2013-06-10 18:54:11 +00:00
else
{
2013-12-11 00:12:44 +00:00
if ( id <= 0 )
{
UWARN ( "Received image ID is null. "
"Please set parameter Mem/GenerateIds to \" true \" or "
"make sure the input source provides image ids (seq)." );
return 0 ;
}
else if ( id > _idCount )
{
_idCount = id ;
}
else
{
UWARN ( "Id of acquired image (%d) is smaller than the last in memory (%d). "
"Please set parameter Mem/GenerateIds to \" true \" or "
"make sure the input source provides image ids (seq) over the last in "
"memory, which is %d." ,
id ,
_idCount ,
_idCount );
return 0 ;
}
2013-06-10 18:54:11 +00:00
}
2012-12-11 18:05:05 +00:00
2013-01-10 20:29:01 +00:00
int treeSize = _workingMem . size () + _stMem . size ();
2013-12-11 00:12:44 +00:00
int meanWordsPerLocation = 0 ;
2012-12-11 18:05:05 +00:00
if ( treeSize > 0 )
{
2013-12-11 00:12:44 +00:00
meanWordsPerLocation = _vwd -> getTotalActiveReferences () / treeSize ;
2012-12-11 18:05:05 +00:00
}
if ( _parallelized )
{
preUpdateThread . start ();
}
if ( ! image . descriptors (). empty ())
{
// DESCRIPTORS
2013-12-11 00:12:44 +00:00
if ( image . descriptors (). rows && image . descriptors (). rows >= _badSignRatio * float ( meanWordsPerLocation ))
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
UASSERT ( image . descriptors (). type () == CV_32F );
descriptors = image . descriptors ();
keypoints = image . keypoints ();
2012-12-11 18:05:05 +00:00
}
2013-12-11 00:12:44 +00:00
limitKeypoints ( keypoints , descriptors , _wordsPerImageTarget );
2012-12-11 18:05:05 +00:00
}
else
{
// IMAGE RAW
2013-12-11 00:12:44 +00:00
this -> extractKeypointsAndDescriptors ( image . image (), keypoints , descriptors );
2012-12-11 18:05:05 +00:00
2013-12-11 00:12:44 +00:00
UDEBUG ( "ratio=%f, meanWordsPerLocation=%d" , _badSignRatio , meanWordsPerLocation );
if ( descriptors . rows && descriptors . rows < _badSignRatio * float ( meanWordsPerLocation ))
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
descriptors = cv :: Mat ();
2012-12-11 18:05:05 +00:00
}
}
if ( _parallelized )
{
preUpdateThread . join (); // Wait the dictionary to be updated
}
std :: list < int > wordIds ;
if ( descriptors . rows )
{
if ( _parallelized )
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "time descriptor and memory update (%d of size=%d) = %fs" , descriptors . rows , descriptors . cols , timer . ticks ());
2012-12-11 18:05:05 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "time descriptor (%d of size=%d) = %fs" , descriptors . rows , descriptors . cols , timer . ticks ());
2012-12-11 18:05:05 +00:00
}
wordIds = _vwd -> addNewWords ( descriptors , id );
2013-12-11 00:12:44 +00:00
UDEBUG ( "time addNewWords %fs" , timer . ticks ());
2012-12-11 18:05:05 +00:00
}
else if ( id > 0 )
{
UDEBUG ( "id %d is a bad signature" , id );
}
std :: multimap < int , cv :: KeyPoint > words ;
if ( wordIds . size () > 0 )
{
std :: vector < cv :: KeyPoint >:: iterator kpIter = keypoints . begin ();
for ( std :: list < int >:: iterator iter = wordIds . begin (); iter != wordIds . end (); ++ iter )
{
if ( kpIter != keypoints . end ())
{
words . insert ( std :: pair < int , cv :: KeyPoint > ( * iter , * kpIter ));
++ kpIter ;
}
else
{
if ( keypoints . size ())
{
UWARN ( "Words (%d) and keypoints(%d) are not the same size ?!?" , ( int ) wordIds . size (), ( int ) keypoints . size ());
}
words . insert ( std :: pair < int , cv :: KeyPoint > ( * iter , cv :: KeyPoint ()));
}
}
}
2013-12-11 00:12:44 +00:00
//3d words
std :: multimap < int , pcl :: PointXYZ > words3 ;
if ( ! image . depth (). empty () && image . depthConstant ())
{
words3 = util3d :: generateWords3 ( words , image . depth (), image . depthConstant (), image . localTransform ());
}
Signature * s ;
2012-12-11 18:05:05 +00:00
if ( keepRawData )
{
2013-12-11 00:12:44 +00:00
std :: vector < unsigned char > imageBytes ;
std :: vector < unsigned char > depthBytes ;
util3d :: CompressionThread ctImage ( image . image (), std :: string ( ".jpg" ));
util3d :: CompressionThread ctDepth ( image . depth (), std :: string ( ".png" ));
ctImage . start ();
ctDepth . start ();
ctImage . join ();
ctDepth . join ();
imageBytes = ctImage . getCompressedData ();
depthBytes = ctDepth . getCompressedData ();
s = new Signature ( id ,
_idMapCount ,
words ,
words3 ,
image . pose (),
util3d :: compressData ( image . depth2d ()),
imageBytes ,
depthBytes ,
image . depthConstant (),
image . localTransform ());
2012-12-11 18:05:05 +00:00
}
else
{
2013-12-11 00:12:44 +00:00
s = new Signature ( id ,
_idMapCount ,
words ,
words3 ,
image . pose (),
util3d :: compressData ( image . depth2d ()));
2012-12-11 18:05:05 +00:00
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "time new signature (id=%d) %fs" , id , timer . ticks ());
2012-12-11 18:05:05 +00:00
if ( words . size ())
{
2013-12-11 00:12:44 +00:00
s -> setEnabled ( true ); // All references are already activated in the dictionary at this point (see _vwd->addNewWords())
2012-12-11 18:05:05 +00:00
}
2013-12-11 00:12:44 +00:00
return s ;
2012-12-11 18:05:05 +00:00
}
2013-03-02 21:53:47 +00:00
void Memory :: disableWordsRef ( int signatureId , bool saveToDatabase )
2012-12-11 18:05:05 +00:00
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "id=%d" , signatureId );
2012-12-11 18:05:05 +00:00
Signature * ss = dynamic_cast < Signature *> ( this -> _getSignature ( signatureId ));
if ( ss && ss -> isEnabled ())
{
const std :: multimap < int , cv :: KeyPoint > & words = ss -> getWords ();
const std :: list < int > & keys = uUniqueKeys ( words );
int count = _vwd -> getTotalActiveReferences ();
// First remove all references
for ( std :: list < int >:: const_iterator i = keys . begin (); i != keys . end (); ++ i )
{
_vwd -> removeAllWordRef ( * i , signatureId );
2013-03-02 21:53:47 +00:00
if ( ! saveToDatabase )
{
// assume just removed word doesn't have any other references
VisualWord * w = _vwd -> getUnusedWord ( * i );
if ( w )
{
std :: vector < VisualWord *> wordToDelete ;
wordToDelete . push_back ( w );
_vwd -> removeWords ( wordToDelete );
delete w ;
}
}
2012-12-11 18:05:05 +00:00
}
count -= _vwd -> getTotalActiveReferences ();
ss -> setEnabled ( false );
2013-12-11 00:12:44 +00:00
UDEBUG ( "%d words total ref removed from signature %d... (total active ref = %d)" , count , ss -> id (), _vwd -> getTotalActiveReferences ());
2012-12-11 18:05:05 +00:00
}
}
void Memory :: cleanUnusedWords ()
{
if ( _vwd -> isIncremental ())
{
std :: vector < VisualWord *> removedWords = _vwd -> getUnusedWords ();
2013-12-11 00:12:44 +00:00
UDEBUG ( "Removing %d words (dictionary size=%d)..." , removedWords . size (), _vwd -> getVisualWords (). size ());
2012-12-11 18:05:05 +00:00
if ( removedWords . size ())
{
// remove them from the dictionary
_vwd -> removeWords ( removedWords );
for ( unsigned int i = 0 ; i < removedWords . size (); ++ i )
{
2012-12-12 16:40:18 +00:00
if ( _dbDriver )
2012-12-11 18:05:05 +00:00
{
_dbDriver -> asyncSave ( removedWords [ i ]);
}
else
{
delete removedWords [ i ];
}
}
}
}
}
void Memory :: enableWordsRef ( const std :: list < int > & signatureIds )
{
2013-12-11 00:12:44 +00:00
UDEBUG ( "size=%d" , signatureIds . size ());
2012-12-11 18:05:05 +00:00
UTimer timer ;
timer . start ();
std :: map < int , int > refsToChange ; //<oldWordId, activeWordId>
std :: set < int > oldWordIds ;
std :: list < Signature *> surfSigns ;
for ( std :: list < int >:: const_iterator i = signatureIds . begin (); i != signatureIds . end (); ++ i )
{
Signature * ss = dynamic_cast < Signature *> ( this -> _getSignature ( * i ));
if ( ss && ! ss -> isEnabled ())
{
surfSigns . push_back ( ss );
std :: list < int > uniqueKeys = uUniqueKeys ( ss -> getWords ());
//Find words in the signature which they are not in the current dictionary
for ( std :: list < int >:: const_iterator k = uniqueKeys . begin (); k != uniqueKeys . end (); ++ k )
{
if ( _vwd -> getWord ( * k ) == 0 && _vwd -> getUnusedWord ( * k ) == 0 )
{
oldWordIds . insert ( oldWordIds . end (), * k );
}
}
}
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "oldWordIds.size()=%d, getOldIds time=%fs" , oldWordIds . size (), timer . ticks ());
2012-12-11 18:05:05 +00:00
// the words were deleted, so try to math it with an active word
std :: list < VisualWord *> vws ;
if ( oldWordIds . size () && _dbDriver )
{
// get the descriptors
_dbDriver -> loadWords ( oldWordIds , vws );
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "loading words(%d) time=%fs" , oldWordIds . size (), timer . ticks ());
2012-12-11 18:05:05 +00:00
if ( vws . size ())
{
//Search in the dictionary
2013-12-11 00:12:44 +00:00
bool reactivatedWordsComparedToNewWords = true ;
std :: vector < int > vwActiveIds = _vwd -> findNN ( vws , reactivatedWordsComparedToNewWords );
UDEBUG ( "find active ids (number=%d) time=%fs" , vws . size (), timer . ticks ());
2012-12-11 18:05:05 +00:00
int i = 0 ;
for ( std :: list < VisualWord *>:: iterator iterVws = vws . begin (); iterVws != vws . end (); ++ iterVws )
{
if ( vwActiveIds [ i ] > 0 )
{
2013-12-11 00:12:44 +00:00
//UDEBUG("Match found %d with %d", (*iterVws)->id(), vwActiveIds[i]);
2012-12-11 18:05:05 +00:00
refsToChange . insert ( refsToChange . end (), std :: pair < int , int > (( * iterVws ) -> id (), vwActiveIds [ i ]));
if (( * iterVws ) -> isSaved ())
{
delete ( * iterVws );
}
else if ( _dbDriver )
{
_dbDriver -> asyncSave ( * iterVws );
}
}
else
{
//add to dictionary
_vwd -> addWord ( * iterVws ); // take ownership
}
++ i ;
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "Added %d to dictionary, time=%fs" , vws . size () - refsToChange . size (), timer . ticks ());
2012-12-11 18:05:05 +00:00
//update the global references map and update the signatures reactivated
for ( std :: map < int , int >:: const_iterator iter = refsToChange . begin (); iter != refsToChange . end (); ++ iter )
{
//uInsert(_wordRefsToChange, (const std::pair<int, int>)*iter); // This will be used to change references in the database
for ( std :: list < Signature *>:: iterator j = surfSigns . begin (); j != surfSigns . end (); ++ j )
{
( * j ) -> changeWordsRef ( iter -> first , iter -> second );
}
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "changing ref, total=%d, time=%fs" , refsToChange . size (), timer . ticks ());
2012-12-11 18:05:05 +00:00
}
int count = _vwd -> getTotalActiveReferences ();
// Reactivate references and signatures
for ( std :: list < Signature *>:: iterator j = surfSigns . begin (); j != surfSigns . end (); ++ j )
{
const std :: vector < int > & keys = uKeys (( * j ) -> getWords ());
// Add all references
for ( std :: vector < int >:: const_iterator i = keys . begin (); i != keys . end (); ++ i )
{
_vwd -> addWordRef ( * i , ( * j ) -> id ());
}
if ( keys . size ())
{
( * j ) -> setEnabled ( true );
}
}
count = _vwd -> getTotalActiveReferences () - count ;
2013-12-11 00:12:44 +00:00
UDEBUG ( "%d words total ref added from %d signatures, time=%fs..." , count , surfSigns . size (), timer . ticks ());
2012-12-11 18:05:05 +00:00
}
std :: set < int > Memory :: reactivateSignatures ( const std :: list < int > & ids , unsigned int maxLoaded , double & timeDbAccess )
{
// get the signatures, if not in the working memory, they
// will be loaded from the database in an more efficient way
// than how it is done in the Memory
2013-12-11 00:12:44 +00:00
UDEBUG ( "" );
2012-12-11 18:05:05 +00:00
UTimer timer ;
std :: list < int > idsToLoad ;
std :: map < int , int >:: iterator wmIter ;
for ( std :: list < int >:: const_iterator i = ids . begin (); i != ids . end (); ++ i )
{
if ( ! this -> getSignature ( * i ) && ! uContains ( idsToLoad , * i ))
{
if ( ! maxLoaded || idsToLoad . size () < maxLoaded )
{
idsToLoad . push_back ( * i );
UINFO ( "Loading location %d from database..." , * i );
}
}
}
2013-12-11 00:12:44 +00:00
UDEBUG ( "idsToLoad = %d" , idsToLoad . size ());
2012-12-11 18:05:05 +00:00
std :: list < Signature *> reactivatedSigns ;
if ( _dbDriver )
{
_dbDriver -> loadSignatures ( idsToLoad , reactivatedSigns );
}
timeDbAccess = timer . getElapsedTime ();
std :: list < int > idsLoaded ;
for ( std :: list < Signature *>:: iterator i = reactivatedSigns . begin (); i != reactivatedSigns . end (); ++ i )
{
idsLoaded . push_back (( * i ) -> id ());
//append to working memory
this -> addSignatureToWm ( * i );
}
this -> enableWordsRef ( idsLoaded );
2013-12-11 00:12:44 +00:00
UDEBUG ( "time = %fs" , timer . ticks ());
2012-12-11 18:05:05 +00:00
return std :: set < int > ( idsToLoad . begin (), idsToLoad . end ());
}
2013-12-11 00:12:44 +00:00
void Memory :: getMetricConstraints (
const std :: vector < int > & ids ,
std :: map < int , Transform > & poses ,
2014-02-11 23:04:22 +00:00
std :: multimap < int , Link > & links ,
2013-12-11 00:12:44 +00:00
bool lookInDatabase )
{
for ( unsigned int i = 0 ; i < ids . size (); ++ i )
{
Transform pose ;
2014-01-22 19:49:28 +00:00
this -> getPose ( ids [ i ], pose , lookInDatabase );
2013-12-11 00:12:44 +00:00
if ( ! pose . isNull ())
{
poses . insert ( std :: make_pair ( ids [ i ], pose ));
}
}
for ( unsigned int i = 0 ; i < ids . size (); ++ i )
{
if ( uContains ( poses , ids [ i ]))
{
std :: map < int , Transform > neighbors = this -> getNeighborLinks ( ids [ i ], true , lookInDatabase ); // only direct neighbors
for ( std :: map < int , Transform >:: iterator jter = neighbors . begin (); jter != neighbors . end (); ++ jter )
{
if ( ! jter -> second . isNull () && uContains ( poses , jter -> first ))
{
2014-01-22 19:49:28 +00:00
bool edgeAlreadyAdded = false ;
2014-02-11 23:04:22 +00:00
for ( std :: multimap < int , Link >:: iterator iter = links . lower_bound ( jter -> first );
2014-01-22 19:49:28 +00:00
iter != links . end () && iter -> first == jter -> first ;
++ iter )
{
2014-02-11 23:04:22 +00:00
if ( iter -> second . to () == ids [ i ])
2014-01-22 19:49:28 +00:00
{
edgeAlreadyAdded = true ;
}
}
if ( ! edgeAlreadyAdded )
{
2014-02-11 23:04:22 +00:00
links . insert ( std :: make_pair ( ids [ i ], Link ( ids [ i ], jter -> first , jter -> second , Link :: kNeighbor )));
2014-01-22 19:49:28 +00:00
}
2013-12-11 00:12:44 +00:00
}
}
2014-01-22 19:49:28 +00:00
2013-12-11 00:12:44 +00:00
std :: map < int , Transform > loops , children ;
this -> getLoopClosureIds ( ids [ i ], loops , children , lookInDatabase );
for ( std :: map < int , Transform >:: iterator jter = children . begin (); jter != children . end (); ++ jter )
{
if ( ! jter -> second . isNull () && uContains ( poses , jter -> first ))
{
2014-02-11 23:04:22 +00:00
links . insert ( std :: make_pair ( ids [ i ], Link ( ids [ i ], jter -> first , jter -> second , Link :: kGlobalClosure )));
2013-12-11 00:12:44 +00:00
}
}
}
}
}
2011-06-05 14:45:39 +00:00
} // namespace rtabmap