mirror of
https://github.com/introlab/rtabmap_ros.git
synced 2026-10-04 00:37:46 +08:00
DatabaseViewer: using DBDriver directly instead of Memory to save RAM on large databases
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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())
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user