g2o
Loading...
Searching...
No Matches
main_window.cpp
Go to the documentation of this file.
1// g2o - General Graph Optimization
2// Copyright (C) 2011 R. Kuemmerle, G. Grisetti, W. Burgard
3//
4// This file is part of g2o.
5//
6// g2o is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10//
11// g2o is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with g2o. If not, see <http://www.gnu.org/licenses/>.
18
19#include "main_window.h"
20
21#include <QComboBox>
22#include <QDoubleValidator>
23#include <QFileDialog>
24#include <QStandardItemModel>
25#include <cassert>
26#include <fstream>
27#include <iostream>
28
37using namespace std;
38using namespace g2o;
39
40MainWindow::MainWindow(QWidget* parent)
41 : QMainWindow(parent),
42 _lastSolver(-1),
43 _currentSolver(0),
44 _viewerPropertiesWidget(0),
45 _optimizerPropertiesWidget(0),
46 _filename("") {
47 setupUi(this);
48 leKernelWidth->setValidator(new QDoubleValidator(
49 -numeric_limits<double>::max(), numeric_limits<double>::max(), 7, this));
50 plainTextEdit->setMaximumBlockCount(1000);
51 btnForceStop->hide();
52 QObject::connect(cbDrawAxis, SIGNAL(toggled(bool)), viewer,
53 SLOT(setAxisIsDrawn(bool)));
54}
55
57
59 QString filename = QFileDialog::getOpenFileName(
60 this, "Load g2o file", "", "g2o files (*.g2o);;All Files (*)");
61 if (!filename.isNull()) {
62 loadFromFile(filename);
63 }
64}
65
67 QString filename = QFileDialog::getSaveFileName(this, "Save g2o file", "",
68 "g2o files (*.g2o)");
69 if (!filename.isNull()) {
70 ofstream fout(filename.toStdString().c_str());
71 viewer->graph->save(fout);
72 if (fout.good())
73 cerr << "Saved " << filename.toStdString() << endl;
74 else
75 cerr << "Error while saving file" << endl;
76 }
77}
78
80 if (viewer->graph->vertices().size() == 0 ||
81 viewer->graph->edges().size() == 0) {
82 cerr << "Graph has no vertices / edges" << endl;
83 return;
84 }
85
86 bool allocatedNewSolver;
87 bool allocateStatus = allocateSolver(allocatedNewSolver);
88 if (!allocateStatus) {
89 cerr << "Error while allocating solver" << endl;
90 return;
91 }
92 if (allocatedNewSolver) prepare();
94
95 btnOptimize->hide();
96 btnForceStop->show();
97
98 _forceStopFlag = false;
99 viewer->graph->setForceStopFlag(&_forceStopFlag);
100
101 int maxIterations = spIterations->value();
102 int iter = viewer->graph->optimize(maxIterations);
103 if (maxIterations > 0 && !iter) {
104 cerr << "Optimization failed, result might be invalid" << endl;
105 }
106
107 btnOptimize->show();
108 btnForceStop->hide();
109
110 viewer->setUpdateDisplay(true);
111 viewer->update();
112 _forceStopFlag = false;
113}
114
116 if (viewer->graph->activeEdges().size() == 0)
117 viewer->graph->initializeOptimization();
118
119 switch (cbxIniitialGuessMethod->currentIndex()) {
120 case 0:
121 // spanning tree
122 viewer->graph->computeInitialGuess();
123 break;
124 case 1:
125 // odometry
126 {
127 EstimatePropagatorCostOdometry costFunction(viewer->graph);
128 viewer->graph->computeInitialGuess(costFunction);
129 }
130 break;
131 default:
132 cerr << __PRETTY_FUNCTION__ << " Unknown initialization method" << endl;
133 break;
134 }
135
136 viewer->setUpdateDisplay(true);
137 viewer->update();
138}
139
141 if (viewer->graph->activeEdges().size() == 0)
142 viewer->graph->initializeOptimization();
143
144 viewer->graph->setToOrigin();
145 viewer->setUpdateDisplay(true);
146 viewer->update();
147}
148
150 if (_filename.length() > 0) {
151 cerr << "reloading " << _filename << endl;
152 viewer->graph->clear();
153 viewer->graph->load(_filename.c_str());
154 viewer->setUpdateDisplay(true);
155 viewer->update();
156 }
157}
158
160 if (viewer->graph->vertices().size() == 0 ||
161 viewer->graph->edges().size() == 0) {
162 return;
163 }
164
165 // check for vertices to fix to remove DoF
166 bool gaugeFreedom = viewer->graph->gaugeFreedom();
167 g2o::OptimizableGraph::Vertex* gauge = viewer->graph->findGauge();
168 if (gaugeFreedom) {
169 if (!gauge) {
170 cerr << "cannot find a vertex to fix in this thing" << endl;
171 return;
172 } else {
173 cerr << "graph is fixed by node " << gauge->id() << endl;
174 gauge->setFixed(true);
175 }
176 } else {
177 cerr << "graph is fixed by priors or nodes are already fixed" << endl;
178 }
179
180 viewer->graph->setVerbose(true);
181 // viewer->graph->computeActiveErrors();
182}
183
185
187 coOptimizer->clear();
188 _knownSolvers.clear();
191
192 bool varFound = false;
193 string varType = "";
194 for (OptimizationAlgorithmFactory::CreatorList::const_iterator it =
195 knownSolvers.begin();
196 it != knownSolvers.end(); ++it) {
197 const OptimizationAlgorithmProperty& sp = (*it)->property();
198 if (sp.name == "gn_var" || sp.name == "gn_var_cholmod") {
199 varType = sp.type;
200 varFound = true;
201 break;
202 }
203 }
204
205 if (varFound) {
206 for (OptimizationAlgorithmFactory::CreatorList::const_iterator it =
207 knownSolvers.begin();
208 it != knownSolvers.end(); ++it) {
209 const OptimizationAlgorithmProperty& sp = (*it)->property();
210 if (sp.type == varType) {
211 coOptimizer->addItem(QString::fromStdString(sp.name));
212 _knownSolvers.push_back(sp);
213 }
214 }
215 }
216
217 map<string, vector<OptimizationAlgorithmProperty> > solverLookUp;
218
219 for (OptimizationAlgorithmFactory::CreatorList::const_iterator it =
220 knownSolvers.begin();
221 it != knownSolvers.end(); ++it) {
222 const OptimizationAlgorithmProperty& sp = (*it)->property();
223 if (varFound && varType == sp.type) continue;
224 solverLookUp[sp.type].push_back(sp);
225 }
226
227 for (map<string, vector<OptimizationAlgorithmProperty> >::iterator it =
228 solverLookUp.begin();
229 it != solverLookUp.end(); ++it) {
230 if (_knownSolvers.size() > 0) {
231 coOptimizer->insertSeparator(coOptimizer->count());
233 }
234 const vector<OptimizationAlgorithmProperty>& vsp = it->second;
235 for (size_t j = 0; j < vsp.size(); ++j) {
236 coOptimizer->addItem(QString::fromStdString(vsp[j].name));
237 _knownSolvers.push_back(vsp[j]);
238 }
239 }
240}
241
242bool MainWindow::load(const QString& filename) {
243 viewer->graph->clear();
244 bool loadStatus = false;
245 if (filename == "-") {
246 cerr << "reading stdin" << endl;
247 loadStatus = viewer->graph->load(cin);
248 } else {
249 ifstream ifs(filename.toStdString().c_str());
250 if (!ifs) return false;
251 loadStatus = viewer->graph->load(ifs);
252 }
253 if (!loadStatus) return false;
254 _lastSolver = -1;
255 viewer->setUpdateDisplay(true);
256 SparseOptimizer* optimizer = viewer->graph;
257
258 // update the solvers which are suitable for this graph
259 set<int> vertDims = optimizer->dimensions();
260 for (size_t i = 0; i < _knownSolvers.size(); ++i) {
262 if (sp.name == "" && sp.desc == "") continue;
263
264 bool suitableSolver = optimizer->isSolverSuitable(sp, vertDims);
265 qobject_cast<QStandardItemModel*>(coOptimizer->model())
266 ->item(i)
267 ->setEnabled(suitableSolver);
268 }
269 return loadStatus;
270}
271
272bool MainWindow::allocateSolver(bool& allocatedNewSolver) {
273 if (coOptimizer->count() == 0) {
274 cerr << "No solvers available" << endl;
275 return false;
276 }
277 int currentIndex = coOptimizer->currentIndex();
278 bool enabled = qobject_cast<QStandardItemModel*>(coOptimizer->model())
279 ->item(currentIndex)
280 ->isEnabled();
281
282 if (!enabled) {
283 cerr << "selected solver is not enabled" << endl;
284 return false;
285 }
286
287 if (currentIndex == _lastSolver) return true;
288
289 allocatedNewSolver = true;
290 QString strSolver = coOptimizer->currentText();
291
292 // delete the old optimization algorithm
293 OptimizationAlgorithm* algorithmPointer =
294 const_cast<OptimizationAlgorithm*>(viewer->graph->algorithm());
295 viewer->graph->setAlgorithm(0);
296 delete algorithmPointer;
297
298 // create the new algorithm
299 OptimizationAlgorithmFactory* solverFactory =
301 _currentSolver = solverFactory->construct(
302 strSolver.toStdString(), _currentOptimizationAlgorithmProperty);
303 viewer->graph->setAlgorithm(_currentSolver);
304
305 _lastSolver = currentIndex;
306 return true;
307}
308
310 SparseOptimizer* optimizer = viewer->graph;
312 cerr << "Marginalizing Landmarks" << endl;
313 for (SparseOptimizer::VertexIDMap::const_iterator it =
314 optimizer->vertices().begin();
315 it != optimizer->vertices().end(); ++it) {
317 static_cast<OptimizableGraph::Vertex*>(it->second);
318 int vdim = v->dimension();
321 }
322 } else {
323 cerr << "Preparing (no marginalization of Landmarks)" << endl;
324 for (SparseOptimizer::VertexIDMap::const_iterator it =
325 optimizer->vertices().begin();
326 it != optimizer->vertices().end(); ++it) {
328 static_cast<OptimizableGraph::Vertex*>(it->second);
329 v->setMarginalized(false);
330 }
331 }
332 viewer->graph->initializeOptimization();
333 return true;
334}
335
337 SparseOptimizer* optimizer = viewer->graph;
338 bool robustKernel = cbRobustKernel->isChecked();
339 double huberWidth = leKernelWidth->text().toDouble();
340 // odometry edges are those whose node ids differ by 1
341
342 bool onlyLoop = cbOnlyLoop->isChecked();
343
344 if (robustKernel) {
345 QString strRobustKernel = coRobustKernel->currentText();
347 RobustKernelFactory::instance()->creator(strRobustKernel.toStdString());
348 if (!creator) {
349 cerr << strRobustKernel.toStdString() << " is not a valid robust kernel"
350 << endl;
351 return;
352 }
353 for (SparseOptimizer::EdgeSet::const_iterator it =
354 optimizer->edges().begin();
355 it != optimizer->edges().end(); ++it) {
356 OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
357 if (onlyLoop) {
358 if (e->vertices().size() >= 2 &&
359 std::abs(e->vertex(0)->id() - e->vertex(1)->id()) != 1) {
360 e->setRobustKernel(creator->construct());
361 e->robustKernel()->setDelta(huberWidth);
362 }
363 } else {
364 e->setRobustKernel(creator->construct());
365 e->robustKernel()->setDelta(huberWidth);
366 }
367 }
368 } else {
369 for (SparseOptimizer::EdgeSet::const_iterator it =
370 optimizer->edges().begin();
371 it != optimizer->edges().end(); ++it) {
372 OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
373 e->setRobustKernel(0);
374 }
375 }
376}
377
379
380bool MainWindow::loadFromFile(const QString& filename) {
381 viewer->graph->clear();
382 bool loadStatus = load(filename);
383 if (loadStatus) {
384 _filename = filename.toStdString();
385 }
386 cerr << "loaded " << filename.toStdString() << " with "
387 << viewer->graph->vertices().size() << " vertices and "
388 << viewer->graph->edges().size() << " measurements" << endl;
389 viewer->update();
390 fixGraph();
391 return loadStatus;
392}
393
395 viewer->setBackgroundColor(QColor::fromRgb(255, 255, 255));
396 viewer->update();
397}
398
400 viewer->setBackgroundColor(QColor::fromRgb(51, 51, 51));
401 viewer->update();
402}
403
407 _viewerPropertiesWidget->setWindowTitle(tr("Drawing Options"));
408 }
411}
412
416 _optimizerPropertiesWidget->setWindowTitle(
417 tr("Internal Solver Properties"));
418 }
419 bool allocatedNewSolver;
420 bool allocateStatus = allocateSolver(allocatedNewSolver);
421 if (!allocateStatus) {
422 cerr << "Error while allocating solver" << endl;
423 return;
424 }
425 if (allocatedNewSolver) prepare();
426 if (_currentSolver) {
428 const_cast<g2o::PropertyMap*>(&_currentSolver->properties()));
429 } else {
431 }
433}
434
436 QString selectedFilter;
437 QString filename = QFileDialog::getSaveFileName(
438 this, "Save screen to a file", "viewer.png",
439 "PNG files (*.png);;JPG files (*.jpg);;EPS files (*.eps)",
440 &selectedFilter);
441
442 if (!filename.isNull()) {
443 // extract the file format from the filter options
444 int spacePos = selectedFilter.indexOf(' ');
445 assert(spacePos > 0 && "extracting the image format failed");
446 QString format = selectedFilter.left(spacePos);
447 // setting up the snapshot and save to file
448 if (format == "JPG") {
449 viewer->setSnapshotQuality(90);
450 } else {
451 viewer->setSnapshotQuality(-1);
452 }
453 viewer->setSnapshotFormat(format);
454 viewer->saveSnapshot(filename);
455 cerr << "saved snapshot " << filename.toStdString() << "("
456 << format.toStdString() << ")" << endl;
457 }
458}
459
461 QString filename = QFileDialog::getOpenFileName(
462 this, "Load State", "camera.xml", "Camera/State file (*.xml)");
463 if (!filename.isEmpty()) {
464 viewer->setStateFileName(filename);
465 viewer->restoreStateFromFile();
466 viewer->setStateFileName(QString());
467 viewer->update();
468 cerr << "Loaded state from " << filename.toStdString() << endl;
469 }
470}
471
473 QString filename = QFileDialog::getSaveFileName(
474 this, "Save State", "camera.xml", "Camera/State file (*.xml)");
475 if (!filename.isEmpty()) {
476 viewer->setStateFileName(filename);
477 viewer->saveStateToFile();
478 viewer->setStateFileName(QString());
479 cerr << "Saved state to " << filename.toStdString() << endl;
480 }
481}
482
484 coRobustKernel->clear();
485 std::vector<std::string> kernels;
487 for (size_t i = 0; i < kernels.size(); ++i) {
488 coRobustKernel->addItem(QString::fromStdString(kernels[i]));
489 }
490}
void on_btnOptimizerParameters_clicked()
void updateDisplayedSolvers()
bool allocateSolver(bool &allocatedNewSolver)
void on_actionSave_Viewer_State_triggered(bool)
void fixGraph()
void on_btnOptimize_clicked()
bool loadFromFile(const QString &filename)
void updateRobustKernels()
int _lastSolver
Definition main_window.h:88
ViewerPropertiesWidget * _viewerPropertiesWidget
Definition main_window.h:93
void on_btnSetZero_clicked()
g2o::OptimizationAlgorithm * _currentSolver
Definition main_window.h:91
void on_actionSave_triggered(bool)
PropertiesWidget * _optimizerPropertiesWidget
Definition main_window.h:94
void on_actionProperties_triggered(bool)
std::vector< g2o::OptimizationAlgorithmProperty > _knownSolvers
Definition main_window.h:87
void on_btnInitialGuess_clicked()
void on_actionLoad_triggered(bool)
g2o::OptimizationAlgorithmProperty _currentOptimizationAlgorithmProperty
Definition main_window.h:90
void on_actionSave_Screenshot_triggered(bool)
MainWindow(QWidget *parent=0)
void on_actionQuit_triggered(bool)
void setRobustKernel()
void on_btnReload_clicked()
void on_actionLoad_Viewer_State_triggered(bool)
void on_btnForceStop_clicked()
bool load(const QString &filename)
bool _forceStopFlag
Definition main_window.h:89
void on_actionDefault_Background_triggered(bool)
std::string _filename
Definition main_window.h:95
void on_actionWhite_Background_triggered(bool)
void setProperties(g2o::PropertyMap *properties)
void setViewer(g2o::G2oQGLViewer *viewer)
Abstract interface for allocating a robust kernel.
virtual RobustKernel * construct()=0
cost for traversing only odometry edges.
const VertexContainer & vertices() const
const Vertex * vertex(size_t i) const
int id() const
returns the id
const EdgeSet & edges() const
const VertexIDMap & vertices() const
void setRobustKernel(RobustKernel *ptr)
RobustKernel * robustKernel() const
if NOT NULL, error of this edge will be robustifed with the kernel
A general case Vertex for optimization.
int dimension() const
dimension of the estimated state belonging to this node
const OptimizableGraph * graph() const
void setFixed(bool fixed)
true => this node should be considered fixed during the optimization
void setMarginalized(bool marginalized)
true => this node should be marginalized out during the optimization
create solvers based on their short name
const CreatorList & creatorList() const
return the underlying list of creators
OptimizationAlgorithm * construct(const std::string &tag, OptimizationAlgorithmProperty &solverProperty) const
static OptimizationAlgorithmFactory * instance()
return the instance
std::list< std::shared_ptr< AbstractOptimizationAlgorithmCreator > > CreatorList
Generic interface for a non-linear solver operating on a graph.
const PropertyMap & properties() const
return the properties of the solver
a collection of properties mapping from name to the property itself
Definition property.h:78
void fillKnownKernels(std::vector< std::string > &types) const
AbstractRobustKernelCreator * creator(const std::string &tag) const
static RobustKernelFactory * instance()
return the instance
virtual void setDelta(double delta)
#define __PRETTY_FUNCTION__
Definition macros.h:90
Definition jet.h:876
std::set< int > dimensions() const
bool isSolverSuitable(const OptimizationAlgorithmProperty &solverProperty, const std::set< int > &vertDims=std::set< int >()) const
std::string type
type of solver, e.g., "CSparse Cholesky", "PCG"
std::string desc
short description of the solver
int landmarkDim
dimension of the landmark vertices (-1 if variable)
std::string name
name of the solver, e.g., var