OptmizerG2O: add prior edge export (#319)

* OptmizerG2O: add prior edge export

* add required conditions and structure to export prior edges

* for now, make the graph exportation of priors not dependent of parameters

* include <locale.h> so to use setlocale() in a windows build
This commit is contained in:
Nuno Marques
2018-10-15 16:58:57 +01:00
committed by matlabbe
parent 444b511548
commit 42c60c7154
6 changed files with 49 additions and 24 deletions

View File

@@ -44,14 +44,14 @@ public:
const std::string & fileName, const std::string & fileName,
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & edgeConstraints, const std::multimap<int, Link> & edgeConstraints,
bool useRobustConstraints = false); const bool useRobustConstraints = false);
public: public:
OptimizerG2O(const ParametersMap & parameters = ParametersMap()) : OptimizerG2O(const ParametersMap & parameters = ParametersMap()) :
Optimizer(parameters), Optimizer(parameters),
solver_(Parameters::defaultg2oSolver()), solver_(Parameters::defaultg2oSolver()),
optimizer_(Parameters::defaultg2oOptimizer()), optimizer_(Parameters::defaultg2oOptimizer()),
pixelVariance_(Parameters::defaultg2oPixelVariance()), pixelVariance_(Parameters::defaultg2oPixelVariance()),
robustKernelDelta_(Parameters::defaultg2oRobustKernelDelta()), robustKernelDelta_(Parameters::defaultg2oRobustKernelDelta()),
baseline_(Parameters::defaultg2oBaseline()) baseline_(Parameters::defaultg2oBaseline())
{ {

View File

@@ -56,7 +56,7 @@ bool exportPoses(
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & constraints, // required for formats 3 and 4 const std::multimap<int, Link> & constraints, // required for formats 3 and 4
const std::map<int, double> & stamps, // required for format 1 const std::map<int, double> & stamps, // required for format 1
bool g2oRobust) // optional for format 4 const bool g2oRobust) // optional for format 4
{ {
UDEBUG("%s", filePath.c_str()); UDEBUG("%s", filePath.c_str());
std::string tmpPath = filePath; std::string tmpPath = filePath;
@@ -366,8 +366,8 @@ bool importPoses(
std::vector<std::string> strList = uListToVector(uSplit(str)); std::vector<std::string> strList = uListToVector(uSplit(str));
if(strList.size() == 3) if(strList.size() == 3)
{ {
if( uIsNumber(uReplaceChar(strList[0], ' ', "")) && if( uIsNumber(uReplaceChar(strList[0], ' ', "")) &&
uIsNumber(uReplaceChar(strList[1], ' ', "")) && uIsNumber(uReplaceChar(strList[1], ' ', "")) &&
uIsNumber(uReplaceChar(strList[2], ' ', "")) && uIsNumber(uReplaceChar(strList[2], ' ', "")) &&
(strList.size()==3 || uIsNumber(uReplaceChar(strList[3], ' ', "")))) (strList.size()==3 || uIsNumber(uReplaceChar(strList[3], ' ', ""))))
{ {
@@ -379,7 +379,7 @@ bool importPoses(
{ {
stamps->insert(std::make_pair(id, stamp)); stamps->insert(std::make_pair(id, stamp));
} }
float yaw = 0.0f; float yaw = 0.0f;
if(uContains(poses, id-1)) if(uContains(poses, id-1))
{ {
// set yaw depending on successive poses // set yaw depending on successive poses

View File

@@ -2304,7 +2304,7 @@ bool Rtabmap::process(
UINFO("Update map correction"); UINFO("Update map correction");
std::map<int, Transform> poses = _optimizedPoses; std::map<int, Transform> poses = _optimizedPoses;
// if _optimizeFromGraphEnd parameter just changed state, don't use optimized poses as guess // if _optimizeFromGraphEnd parameter just changed state, don't use optimized poses as guess
float normMapCorrection = _mapCorrection.getNormSquared(); // use distance for identity detection float normMapCorrection = _mapCorrection.getNormSquared(); // use distance for identity detection
if((normMapCorrection > 0.000001f && _optimizeFromGraphEnd) || if((normMapCorrection > 0.000001f && _optimizeFromGraphEnd) ||
@@ -4694,7 +4694,7 @@ void Rtabmap::updateGoalIndex()
this->clearPath(-1); this->clearPath(-1);
return; return;
} }
} }
} }
else if(!isStuck) else if(!isStuck)
{ {

View File

@@ -348,12 +348,12 @@ bool RtabmapThread::handleEvent(UEvent* event)
} }
} }
else else
{ {
OdometryInfo infoCov; OdometryInfo infoCov;
infoCov.reg.covariance = e->info().odomCovariance; infoCov.reg.covariance = e->info().odomCovariance;
this->addData(OdometryEvent(e->data(), e->info().odomPose, infoCov)); this->addData(OdometryEvent(e->data(), e->info().odomPose, infoCov));
} }
} }
} }
else if(event->getClassName().compare("OdometryEvent") == 0) else if(event->getClassName().compare("OdometryEvent") == 0)

View File

@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UMath.h> #include <rtabmap/utilite/UMath.h>
#include <rtabmap/utilite/UConversion.h> #include <rtabmap/utilite/UConversion.h>
#include <rtabmap/utilite/UTimer.h> #include <rtabmap/utilite/UTimer.h>
#include <locale.h>
#include <set> #include <set>
#include <rtabmap/core/Version.h> #include <rtabmap/core/Version.h>
@@ -1363,7 +1364,7 @@ bool OptimizerG2O::saveGraph(
const std::string & fileName, const std::string & fileName,
const std::map<int, Transform> & poses, const std::map<int, Transform> & poses,
const std::multimap<int, Link> & edgeConstraints, const std::multimap<int, Link> & edgeConstraints,
bool useRobustConstraints) const bool useRobustConstraints)
{ {
FILE * file = 0; FILE * file = 0;
@@ -1375,6 +1376,22 @@ bool OptimizerG2O::saveGraph(
if(file) if(file)
{ {
// force periods to be used instead of commas
setlocale(LC_ALL, "en_US.UTF-8");
// PARAMS_SE3OFFSET id x y z qw qx qy qz (set for priors)
Eigen::Vector3f v = Eigen::Vector3f::Zero();
Eigen::Quaternionf q = Eigen::Quaternionf::Identity();
fprintf(file, "PARAMS_SE3OFFSET %d %f %f %f %f %f %f %f\n",
PARAM_OFFSET,
v.x(),
v.y(),
v.z(),
q.x(),
q.y(),
q.z(),
q.w());
// VERTEX_SE3 id x y z qw qx qy qz // VERTEX_SE3 id x y z qw qx qy qz
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter) for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{ {
@@ -1390,12 +1407,14 @@ bool OptimizerG2O::saveGraph(
q.w()); q.w());
} }
//EDGE_SE3 observed_vertex_id observing_vertex_id x y z qx qy qz qw inf_11 inf_12 .. inf_16 inf_22 .. inf_66 // EDGE_SE3 observed_vertex_id observing_vertex_id x y z qx qy qz qw inf_11 inf_12 .. inf_16 inf_22 .. inf_66
// EDGE_SE3_PRIOR observed_vertex_id x y z qx qy qz qw inf_11 inf_12 .. inf_16 inf_22 .. inf_66
int virtualVertexId = poses.size()?poses.rbegin()->first+1:0; int virtualVertexId = poses.size()?poses.rbegin()->first+1:0;
for(std::multimap<int, Link>::const_iterator iter = edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter) for(std::multimap<int, Link>::const_iterator iter = edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
{ {
std::string prefix = "EDGE_SE3:QUAT"; std::string prefix = "EDGE_SE3:QUAT";
std::string suffix = ""; std::string suffix = "";
std::string to = uFormat(" %d", iter->second.to());
if(useRobustConstraints && if(useRobustConstraints &&
iter->second.type() != Link::kNeighbor && iter->second.type() != Link::kNeighbor &&
@@ -1406,12 +1425,17 @@ bool OptimizerG2O::saveGraph(
fprintf(file, "EDGE_SWITCH_PRIOR %d 1 1.0\n", virtualVertexId); fprintf(file, "EDGE_SWITCH_PRIOR %d 1 1.0\n", virtualVertexId);
suffix = uFormat(" %d", virtualVertexId++); suffix = uFormat(" %d", virtualVertexId++);
} }
else if(iter->second.type() == Link::kPosePrior)
{
prefix = "EDGE_SE3_PRIOR";
to = uFormat(" %d", PARAM_OFFSET);
}
Eigen::Quaternionf q = iter->second.transform().getQuaternionf(); Eigen::Quaternionf q = iter->second.transform().getQuaternionf();
fprintf(file, "%s %d %d%s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n", fprintf(file, "%s %d%s%s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f\n",
prefix.c_str(), prefix.c_str(),
iter->second.from(), iter->second.from(),
iter->second.to(), to.c_str(),
suffix.c_str(), suffix.c_str(),
iter->second.transform().x(), iter->second.transform().x(),
iter->second.transform().y(), iter->second.transform().y(),
@@ -1443,6 +1467,7 @@ bool OptimizerG2O::saveGraph(
iter->second.infMatrix().at<double>(5,5)); iter->second.infMatrix().at<double>(5,5));
} }
UINFO("Graph saved to %s", fileName.c_str()); UINFO("Graph saved to %s", fileName.c_str());
fclose(file); fclose(file);
} }
else else

View File

@@ -208,9 +208,9 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent, bool sh
// Add cloud viewers // Add cloud viewers
// Note that we add them here manually because there is a crash issue // Note that we add them here manually because there is a crash issue
// when adding them in a DockWidget of the *.ui file. The cloud viewer is // when adding them in a DockWidget of the *.ui file. The cloud viewer is
// created in a widget which is not yet linked to main window when the CloudViewer constructor // created in a widget which is not yet linked to main window when the CloudViewer constructor
// is called (see order in generated ui file). VTK needs to get the top // is called (see order in generated ui file). VTK needs to get the top
// level window at the time CloudViewer is created, otherwise it may crash on some systems. // level window at the time CloudViewer is created, otherwise it may crash on some systems.
_cloudViewer = new CloudViewer(_ui->layout_cloudViewer); _cloudViewer = new CloudViewer(_ui->layout_cloudViewer);
_cloudViewer->setObjectName("widget_cloudViewer"); _cloudViewer->setObjectName("widget_cloudViewer");
@@ -394,7 +394,7 @@ MainWindow::MainWindow(PreferencesDialog * prefDialog, QWidget * parent, bool sh
_ui->actionPause->setShortcut(Qt::Key_Space); _ui->actionPause->setShortcut(Qt::Key_Space);
_ui->actionSave_GUI_config->setShortcut(QKeySequence::Save); _ui->actionSave_GUI_config->setShortcut(QKeySequence::Save);
// Qt5 issue, we should explicitly add actions not in // Qt5 issue, we should explicitly add actions not in
// menu bar to have shortcut working // menu bar to have shortcut working
this->addAction(_ui->actionSave_GUI_config); this->addAction(_ui->actionSave_GUI_config);
_ui->actionReset_Odometry->setEnabled(false); _ui->actionReset_Odometry->setEnabled(false);
@@ -670,23 +670,23 @@ void MainWindow::setupMainLayout(bool vertical)
} }
void MainWindow::setCloudViewer(rtabmap::CloudViewer * cloudViewer) void MainWindow::setCloudViewer(rtabmap::CloudViewer * cloudViewer)
{ {
UASSERT(cloudViewer); UASSERT(cloudViewer);
delete _cloudViewer; delete _cloudViewer;
_cloudViewer = cloudViewer; _cloudViewer = cloudViewer;
_cloudViewer->setParent(_ui->layout_cloudViewer); _cloudViewer->setParent(_ui->layout_cloudViewer);
_cloudViewer->setObjectName("widget_cloudViewer"); _cloudViewer->setObjectName("widget_cloudViewer");
_ui->layout_cloudViewer->layout()->addWidget(_cloudViewer); _ui->layout_cloudViewer->layout()->addWidget(_cloudViewer);
_cloudViewer->setBackfaceCulling(true, false); _cloudViewer->setBackfaceCulling(true, false);
_preferencesDialog->loadWidgetState(_cloudViewer); _preferencesDialog->loadWidgetState(_cloudViewer);
connect(_cloudViewer, SIGNAL(configChanged()), this, SLOT(configGUIModified())); connect(_cloudViewer, SIGNAL(configChanged()), this, SLOT(configGUIModified()));
} }
void MainWindow::setLoopClosureViewer(rtabmap::LoopClosureViewer * loopClosureViewer) void MainWindow::setLoopClosureViewer(rtabmap::LoopClosureViewer * loopClosureViewer)
{ {
UASSERT(loopClosureViewer); UASSERT(loopClosureViewer);
delete _loopClosureViewer; delete _loopClosureViewer;
_loopClosureViewer = loopClosureViewer; _loopClosureViewer = loopClosureViewer;
_loopClosureViewer->setParent(_ui->layout_loopClosureViewer); _loopClosureViewer->setParent(_ui->layout_loopClosureViewer);
_loopClosureViewer->setObjectName("widget_loopClosureViewer"); _loopClosureViewer->setObjectName("widget_loopClosureViewer");