DatabaseViewer: using DBDriver directly instead of Memory to save RAM on large databases

This commit is contained in:
matlabbe
2015-10-16 14:54:47 -04:00
parent 835155e6ae
commit 5934ec90db
9 changed files with 544 additions and 408 deletions
+14
View File
@@ -60,6 +60,9 @@ class VisualWord;
// //
class RTABMAP_EXP DBDriver : public UThreadNode class RTABMAP_EXP DBDriver : public UThreadNode
{ {
public:
static DBDriver * create(const ParametersMap & parameters = ParametersMap());
public: public:
virtual ~DBDriver(); virtual ~DBDriver();
@@ -75,6 +78,15 @@ public:
double getEmptyTrashesTime() const {return _emptyTrashesTime;} double getEmptyTrashesTime() const {return _emptyTrashesTime;}
void setTimestampUpdateEnabled(bool enabled) {_timestampUpdate = enabled;} // used on Update Signature and Word queries void setTimestampUpdateEnabled(bool enabled) {_timestampUpdate = enabled;} // used on Update Signature and Word queries
// Warning: the following functions don't look in the trash, direct database modifications
void generateGraph(
const std::string & fileName,
const std::set<int> & ids = std::set<int>(),
const std::map<int, Signature *> & otherSignatures = std::map<int, Signature *>());
void addLink(const Link & link);
void removeLink(int from, int to);
void updateLink(const Link & link);
public: public:
void addStatisticsAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed, int dictionarySize) const; void addStatisticsAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed, int dictionarySize) const;
@@ -128,6 +140,8 @@ private:
virtual void updateQuery(const std::list<Signature *> & signatures, bool updateTimestamp) const = 0; virtual void updateQuery(const std::list<Signature *> & signatures, bool updateTimestamp) const = 0;
virtual void updateQuery(const std::list<VisualWord *> & words, bool updateTimestamp) const = 0; virtual void updateQuery(const std::list<VisualWord *> & words, bool updateTimestamp) const = 0;
virtual void addLinkQuery(const Link & link) const = 0;
virtual void updateLinkQuery(const Link & link) const = 0;
// Load objects // Load objects
virtual void loadQuery(VWDictionary * dictionary) const = 0; virtual void loadQuery(VWDictionary * dictionary) const = 0;
+1 -5
View File
@@ -48,7 +48,6 @@ namespace rtabmap {
class Signature; class Signature;
class DBDriver; class DBDriver;
class GraphNode;
class VWDictionary; class VWDictionary;
class VisualWord; class VisualWord;
class Feature2D; class Feature2D;
@@ -164,10 +163,7 @@ public:
virtual void dumpSignatures(const char * fileNameSign, bool words3D) const; virtual void dumpSignatures(const char * fileNameSign, bool words3D) const;
void dumpDictionary(const char * fileNameRef, const char * fileNameDesc) const; void dumpDictionary(const char * fileNameRef, const char * fileNameDesc) const;
void generateGraph(const std::string & fileName, std::set<int> ids = std::set<int>()); void generateGraph(const std::string & fileName, const std::set<int> & ids = std::set<int>());
void createGraph(GraphNode * parent,
unsigned int maxDepth,
const std::set<int> & endIds = std::set<int>());
//keypoint stuff //keypoint stuff
const VWDictionary * getVWDictionary() const; const VWDictionary * getVWDictionary() const;
+175
View File
@@ -34,9 +34,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/utilite/ULogger.h" #include "rtabmap/utilite/ULogger.h"
#include "rtabmap/utilite/UTimer.h" #include "rtabmap/utilite/UTimer.h"
#include "rtabmap/utilite/UStl.h" #include "rtabmap/utilite/UStl.h"
#include "DBDriverSqlite3.h"
namespace rtabmap { namespace rtabmap {
DBDriver * DBDriver::create(const ParametersMap & parameters)
{
// well, we only have Sqlite3 database type for now :P
return new DBDriverSqlite3(parameters);
}
DBDriver::DBDriver(const ParametersMap & parameters) : DBDriver::DBDriver(const ParametersMap & parameters) :
_emptyTrashesTime(0), _emptyTrashesTime(0),
_timestampUpdate(true) _timestampUpdate(true)
@@ -291,6 +298,23 @@ void DBDriver::saveOrUpdate(const std::vector<VisualWord *> & words) const
} }
} }
void DBDriver::addLink(const Link & link)
{
_dbSafeAccessMutex.lock();
this->addLinkQuery(link);
_dbSafeAccessMutex.unlock();
}
void DBDriver::removeLink(int from, int to)
{
this->executeNoResult(uFormat("DELETE FROM Link WHERE from_id=%d and to_id=%d", from, to).c_str());
}
void DBDriver::updateLink(const Link & link)
{
_dbSafeAccessMutex.lock();
this->updateLinkQuery(link);
_dbSafeAccessMutex.unlock();
}
void DBDriver::load(VWDictionary * dictionary) const void DBDriver::load(VWDictionary * dictionary) const
{ {
_dbSafeAccessMutex.lock(); _dbSafeAccessMutex.lock();
@@ -715,4 +739,155 @@ void DBDriver::addStatisticsAfterRun(int stMemSize, int lastSignAdded, int proce
} }
} }
void DBDriver::generateGraph(
const std::string & fileName,
const std::set<int> & idsInput,
const std::map<int, Signature *> & otherSignatures)
{
if(this->isConnected())
{
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;
}
std::set<int> ids;
if(idsInput.size() == 0)
{
this->getAllNodeIds(ids);
UDEBUG("ids.size()=%d", ids.size());
for(std::map<int, Signature*>::const_iterator iter=otherSignatures.begin(); iter!=otherSignatures.end(); ++iter)
{
ids.insert(iter->first);
}
}
else
{
ids = idsInput;
}
const char * colorG = "green";
const char * colorP = "pink";
; UINFO("Generating map with %d locations", ids.size());
fprintf(fout, "digraph G {\n");
for(std::set<int>::iterator i=ids.begin(); i!=ids.end(); ++i)
{
if(otherSignatures.find(*i) == otherSignatures.end())
{
int id = *i;
std::map<int, Link> links;
this->loadLinks(id, links);
int weight = 0;
this->getWeight(id, weight);
for(std::map<int, Link>::iterator iter = links.begin(); iter!=links.end(); ++iter)
{
int weightNeighbor = 0;
if(otherSignatures.find(iter->first) == otherSignatures.end())
{
this->getWeight(iter->first, weightNeighbor);
}
else
{
weightNeighbor = otherSignatures.find(iter->first)->second->getWeight();
}
//UDEBUG("Add neighbor link from %d to %d", id, iter->first);
if(iter->second.type() == Link::kNeighbor)
{
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\"\n",
id,
weight,
iter->first,
weightNeighbor);
}
else if(iter->first > id)
{
//loop
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"L\", fontcolor=%s, fontsize=8];\n",
id,
weight,
iter->first,
weightNeighbor,
colorG);
}
else
{
//child
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"C\", fontcolor=%s, fontsize=8];\n",
id,
weight,
iter->first,
weightNeighbor,
colorP);
}
}
}
}
for(std::map<int, Signature*>::const_iterator i=otherSignatures.begin(); i!=otherSignatures.end(); ++i)
{
if(ids.find(i->first) != ids.end())
{
int id = i->second->id();
const std::map<int, Link> & links = i->second->getLinks();
int weight = i->second->getWeight();
for(std::map<int, Link>::const_iterator iter = links.begin(); iter!=links.end(); ++iter)
{
int weightNeighbor = 0;
const Signature * s = uValue(otherSignatures, iter->first, (Signature*)0);
if(s)
{
weightNeighbor = s->getWeight();
}
else
{
this->getWeight(iter->first, weightNeighbor);
}
//UDEBUG("Add neighbor link from %d to %d", id, iter->first);
if(iter->second.type() == Link::kNeighbor)
{
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\"\n",
id,
weight,
iter->first,
weightNeighbor);
}
else if(iter->first > id)
{
//loop
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"L\", fontcolor=%s, fontsize=8];\n",
id,
weight,
iter->first,
weightNeighbor,
colorG);
}
else
{
//child
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"C\", fontcolor=%s, fontsize=8];\n",
id,
weight,
iter->first,
weightNeighbor,
colorP);
}
}
}
}
fprintf(fout, "}\n");
fclose(fout);
UINFO("Graph saved to \"%s\" (Tip: $ neato -Tpdf \"%s\" -o out.pdf)", fileName.c_str(), fileName.c_str());
}
}
}
} // namespace rtabmap } // namespace rtabmap
+85 -9
View File
@@ -2179,6 +2179,61 @@ void DBDriverSqlite3::saveQuery(const std::list<VisualWord *> & words) const
} }
} }
void DBDriverSqlite3::addLinkQuery(const Link & link) const
{
UDEBUG("");
if(_ppDb)
{
std::string type;
UTimer timer;
timer.start();
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
// Create new entries in table Link
std::string query = queryStepLink();
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
// Save link
stepLink(ppStmt, link);
// Finalize (delete) the statement
rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
UDEBUG("Time=%fs", timer.ticks());
}
}
void DBDriverSqlite3::updateLinkQuery(const Link & link) const
{
UDEBUG("");
if(_ppDb)
{
std::string type;
UTimer timer;
timer.start();
int rc = SQLITE_OK;
sqlite3_stmt * ppStmt = 0;
// Create new entries in table Link
std::string query = queryStepLinkUpdate();
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
// Save link
stepLink(ppStmt, link);
// Finalize (delete) the statement
rc = sqlite3_finalize(ppStmt);
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
UDEBUG("Time=%fs", timer.ticks());
}
}
std::string DBDriverSqlite3::queryStepNode() const std::string DBDriverSqlite3::queryStepNode() const
{ {
if(uStrNumCmp(_version, "0.10.1") >= 0) if(uStrNumCmp(_version, "0.10.1") >= 0)
@@ -2549,23 +2604,43 @@ void DBDriverSqlite3::stepSensorData(sqlite3_stmt * ppStmt,
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str()); UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
} }
std::string DBDriverSqlite3::queryStepLink() const std::string DBDriverSqlite3::queryStepLinkUpdate() const
{ {
if(uStrNumCmp(_version, "0.10.10") >= 0) if(uStrNumCmp(_version, "0.10.10") >= 0)
{ {
return "INSERT INTO Link(from_id, to_id, type, rot_variance, trans_variance, transform, user_data) VALUES(?,?,?,?,?,?,?);"; return "UPDATE Link SET type=?, rot_variance=?, trans_variance=?, transform=?, user_data=? WHERE from_id=? AND to_id = ?;";
} }
else if(uStrNumCmp(_version, "0.8.4") >= 0) else if(uStrNumCmp(_version, "0.8.4") >= 0)
{ {
return "INSERT INTO Link(from_id, to_id, type, rot_variance, trans_variance, transform) VALUES(?,?,?,?,?,?);"; return "UPDATE Link SET type=?, rot_variance=?, trans_variance=?, transform=? WHERE from_id=? AND to_id = ?;";
} }
else if(uStrNumCmp(_version, "0.7.4") >= 0) else if(uStrNumCmp(_version, "0.7.4") >= 0)
{ {
return "INSERT INTO Link(from_id, to_id, type, variance, transform) VALUES(?,?,?,?,?);"; return "UPDATE Link SET type=?, variance=?, transform=? WHERE from_id=? AND to_id = ?;";
} }
else else
{ {
return "INSERT INTO Link(from_id, to_id, type, transform) VALUES(?,?,?,?);"; return "UPDATE Link SET type=?, transform=? WHERE from_id=? AND to_id = ?;";
}
}
std::string DBDriverSqlite3::queryStepLink() const
{
// from_id, to_id are at the end to match the update query above
if(uStrNumCmp(_version, "0.10.10") >= 0)
{
return "INSERT INTO Link(type, rot_variance, trans_variance, transform, user_data, from_id, to_id) VALUES(?,?,?,?,?,?,?);";
}
else if(uStrNumCmp(_version, "0.8.4") >= 0)
{
return "INSERT INTO Link(type, rot_variance, trans_variance, transform, from_id, to_id) VALUES(?,?,?,?,?,?);";
}
else if(uStrNumCmp(_version, "0.7.4") >= 0)
{
return "INSERT INTO Link(type, variance, transform, from_id, to_id) VALUES(?,?,?,?,?);";
}
else
{
return "INSERT INTO Link(type, transform, from_id, to_id) VALUES(?,?,?,?);";
} }
} }
void DBDriverSqlite3::stepLink( void DBDriverSqlite3::stepLink(
@@ -2587,10 +2662,6 @@ void DBDriverSqlite3::stepLink(
int rc = SQLITE_OK; int rc = SQLITE_OK;
int index = 1; int index = 1;
rc = sqlite3_bind_int(ppStmt, index++, link.from());
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_int(ppStmt, index++, link.to());
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_int(ppStmt, index++, link.type()); rc = sqlite3_bind_int(ppStmt, index++, link.type());
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str()); UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
@@ -2624,6 +2695,11 @@ void DBDriverSqlite3::stepLink(
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str()); UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
} }
rc = sqlite3_bind_int(ppStmt, index++, link.from());
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
rc = sqlite3_bind_int(ppStmt, index++, link.to());
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
rc=sqlite3_step(ppStmt); rc=sqlite3_step(ppStmt);
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str()); UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
+4
View File
@@ -64,6 +64,9 @@ private:
virtual void updateQuery(const std::list<Signature *> & signatures, bool updateTimestamp) const; virtual void updateQuery(const std::list<Signature *> & signatures, bool updateTimestamp) const;
virtual void updateQuery(const std::list<VisualWord *> & words, bool updateTimestamp) const; virtual void updateQuery(const std::list<VisualWord *> & words, bool updateTimestamp) const;
virtual void addLinkQuery(const Link & link) const;
virtual void updateLinkQuery(const Link & link) const;
// Load objects // Load objects
virtual void loadQuery(VWDictionary * dictionary) const; virtual void loadQuery(VWDictionary * dictionary) const;
virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const; virtual void loadLastNodesQuery(std::list<Signature *> & signatures) const;
@@ -85,6 +88,7 @@ private:
std::string queryStepImage() const; std::string queryStepImage() const;
std::string queryStepDepth() const; std::string queryStepDepth() const;
std::string queryStepSensorData() const; std::string queryStepSensorData() const;
std::string queryStepLinkUpdate() const;
std::string queryStepLink() const; std::string queryStepLink() const;
std::string queryStepWordsChanged() const; std::string queryStepWordsChanged() const;
std::string queryStepKeypoint() const; std::string queryStepKeypoint() const;
+4 -232
View File
@@ -40,7 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/EpipolarGeometry.h> #include <rtabmap/core/EpipolarGeometry.h>
#include "rtabmap/core/VisualWord.h" #include "rtabmap/core/VisualWord.h"
#include "rtabmap/core/Features2d.h" #include "rtabmap/core/Features2d.h"
#include "DBDriverSqlite3.h" #include "rtabmap/core/DBDriver.h"
#include "rtabmap/core/util3d_features.h" #include "rtabmap/core/util3d_features.h"
#include "rtabmap/core/util3d_filtering.h" #include "rtabmap/core/util3d_filtering.h"
#include "rtabmap/core/util3d_correspondences.h" #include "rtabmap/core/util3d_correspondences.h"
@@ -184,7 +184,7 @@ bool Memory::init(const std::string & dbUrl, bool dbOverwritten, const Parameter
if(_dbDriver == 0 && !dbUrl.empty()) if(_dbDriver == 0 && !dbUrl.empty())
{ {
_dbDriver = new DBDriverSqlite3(parameters); _dbDriver = DBDriver::create(parameters);
} }
bool success = true; bool success = true;
@@ -3523,7 +3523,7 @@ SensorData Memory::getSignatureDataConst(int locationId) const
return r; return r;
} }
void Memory::generateGraph(const std::string & fileName, std::set<int> ids) void Memory::generateGraph(const std::string & fileName, const std::set<int> & ids)
{ {
if(!_dbDriver) if(!_dbDriver)
{ {
@@ -3531,235 +3531,7 @@ void Memory::generateGraph(const std::string & fileName, std::set<int> ids)
return; return;
} }
if(!fileName.empty()) _dbDriver->generateGraph(fileName, ids, _signatures);
{
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)
{
_dbDriver->getAllNodeIds(ids);
UDEBUG("ids.size()=%d", ids.size());
for(std::map<int, Signature*>::iterator iter=_signatures.begin(); iter!=_signatures.end(); ++iter)
{
ids.insert(iter->first);
}
}
const char * colorG = "green";
const char * colorP = "pink";
; UINFO("Generating map with %d locations", ids.size());
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;
std::map<int, Link> links;
_dbDriver->loadLinks(id, links);
int weight = 0;
_dbDriver->getWeight(id, weight);
for(std::map<int, Link>::iterator iter = links.begin(); iter!=links.end(); ++iter)
{
int weightNeighbor = 0;
if(_signatures.find(iter->first) == _signatures.end())
{
_dbDriver->getWeight(iter->first, weightNeighbor);
}
else
{
weightNeighbor = _signatures.find(iter->first)->second->getWeight();
}
//UDEBUG("Add neighbor link from %d to %d", id, iter->first);
if(iter->second.type() == Link::kNeighbor)
{
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\"\n",
id,
weight,
iter->first,
weightNeighbor);
}
else if(iter->first > id)
{
//loop
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"L\", fontcolor=%s, fontsize=8];\n",
id,
weight,
iter->first,
weightNeighbor,
colorG);
}
else
{
//child
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"C\", fontcolor=%s, fontsize=8];\n",
id,
weight,
iter->first,
weightNeighbor,
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();
const std::map<int, Link> & links = i->second->getLinks();
int weight = i->second->getWeight();
for(std::map<int, Link>::const_iterator iter = links.begin(); iter!=links.end(); ++iter)
{
int weightNeighbor = 0;
const Signature * s = this->getSignature(iter->first);
if(s)
{
weightNeighbor = s->getWeight();
}
else
{
_dbDriver->getWeight(iter->first, weightNeighbor);
}
//UDEBUG("Add neighbor link from %d to %d", id, iter->first);
if(iter->second.type() == Link::kNeighbor)
{
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\"\n",
id,
weight,
iter->first,
weightNeighbor);
}
else if(iter->first > id)
{
//loop
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"L\", fontcolor=%s, fontsize=8];\n",
id,
weight,
iter->first,
weightNeighbor,
colorG);
}
else
{
//child
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"C\", fontcolor=%s, fontsize=8];\n",
id,
weight,
iter->first,
weightNeighbor,
colorP);
}
}
}
}
fprintf(fout, "}\n");
fclose(fout);
UINFO("Graph saved to \"%s\"", fileName.c_str());
}
}
// Only used to generate a .dot file
class GraphNode
{
public:
GraphNode(int id, GraphNode * parent = 0) :
_parent(parent),
_id(id)
{
if(_parent)
{
_parent->addChild(this);
}
}
virtual ~GraphNode()
{
//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)
{
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)
{
return true;
}
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);
}
}
private:
void addChild(GraphNode * child)
{
_children.insert(child);
}
void removeChild(GraphNode * child)
{
_children.erase(child);
}
private:
std::set<GraphNode*> _children;
GraphNode * _parent;
int _id;
};
//recursive
void Memory::createGraph(GraphNode * parent, unsigned int maxDepth, const std::set<int> & endIds)
{
if(maxDepth == 0 || !parent)
{
return;
}
std::map<int, int> neighbors = this->getNeighborsId(parent->id(), 1, -1, false);
for(std::map<int, int>::iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
{
if(!parent->isAncestor(iter->first))
{
GraphNode * n = new GraphNode(iter->first, parent);
if(endIds.find(iter->first) == endIds.end())
{
this->createGraph(n, maxDepth-1, endIds);
}
}
}
} }
int Memory::getNi(int signatureId) const int Memory::getNi(int signatureId) const
+2 -2
View File
@@ -50,7 +50,7 @@ class QLabel;
namespace rtabmap namespace rtabmap
{ {
class Memory; class DBDriver;
class ImageView; class ImageView;
class SensorData; class SensorData;
class CloudViewer; class CloudViewer;
@@ -155,7 +155,7 @@ private:
QMap<int, int> idToIndex_; QMap<int, int> idToIndex_;
QList<rtabmap::Link> neighborLinks_; QList<rtabmap::Link> neighborLinks_;
QList<rtabmap::Link> loopLinks_; QList<rtabmap::Link> loopLinks_;
rtabmap::Memory * memory_; rtabmap::DBDriver * dbDriver_;
QString pathDatabase_; QString pathDatabase_;
std::string databaseFileName_; std::string databaseFileName_;
std::list<std::map<int, rtabmap::Transform> > graphes_; std::list<std::map<int, rtabmap::Transform> > graphes_;
+258 -159
View File
@@ -45,7 +45,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <opencv2/highgui/highgui.hpp> #include <opencv2/highgui/highgui.hpp>
#include <rtabmap/utilite/UTimer.h> #include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/UFile.h> #include <rtabmap/utilite/UFile.h>
#include "rtabmap/core/Memory.h"
#include "rtabmap/core/DBDriver.h" #include "rtabmap/core/DBDriver.h"
#include "rtabmap/gui/KeypointItem.h" #include "rtabmap/gui/KeypointItem.h"
#include "rtabmap/utilite/UCv2Qt.h" #include "rtabmap/utilite/UCv2Qt.h"
@@ -57,6 +56,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/util3d_mapping.h" #include "rtabmap/core/util3d_mapping.h"
#include "rtabmap/core/util2d.h" #include "rtabmap/core/util2d.h"
#include "rtabmap/core/Signature.h" #include "rtabmap/core/Signature.h"
#include "rtabmap/core/Memory.h"
#include "rtabmap/core/Features2d.h" #include "rtabmap/core/Features2d.h"
#include "rtabmap/core/Compression.h" #include "rtabmap/core/Compression.h"
#include "rtabmap/core/Graph.h" #include "rtabmap/core/Graph.h"
@@ -74,7 +74,7 @@ namespace rtabmap {
DatabaseViewer::DatabaseViewer(QWidget * parent) : DatabaseViewer::DatabaseViewer(QWidget * parent) :
QMainWindow(parent), QMainWindow(parent),
memory_(0), dbDriver_(0),
savedMaximized_(false), savedMaximized_(false),
firstCall_(true) firstCall_(true)
{ {
@@ -332,9 +332,9 @@ DatabaseViewer::DatabaseViewer(QWidget * parent) :
DatabaseViewer::~DatabaseViewer() DatabaseViewer::~DatabaseViewer()
{ {
delete ui_; delete ui_;
if(memory_) if(dbDriver_)
{ {
delete memory_; delete dbDriver_;
} }
} }
@@ -577,10 +577,10 @@ bool DatabaseViewer::openDatabase(const QString & path)
UDEBUG("Open database \"%s\"", path.toStdString().c_str()); UDEBUG("Open database \"%s\"", path.toStdString().c_str());
if(QFile::exists(path)) if(QFile::exists(path))
{ {
if(memory_) if(dbDriver_)
{ {
delete memory_; delete dbDriver_;
memory_ = 0; dbDriver_ = 0;
ids_.clear(); ids_.clear();
idToIndex_.clear(); idToIndex_.clear();
neighborLinks_.clear(); neighborLinks_.clear();
@@ -602,16 +602,10 @@ bool DatabaseViewer::openDatabase(const QString & path)
} }
std::string driverType = "sqlite3"; std::string driverType = "sqlite3";
rtabmap::ParametersMap parameters;
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kDbSqlite3InMemory(), "false"));
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kMemIncrementalMemory(), "false"));
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kMemInitWMWithAllNodes(), "true"));
// use BruteForce dictionary because we don't know which type of descriptors are saved in database
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kKpNNStrategy(), "3"));
memory_ = new rtabmap::Memory(); dbDriver_ = DBDriver::create();
if(!memory_->init(path.toStdString(), false, parameters)) if(!dbDriver_->openConnection(path.toStdString()))
{ {
QMessageBox::warning(this, "Database error", tr("Can't open database \"%1\"").arg(path)); QMessageBox::warning(this, "Database error", tr("Can't open database \"%1\"").arg(path));
} }
@@ -673,21 +667,13 @@ void DatabaseViewer::closeEvent(QCloseEvent* event)
std::multimap<int, rtabmap::Link>::iterator refinedIter = rtabmap::graph::findLink(linksRefined_, iter->second.from(), iter->second.to()); std::multimap<int, rtabmap::Link>::iterator refinedIter = rtabmap::graph::findLink(linksRefined_, iter->second.from(), iter->second.to());
if(refinedIter != linksRefined_.end()) if(refinedIter != linksRefined_.end())
{ {
memory_->addLink(Link( dbDriver_->addLink(refinedIter->second);
refinedIter->second.from(), dbDriver_->addLink(refinedIter->second.inverse());
refinedIter->second.to(),
refinedIter->second.type(),
refinedIter->second.transform(),
refinedIter->second.infMatrix()));
} }
else else
{ {
memory_->addLink(Link( dbDriver_->addLink(iter->second);
iter->second.from(), dbDriver_->addLink(iter->second.inverse());
iter->second.to(),
iter->second.type(),
iter->second.transform(),
iter->second.infMatrix()));
} }
} }
@@ -696,18 +682,16 @@ void DatabaseViewer::closeEvent(QCloseEvent* event)
{ {
if(!containsLink(linksAdded_, iter->second.from(), iter->second.to())) if(!containsLink(linksAdded_, iter->second.from(), iter->second.to()))
{ {
memory_->updateLink( dbDriver_->updateLink(iter->second);
iter->second.from(), dbDriver_->updateLink(iter->second.inverse());
iter->second.to(),
iter->second.transform(),
iter->second.infMatrix());
} }
} }
// Rejected links // Rejected links
for(std::multimap<int, rtabmap::Link>::iterator iter=linksRemoved_.begin(); iter!=linksRemoved_.end(); ++iter) for(std::multimap<int, rtabmap::Link>::iterator iter=linksRemoved_.begin(); iter!=linksRemoved_.end(); ++iter)
{ {
memory_->removeLink(iter->second.to(), iter->second.from()); dbDriver_->removeLink(iter->second.to(), iter->second.from());
dbDriver_->removeLink(iter->second.from(), iter->second.to());
} }
} }
@@ -727,10 +711,10 @@ void DatabaseViewer::closeEvent(QCloseEvent* event)
if(event->isAccepted()) if(event->isAccepted())
{ {
if(memory_) if(dbDriver_)
{ {
delete memory_; delete dbDriver_;
memory_ = 0; dbDriver_ = 0;
} }
} }
} }
@@ -778,7 +762,7 @@ bool DatabaseViewer::eventFilter(QObject *obj, QEvent *event)
void DatabaseViewer::exportDatabase() void DatabaseViewer::exportDatabase()
{ {
if(!memory_ || ids_.size() == 0) if(!dbDriver_ || ids_.size() == 0)
{ {
return; return;
} }
@@ -807,7 +791,7 @@ void DatabaseViewer::exportDatabase()
int mapId = -1; int mapId = -1;
std::string label; std::string label;
double stamp = 0; double stamp = 0;
if(memory_->getNodeInfo(ids_[i], odomPose, mapId, weight, label, stamp, true)) if(dbDriver_->getNodeInfo(ids_[i], odomPose, mapId, weight, label, stamp))
{ {
if(frameRate == 0 || if(frameRate == 0 ||
previousStamp == 0 || previousStamp == 0 ||
@@ -846,17 +830,17 @@ void DatabaseViewer::exportDatabase()
{ {
int id = ids.at(i); int id = ids.at(i);
SensorData data = memory_->getNodeData(id, true, false); SensorData data;
dbDriver_->getNodeData(id, data);
data.uncompressData();
cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1); cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
if(dialog.isOdomExported()) if(dialog.isOdomExported())
{ {
if(memory_->getSignature(id) == 0) std::map<int, Link> links;
dbDriver_->loadLinks(id, links, Link::kNeighbor);
if(links.size() && links.begin()->first < id)
{ {
UERROR("could not find node %d in memory.", id); covariance = links.begin()->second.infMatrix().inv();
}
else
{
covariance = memory_->getSignature(id)->getPoseCovariance();
} }
} }
@@ -916,7 +900,7 @@ void DatabaseViewer::exportDatabase()
void DatabaseViewer::extractImages() void DatabaseViewer::extractImages()
{ {
if(!memory_ || ids_.size() == 0) if(!dbDriver_ || ids_.size() == 0)
{ {
return; return;
} }
@@ -927,7 +911,9 @@ void DatabaseViewer::extractImages()
if(ids_.size()) if(ids_.size())
{ {
int id = ids_.at(0); int id = ids_.at(0);
SensorData data = memory_->getNodeData(id, true, false); SensorData data;
dbDriver_->getNodeData(id, data);
data.uncompressData();
if(!data.imageRaw().empty() && !data.rightRaw().empty()) if(!data.imageRaw().empty() && !data.rightRaw().empty())
{ {
QDir dir; QDir dir;
@@ -1009,7 +995,9 @@ void DatabaseViewer::extractImages()
for(int i=0; i<ids_.size(); ++i) for(int i=0; i<ids_.size(); ++i)
{ {
int id = ids_.at(i); int id = ids_.at(i);
SensorData data = memory_->getNodeData(id, true, false); SensorData data;
dbDriver_->getNodeData(id, data);
data.uncompressData();
if(!data.imageRaw().empty() && !data.rightRaw().empty()) if(!data.imageRaw().empty() && !data.rightRaw().empty())
{ {
cv::imwrite(QString("%1/left/%2.jpg").arg(path).arg(id).toStdString(), data.imageRaw()); cv::imwrite(QString("%1/left/%2.jpg").arg(path).arg(id).toStdString(), data.imageRaw());
@@ -1033,15 +1021,22 @@ void DatabaseViewer::extractImages()
void DatabaseViewer::updateIds() void DatabaseViewer::updateIds()
{ {
if(!memory_) if(!dbDriver_)
{ {
return; return;
} }
std::set<int> ids = memory_->getAllSignatureIds(); std::set<int> ids;
dbDriver_->getAllNodeIds(ids);
ids_ = QList<int>::fromStdList(std::list<int>(ids.begin(), ids.end())); ids_ = QList<int>::fromStdList(std::list<int>(ids.begin(), ids.end()));
idToIndex_.clear(); idToIndex_.clear();
mapIds_.clear(); mapIds_.clear();
poses_.clear();
links_.clear();
linksAdded_.clear();
linksRefined_.clear();
linksRemoved_.clear();
ui_->label_optimizeFrom->setText(tr("Optimize from"));
for(int i=0; i<ids_.size(); ++i) for(int i=0; i<ids_.size(); ++i)
{ {
idToIndex_.insert(ids_[i], i); idToIndex_.insert(ids_[i], i);
@@ -1051,22 +1046,27 @@ void DatabaseViewer::updateIds()
std::string l; std::string l;
double s; double s;
int mapId; int mapId;
memory_->getNodeInfo(ids_[i], p, mapId, w, l, s, true); dbDriver_->getNodeInfo(ids_[i], p, mapId, w, l, s);
mapIds_.insert(std::make_pair(ids_[i], mapId)); mapIds_.insert(std::make_pair(ids_[i], mapId));
poses_.insert(std::make_pair(ids_[i], p));
//links
std::map<int, Link> neighbors;
dbDriver_->loadLinks(ids_[i], neighbors); // including loop closures
for(std::map<int, Link>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter)
{
if( jter->second.isValid() && // null transform means a rehearsed location
uContains(poses_, jter->first) &&
graph::findLink(links_, ids_[i], jter->first) == links_.end() &&
(jter->second.type() == Link::kNeighbor || jter->first < ids_[i])) //Loop parent to child
{
links_.insert(std::make_pair(ids_[i], jter->second));
}
}
} }
poses_.clear(); if(ids.size())
links_.clear();
linksAdded_.clear();
linksRefined_.clear();
linksRemoved_.clear();
ui_->label_optimizeFrom->setText(tr("Optimize from"));
if(memory_->getLastWorkingSignature())
{ {
//get constraints only for parent links
memory_->getMetricConstraints(ids, poses_, links_, true);
if(poses_.size()) if(poses_.size())
{ {
bool nullPoses = poses_.begin()->second.isNull(); bool nullPoses = poses_.begin()->second.isNull();
@@ -1092,9 +1092,9 @@ void DatabaseViewer::updateIds()
} }
int first = *ids.begin(); int first = *ids.begin();
ui_->spinBox_optimizationsFrom->setRange(first, memory_->getLastWorkingSignature()->id()); ui_->spinBox_optimizationsFrom->setRange(first, ids_.last());
ui_->spinBox_optimizationsFrom->setValue(memory_->getLastWorkingSignature()->id()); ui_->spinBox_optimizationsFrom->setValue(ids_.first());
ui_->label_optimizeFrom->setText(tr("Optimize from [%1, %2]").arg(first).arg(memory_->getLastWorkingSignature()->id())); ui_->label_optimizeFrom->setText(tr("Optimize from [%1, %2]").arg(first).arg(ids_.first()));
} }
} }
@@ -1167,7 +1167,7 @@ void DatabaseViewer::updateIds()
void DatabaseViewer::generateGraph() void DatabaseViewer::generateGraph()
{ {
if(!memory_) if(!dbDriver_)
{ {
QMessageBox::warning(this, tr("Cannot generate a graph"), tr("A database must must loaded first...\nUse File->Open database.")); QMessageBox::warning(this, tr("Cannot generate a graph"), tr("A database must must loaded first...\nUse File->Open database."));
return; return;
@@ -1176,13 +1176,13 @@ void DatabaseViewer::generateGraph()
QString path = QFileDialog::getSaveFileName(this, tr("Save File"), pathDatabase_+"/Graph.dot", tr("Graphiz file (*.dot)")); QString path = QFileDialog::getSaveFileName(this, tr("Save File"), pathDatabase_+"/Graph.dot", tr("Graphiz file (*.dot)"));
if(!path.isEmpty()) if(!path.isEmpty())
{ {
memory_->generateGraph(path.toStdString()); dbDriver_->generateGraph(path.toStdString());
} }
} }
void DatabaseViewer::generateLocalGraph() void DatabaseViewer::generateLocalGraph()
{ {
if(!ids_.size() || !memory_) if(!ids_.size() || !dbDriver_)
{ {
QMessageBox::warning(this, tr("Cannot generate a graph"), tr("The database is empty...")); QMessageBox::warning(this, tr("Cannot generate a graph"), tr("The database is empty..."));
return; return;
@@ -1196,9 +1196,53 @@ void DatabaseViewer::generateLocalGraph()
if(ok) if(ok)
{ {
QString path = QFileDialog::getSaveFileName(this, tr("Save File"), pathDatabase_+"/Graph" + QString::number(id) + ".dot", tr("Graphiz file (*.dot)")); QString path = QFileDialog::getSaveFileName(this, tr("Save File"), pathDatabase_+"/Graph" + QString::number(id) + ".dot", tr("Graphiz file (*.dot)"));
if(!path.isEmpty()) if(!path.isEmpty() && id>0)
{ {
std::map<int, int> ids = memory_->getNeighborsId(id, margin, -1, false); std::map<int, int> ids;
std::list<int> curentMarginList;
std::set<int> currentMargin;
std::set<int> nextMargin;
nextMargin.insert(id);
int m = 0;
while((margin == 0 || m < margin) && nextMargin.size())
{
curentMarginList = std::list<int>(nextMargin.rbegin(), nextMargin.rend());
nextMargin.clear();
for(std::list<int>::iterator jter = curentMarginList.begin(); jter!=curentMarginList.end(); ++jter)
{
if(ids.find(*jter) == ids.end())
{
std::map<int, Link> links;
ids.insert(std::pair<int, int>(*jter, m));
UTimer timer;
dbDriver_->loadLinks(*jter, links);
// links
for(std::map<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
{
if( !uContains(ids, iter->first))
{
UASSERT(iter->second.type() != Link::kUndef);
if(iter->second.type() == Link::kNeighbor)
{
nextMargin.insert(iter->first);
}
else
{
// loop closures are on same margin
if(currentMargin.insert(iter->first).second)
{
curentMarginList.push_back(iter->first);
}
}
}
}
}
}
++m;
}
if(ids.size() > 0) if(ids.size() > 0)
{ {
@@ -1210,7 +1254,7 @@ void DatabaseViewer::generateLocalGraph()
UINFO("Node %d", iter->first); UINFO("Node %d", iter->first);
} }
UINFO("idsSet=%d", idsSet.size()); UINFO("idsSet=%d", idsSet.size());
memory_->generateGraph(path.toStdString(), idsSet); dbDriver_->generateGraph(path.toStdString(), idsSet);
} }
else else
{ {
@@ -1287,7 +1331,7 @@ void DatabaseViewer::generateG2OGraph()
void DatabaseViewer::view3DMap() void DatabaseViewer::view3DMap()
{ {
if(!ids_.size() || !memory_) if(!ids_.size() || !dbDriver_)
{ {
QMessageBox::warning(this, tr("Cannot view 3D map"), tr("The database is empty...")); QMessageBox::warning(this, tr("Cannot view 3D map"), tr("The database is empty..."));
return; return;
@@ -1350,7 +1394,9 @@ void DatabaseViewer::view3DMap()
rtabmap::Transform pose = iter->second; rtabmap::Transform pose = iter->second;
if(!pose.isNull()) if(!pose.isNull())
{ {
SensorData data = memory_->getNodeData(iter->first, true, false); SensorData data;
dbDriver_->getNodeData(iter->first, data);
data.uncompressData();
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud; pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
UASSERT(data.imageRaw().empty() || data.imageRaw().type()==CV_8UC3 || data.imageRaw().type() == CV_8UC1); UASSERT(data.imageRaw().empty() || data.imageRaw().type()==CV_8UC3 || data.imageRaw().type() == CV_8UC1);
UASSERT(data.depthOrRightRaw().empty() || data.depthOrRightRaw().type()==CV_8UC1 || data.depthOrRightRaw().type() == CV_16UC1 || data.depthOrRightRaw().type() == CV_32FC1); UASSERT(data.depthOrRightRaw().empty() || data.depthOrRightRaw().type()==CV_8UC1 || data.depthOrRightRaw().type() == CV_16UC1 || data.depthOrRightRaw().type() == CV_32FC1);
@@ -1363,7 +1409,7 @@ void DatabaseViewer::view3DMap()
Transform odomPose; Transform odomPose;
std::string label; std::string label;
double stamp; double stamp;
if(memory_->getNodeInfo(iter->first, odomPose, mapId, weight, label, stamp, true)) if(dbDriver_->getNodeInfo(iter->first, odomPose, mapId, weight, label, stamp))
{ {
color = (Qt::GlobalColor)(mapId % 12 + 7 ); color = (Qt::GlobalColor)(mapId % 12 + 7 );
} }
@@ -1394,7 +1440,7 @@ void DatabaseViewer::view3DMap()
void DatabaseViewer::generate3DMap() void DatabaseViewer::generate3DMap()
{ {
if(!ids_.size() || !memory_) if(!ids_.size() || !dbDriver_)
{ {
QMessageBox::warning(this, tr("Cannot generate a graph"), tr("The database is empty...")); QMessageBox::warning(this, tr("Cannot generate a graph"), tr("The database is empty..."));
return; return;
@@ -1434,7 +1480,9 @@ void DatabaseViewer::generate3DMap()
const rtabmap::Transform & pose = iter->second; const rtabmap::Transform & pose = iter->second;
if(!pose.isNull()) if(!pose.isNull())
{ {
SensorData data = memory_->getNodeData(iter->first, true, false); SensorData data;
dbDriver_->getNodeData(iter->first, data);
data.uncompressData();
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud; pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
UASSERT(data.imageRaw().empty() || data.imageRaw().type()==CV_8UC3 || data.imageRaw().type() == CV_8UC1); UASSERT(data.imageRaw().empty() || data.imageRaw().type()==CV_8UC3 || data.imageRaw().type() == CV_8UC1);
UASSERT(data.depthOrRightRaw().empty() || data.depthOrRightRaw().type()==CV_8UC1 || data.depthOrRightRaw().type() == CV_16UC1 || data.depthOrRightRaw().type() == CV_32FC1); UASSERT(data.depthOrRightRaw().empty() || data.depthOrRightRaw().type()==CV_8UC1 || data.depthOrRightRaw().type() == CV_16UC1 || data.depthOrRightRaw().type() == CV_32FC1);
@@ -1696,9 +1744,11 @@ void DatabaseViewer::update(int value,
//image //image
QImage img; QImage img;
QImage imgDepth; QImage imgDepth;
if(memory_) if(dbDriver_)
{ {
SensorData data = memory_->getNodeData(id, true, false); SensorData data;
dbDriver_->getNodeData(id, data);
data.uncompressData();
if(!data.imageRaw().empty()) if(!data.imageRaw().empty())
{ {
img = uCvMat2QImage(data.imageRaw()); img = uCvMat2QImage(data.imageRaw());
@@ -1708,18 +1758,23 @@ void DatabaseViewer::update(int value,
imgDepth = uCvMat2QImage(data.depthOrRightRaw()); imgDepth = uCvMat2QImage(data.depthOrRightRaw());
} }
const Signature * signature = memory_->getSignature(id); std::list<int> ids;
ids.push_back(id);
std::list<Signature*> signatures;
dbDriver_->loadSignatures(ids, signatures);
if(signature && signature->getWords().size()) if(signatures.size() && signatures.front()!=0 && signatures.front()->getWords().size())
{ {
view->setFeatures(signature->getWords(), data.depthOrRightRaw().type() == CV_8UC1?cv::Mat():data.depthOrRightRaw(), Qt::yellow); view->setFeatures(signatures.front()->getWords(), data.depthOrRightRaw().type() == CV_8UC1?cv::Mat():data.depthOrRightRaw(), Qt::yellow);
delete signatures.front();
signatures.clear();
} }
Transform odomPose; Transform odomPose;
int w; int w;
std::string l; std::string l;
double s; double s;
memory_->getNodeInfo(id, odomPose, mapId, w, l, s, true); dbDriver_->getNodeInfo(id, odomPose, mapId, w, l, s);
weight->setNum(w); weight->setNum(w);
label->setText(l.c_str()); label->setText(l.c_str());
@@ -1781,20 +1836,23 @@ void DatabaseViewer::update(int value,
} }
// loops // loops
std::map<int, rtabmap::Link> loopClosures; std::map<int, rtabmap::Link> links;
loopClosures = memory_->getLoopClosureLinks(id, true); dbDriver_->loadLinks(id, links);
if(loopClosures.size()) if(links.size())
{ {
QString strParents, strChildren; QString strParents, strChildren;
for(std::map<int, rtabmap::Link>::iterator iter=loopClosures.begin(); iter!=loopClosures.end(); ++iter) for(std::map<int, rtabmap::Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
{ {
if(iter->first < id) if(iter->second.type() != Link::kNeighbor)
{ {
strChildren.append(QString("%1 ").arg(iter->first)); if(iter->first < id)
} {
else strChildren.append(QString("%1 ").arg(iter->first));
{ }
strParents.append(QString("%1 ").arg(iter->first)); else
{
strParents.append(QString("%1 ").arg(iter->first));
}
} }
} }
labelParents->setText(strParents); labelParents->setText(strParents);
@@ -1906,7 +1964,9 @@ void DatabaseViewer::updateStereo()
if(ui_->horizontalSlider_A->maximum()) if(ui_->horizontalSlider_A->maximum())
{ {
int id = ids_.at(ui_->horizontalSlider_A->value()); int id = ids_.at(ui_->horizontalSlider_A->value());
SensorData data = memory_->getNodeData(id, true, false); SensorData data;
dbDriver_->getNodeData(id, data);
data.uncompressData();
updateStereo(&data); updateStereo(&data);
} }
} }
@@ -2240,7 +2300,7 @@ void DatabaseViewer::updateConstraintView(
ui_->label_constraint->clear(); ui_->label_constraint->clear();
ui_->label_constraint_opt->clear(); ui_->label_constraint_opt->clear();
ui_->checkBox_showOptimized->setEnabled(false); ui_->checkBox_showOptimized->setEnabled(false);
UASSERT(!t.isNull() && memory_); UASSERT(!t.isNull() && dbDriver_);
ui_->label_type->setNum(link.type()); ui_->label_type->setNum(link.type());
ui_->label_variance->setText(QString("%1, %2") ui_->label_variance->setText(QString("%1, %2")
@@ -2316,11 +2376,13 @@ void DatabaseViewer::updateConstraintView(
{ {
SensorData dataFrom, dataTo; SensorData dataFrom, dataTo;
dataFrom = memory_->getNodeData(link.from(), true, false); dbDriver_->getNodeData(link.from(), dataFrom);
dataFrom.uncompressData();
UASSERT(dataFrom.imageRaw().empty() || dataFrom.imageRaw().type()==CV_8UC3 || dataFrom.imageRaw().type() == CV_8UC1); UASSERT(dataFrom.imageRaw().empty() || dataFrom.imageRaw().type()==CV_8UC3 || dataFrom.imageRaw().type() == CV_8UC1);
UASSERT(dataFrom.depthOrRightRaw().empty() || dataFrom.depthOrRightRaw().type()==CV_8UC1 || dataFrom.depthOrRightRaw().type() == CV_16UC1 || dataFrom.depthOrRightRaw().type() == CV_32FC1); UASSERT(dataFrom.depthOrRightRaw().empty() || dataFrom.depthOrRightRaw().type()==CV_8UC1 || dataFrom.depthOrRightRaw().type() == CV_16UC1 || dataFrom.depthOrRightRaw().type() == CV_32FC1);
dataTo = memory_->getNodeData(link.to(), true, false); dbDriver_->getNodeData(link.to(), dataTo);
dataTo.uncompressData();
UASSERT(dataTo.imageRaw().empty() || dataTo.imageRaw().type()==CV_8UC3 || dataTo.imageRaw().type() == CV_8UC1); UASSERT(dataTo.imageRaw().empty() || dataTo.imageRaw().type()==CV_8UC3 || dataTo.imageRaw().type() == CV_8UC1);
UASSERT(dataTo.depthOrRightRaw().empty() || dataTo.depthOrRightRaw().type()==CV_8UC1 || dataTo.depthOrRightRaw().type() == CV_16UC1 || dataTo.depthOrRightRaw().type() == CV_32FC1); UASSERT(dataTo.depthOrRightRaw().empty() || dataTo.depthOrRightRaw().type()==CV_8UC1 || dataTo.depthOrRightRaw().type() == CV_16UC1 || dataTo.depthOrRightRaw().type() == CV_32FC1);
@@ -2351,10 +2413,16 @@ void DatabaseViewer::updateConstraintView(
} }
if(ui_->checkBox_show3DWords->isChecked()) if(ui_->checkBox_show3DWords->isChecked())
{ {
const Signature * sFrom = memory_->getSignature(link.from()); std::list<int> ids;
const Signature * sTo = memory_->getSignature(link.to()); ids.push_back(link.from());
if(sFrom && sTo) ids.push_back(link.to());
std::list<Signature*> signatures;
dbDriver_->loadSignatures(ids, signatures);
if(signatures.size() == 2)
{ {
const Signature * sFrom = signatures.front();
const Signature * sTo = signatures.back();
UASSERT(sFrom && sTo);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFrom(new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloudFrom(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTo(new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloudTo(new pcl::PointCloud<pcl::PointXYZ>);
cloudFrom->resize(sFrom->getWords3().size()); cloudFrom->resize(sFrom->getWords3().size());
@@ -2412,6 +2480,11 @@ void DatabaseViewer::updateConstraintView(
ui_->constraintsViewer->removeCloud("words0"); ui_->constraintsViewer->removeCloud("words0");
ui_->constraintsViewer->removeCloud("words1"); ui_->constraintsViewer->removeCloud("words1");
} }
//cleanup
for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
{
delete *iter;
}
} }
else else
{ {
@@ -2539,7 +2612,8 @@ void DatabaseViewer::updateConstraintView(
if(iter->first != link.to()) // already added to view if(iter->first != link.to()) // already added to view
{ {
//create scan //create scan
SensorData data = memory_->getNodeData(iter->first, false); SensorData data;
dbDriver_->getNodeData(iter->first, data);
cv::Mat scan; cv::Mat scan;
data.uncompressDataConst(0, 0, &scan, 0); data.uncompressDataConst(0, 0, &scan, 0);
if(!scan.empty()) if(!scan.empty())
@@ -2684,7 +2758,7 @@ void DatabaseViewer::updateConstraintButtons()
void DatabaseViewer::sliderIterationsValueChanged(int value) void DatabaseViewer::sliderIterationsValueChanged(int value)
{ {
if(memory_ && value >=0 && value < (int)graphes_.size()) if(dbDriver_ && value >=0 && value < (int)graphes_.size())
{ {
std::map<int, rtabmap::Transform> & graph = uValueAt(graphes_, value); std::map<int, rtabmap::Transform> & graph = uValueAt(graphes_, value);
std::map<int, rtabmap::Transform> graphFiltered = graph; std::map<int, rtabmap::Transform> graphFiltered = graph;
@@ -2707,7 +2781,9 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
bool added = false; bool added = false;
if(ui_->groupBox_gridFromProjection->isChecked()) if(ui_->groupBox_gridFromProjection->isChecked())
{ {
SensorData data = memory_->getNodeData(ids.at(i), true, false); SensorData data;
dbDriver_->getNodeData(ids.at(i), data);
data.uncompressData();
if(!data.depthOrRightRaw().empty()) if(!data.depthOrRightRaw().empty())
{ {
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud; pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
@@ -2741,7 +2817,8 @@ void DatabaseViewer::sliderIterationsValueChanged(int value)
} }
else else
{ {
SensorData data = memory_->getNodeData(ids.at(i), false); SensorData data;
dbDriver_->getNodeData(ids.at(i), data);
if(!data.laserScanCompressed().empty()) if(!data.laserScanCompressed().empty())
{ {
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud; pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;
@@ -3114,8 +3191,8 @@ void DatabaseViewer::refineConstraint(int from, int to, bool silent, bool update
Transform transform; Transform transform;
SensorData dataFrom, dataTo; SensorData dataFrom, dataTo;
dataFrom = memory_->getNodeData(currentLink.from(), false); dbDriver_->getNodeData(currentLink.from(), dataFrom);
dataTo = memory_->getNodeData(currentLink.to(), false); dbDriver_->getNodeData(currentLink.to(), dataTo);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA(new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloudA(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB(new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointXYZ>::Ptr cloudB(new pcl::PointCloud<pcl::PointXYZ>);
@@ -3337,31 +3414,35 @@ void DatabaseViewer::refineConstraintVisually(int from, int to, bool silent, boo
return; return;
} }
// create a fake memory to compute transform
ParametersMap parameters;
parameters.insert(ParametersPair(Parameters::kKpDetectorStrategy(), uNumber2Str(ui_->comboBox_featureType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kKpNNStrategy(), uNumber2Str(ui_->comboBox_nnType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value())));
parameters.insert(ParametersPair(Parameters::kKpMaxDepth(), uNumber2Str(ui_->doubleSpinBox_visual_maxDepth->value())));
parameters.insert(ParametersPair(Parameters::kKpNndrRatio(), uNumber2Str(ui_->doubleSpinBox_visual_nndr->value())));
parameters.insert(ParametersPair(Parameters::kLccBowIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value())));
parameters.insert(ParametersPair(Parameters::kLccBowMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value())));
parameters.insert(ParametersPair(Parameters::kLccBowEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
parameters.insert(ParametersPair(Parameters::kMemGenerateIds(), "false"));
parameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0"));
parameters.insert(ParametersPair(Parameters::kKpWordsPerImage(), "0"));
Memory tmpMemory(parameters);
Transform t; Transform t;
std::string rejectedMsg; std::string rejectedMsg;
double variance = -1.0; double variance = -1.0;
int inliers = -1; int inliers = -1;
if(ui_->groupBox_visual_recomputeFeatures->isChecked()) if(ui_->groupBox_visual_recomputeFeatures->isChecked())
{ {
// create a fake memory to regenerate features // Add sensor data to generate features
ParametersMap parameters; SensorData dataFrom;
parameters.insert(ParametersPair(Parameters::kKpDetectorStrategy(), uNumber2Str(ui_->comboBox_featureType->currentIndex()))); dbDriver_->getNodeData(from, dataFrom);
parameters.insert(ParametersPair(Parameters::kKpNNStrategy(), uNumber2Str(ui_->comboBox_nnType->currentIndex()))); dataFrom.uncompressData();
parameters.insert(ParametersPair(Parameters::kLccBowInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value()))); SensorData dataTo;
parameters.insert(ParametersPair(Parameters::kKpMaxDepth(), uNumber2Str(ui_->doubleSpinBox_visual_maxDepth->value()))); dbDriver_->getNodeData(to, dataTo);
parameters.insert(ParametersPair(Parameters::kKpNndrRatio(), uNumber2Str(ui_->doubleSpinBox_visual_nndr->value()))); dataTo.uncompressData();
parameters.insert(ParametersPair(Parameters::kLccBowIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value())));
parameters.insert(ParametersPair(Parameters::kLccBowMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value())));
parameters.insert(ParametersPair(Parameters::kLccBowEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
parameters.insert(ParametersPair(Parameters::kMemGenerateIds(), "false"));
parameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0"));
parameters.insert(ParametersPair(Parameters::kKpWordsPerImage(), "0"));
Memory tmpMemory(parameters);
// Add signatures
SensorData dataFrom = memory_->getNodeData(from, true, false);
SensorData dataTo = memory_->getNodeData(to, true, false);
if(from > to) if(from > to)
{ {
@@ -3379,14 +3460,21 @@ void DatabaseViewer::refineConstraintVisually(int from, int to, bool silent, boo
} }
else else
{ {
ParametersMap parameters; std::list<int> ids;
parameters.insert(ParametersPair(Parameters::kLccBowInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value()))); ids.push_back(to);
parameters.insert(ParametersPair(Parameters::kLccBowIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value()))); ids.push_back(from);
parameters.insert(ParametersPair(Parameters::kLccBowMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value()))); std::list<Signature*> signatures;
parameters.insert(ParametersPair(Parameters::kLccBowEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex()))); dbDriver_->loadSignatures(ids, signatures);
parameters.insert(ParametersPair(Parameters::kLccBowPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
memory_->parseParameters(parameters); if(signatures.size() == 2)
t = memory_->computeVisualTransform(to, from, &rejectedMsg, &inliers, &variance); {
t = tmpMemory.computeVisualTransform(*signatures.front(), *signatures.back(), &rejectedMsg, &inliers, &variance);
}
//cleanup
for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
{
delete *iter;
}
} }
if(!t.isNull()) if(!t.isNull())
@@ -3458,31 +3546,35 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent, bool updateGra
UASSERT(!containsLink(linksRemoved_, from, to)); UASSERT(!containsLink(linksRemoved_, from, to));
UASSERT(!containsLink(linksRefined_, from, to)); UASSERT(!containsLink(linksRefined_, from, to));
// create a fake memory to compute the transform
ParametersMap parameters;
parameters.insert(ParametersPair(Parameters::kKpDetectorStrategy(), uNumber2Str(ui_->comboBox_featureType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kKpNNStrategy(), uNumber2Str(ui_->comboBox_nnType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value())));
parameters.insert(ParametersPair(Parameters::kKpMaxDepth(), uNumber2Str(ui_->doubleSpinBox_visual_maxDepth->value())));
parameters.insert(ParametersPair(Parameters::kKpNndrRatio(), uNumber2Str(ui_->doubleSpinBox_visual_nndr->value())));
parameters.insert(ParametersPair(Parameters::kLccBowIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value())));
parameters.insert(ParametersPair(Parameters::kLccBowMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value())));
parameters.insert(ParametersPair(Parameters::kLccBowEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
parameters.insert(ParametersPair(Parameters::kMemGenerateIds(), "false"));
parameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0"));
parameters.insert(ParametersPair(Parameters::kKpWordsPerImage(), "0"));
Memory tmpMemory(parameters);
Transform t; Transform t;
std::string rejectedMsg; std::string rejectedMsg;
double variance = -1.0; double variance = -1.0;
int inliers = -1; int inliers = -1;
if(ui_->groupBox_visual_recomputeFeatures->isChecked()) if(ui_->groupBox_visual_recomputeFeatures->isChecked())
{ {
// create a fake memory to regenerate features // Add sensor data to generate features
ParametersMap parameters; SensorData dataFrom;
parameters.insert(ParametersPair(Parameters::kKpDetectorStrategy(), uNumber2Str(ui_->comboBox_featureType->currentIndex()))); dbDriver_->getNodeData(from, dataFrom);
parameters.insert(ParametersPair(Parameters::kKpNNStrategy(), uNumber2Str(ui_->comboBox_nnType->currentIndex()))); dataFrom.uncompressData();
parameters.insert(ParametersPair(Parameters::kLccBowInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value()))); SensorData dataTo;
parameters.insert(ParametersPair(Parameters::kKpMaxDepth(), uNumber2Str(ui_->doubleSpinBox_visual_maxDepth->value()))); dbDriver_->getNodeData(to, dataTo);
parameters.insert(ParametersPair(Parameters::kKpNndrRatio(), uNumber2Str(ui_->doubleSpinBox_visual_nndr->value()))); dataTo.uncompressData();
parameters.insert(ParametersPair(Parameters::kLccBowIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value())));
parameters.insert(ParametersPair(Parameters::kLccBowMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value())));
parameters.insert(ParametersPair(Parameters::kLccBowEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex())));
parameters.insert(ParametersPair(Parameters::kLccBowPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
parameters.insert(ParametersPair(Parameters::kMemGenerateIds(), "false"));
parameters.insert(ParametersPair(Parameters::kMemRehearsalSimilarity(), "1.0"));
parameters.insert(ParametersPair(Parameters::kKpWordsPerImage(), "0"));
Memory tmpMemory(parameters);
// Add signatures
SensorData dataFrom = memory_->getNodeData(from, true, false);
SensorData dataTo = memory_->getNodeData(to, true, false);
if(from > to) if(from > to)
{ {
@@ -3507,14 +3599,21 @@ bool DatabaseViewer::addConstraint(int from, int to, bool silent, bool updateGra
} }
else else
{ {
ParametersMap parameters; std::list<int> ids;
parameters.insert(ParametersPair(Parameters::kLccBowInlierDistance(), uNumber2Str(ui_->doubleSpinBox_visual_maxCorrespDistance->value()))); ids.push_back(to);
parameters.insert(ParametersPair(Parameters::kLccBowIterations(), uNumber2Str(ui_->spinBox_visual_iteration->value()))); ids.push_back(from);
parameters.insert(ParametersPair(Parameters::kLccBowMinInliers(), uNumber2Str(ui_->spinBox_visual_minCorrespondences->value()))); std::list<Signature*> signatures;
parameters.insert(ParametersPair(Parameters::kLccBowEstimationType(), uNumber2Str(ui_->comboBox_estimationType->currentIndex()))); dbDriver_->loadSignatures(ids, signatures);
parameters.insert(ParametersPair(Parameters::kLccBowPnPFlags(), uNumber2Str(ui_->comboBox_pnpFlags->currentIndex())));
memory_->parseParameters(parameters); if(signatures.size() == 2)
t = memory_->computeVisualTransform(to, from, &rejectedMsg, &inliers, &variance); {
t = tmpMemory.computeVisualTransform(*signatures.front(), *signatures.back(), &rejectedMsg, &inliers, &variance);
}
//cleanup
for(std::list<Signature*>::iterator iter=signatures.begin(); iter!=signatures.end(); ++iter)
{
delete *iter;
}
} }
if(!t.isNull()) if(!t.isNull())
+1 -1
View File
@@ -3198,7 +3198,7 @@ void MainWindow::generateGraphDOT()
this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdGenerateDOTGraph, false, path.toStdString(), id, margin)); this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdGenerateDOTGraph, false, path.toStdString(), id, margin));
_ui->dockWidget_console->show(); _ui->dockWidget_console->show();
_ui->widget_console->appendMsg(QString("Graph saved... Tip:\nneato -Tpdf \"%1\" -o out.pdf").arg(_graphSavingFileName).arg(_graphSavingFileName)); _ui->widget_console->appendMsg(QString("Graph saved... Tip:\nneato -Tpdf \"%1\" -o out.pdf").arg(_graphSavingFileName));
} }
} }
} }