g2o
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"
21 
28 #include "g2o/core/robust_kernel.h"
29 
30 #include <QFileDialog>
31 #include <QStandardItemModel>
32 #include <QDoubleValidator>
33 #include <QComboBox>
34 
35 #include <fstream>
36 #include <iostream>
37 #include <cassert>
38 using namespace std;
39 using namespace g2o;
40 
41 MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags flags) :
42  QMainWindow(parent, flags),
43  _lastSolver(-1), _currentSolver(0), _viewerPropertiesWidget(0), _optimizerPropertiesWidget(0)
44 {
45  setupUi(this);
46  leKernelWidth->setValidator(new QDoubleValidator(-numeric_limits<double>::max(), numeric_limits<double>::max(), 7, this));
47  plainTextEdit->setMaximumBlockCount(1000);
48  btnForceStop->hide();
49  QObject::connect(cbDrawAxis, SIGNAL(toggled(bool)), viewer, SLOT(setAxisIsDrawn(bool)));
50 }
51 
53 {
54 }
55 
57 {
58  QString filename = QFileDialog::getOpenFileName(this, "Load g2o file", "", "g2o files (*.g2o);;All Files (*)");
59  if (! filename.isNull()) {
60  loadFromFile(filename);
61  }
62 }
63 
65 {
66  QString filename = QFileDialog::getSaveFileName(this, "Save g2o file", "", "g2o files (*.g2o)");
67  if (! filename.isNull()) {
68  ofstream fout(filename.toStdString().c_str());
69  viewer->graph->save(fout);
70  if (fout.good())
71  cerr << "Saved " << filename.toStdString() << endl;
72  else
73  cerr << "Error while saving file" << endl;
74  }
75 }
76 
78 {
79  if (viewer->graph->vertices().size() == 0 || viewer->graph->edges().size() == 0) {
80  cerr << "Graph has no vertices / egdes" << endl;
81  return;
82  }
83 
84  bool allocatedNewSolver;
85  bool allocateStatus = allocateSolver(allocatedNewSolver);
86  if (! allocateStatus) {
87  cerr << "Error while allocating solver" << endl;
88  return;
89  }
90  if (allocatedNewSolver)
91  prepare();
93 
94  btnOptimize->hide();
95  btnForceStop->show();
96 
97  _forceStopFlag = false;
98  viewer->graph->setForceStopFlag(&_forceStopFlag);
99 
100  int maxIterations = spIterations->value();
101  int iter = viewer->graph->optimize(maxIterations);
102  if (maxIterations > 0 && !iter){
103  cerr << "Optimization failed, result might be invalid" << endl;
104  }
105 
106  btnOptimize->show();
107  btnForceStop->hide();
108 
109  viewer->setUpdateDisplay(true);
110  viewer->updateGL();
111  _forceStopFlag = false;
112 }
113 
115 {
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->updateGL();
138 }
139 
141 {
142  if (viewer->graph->activeEdges().size() == 0)
143  viewer->graph->initializeOptimization();
144 
145  viewer->graph->setToOrigin();
146  viewer->setUpdateDisplay(true);
147  viewer->updateGL();
148 }
149 
151 {
152  if (viewer->graph->vertices().size() == 0 || viewer->graph->edges().size() == 0) {
153  return;
154  }
155 
156  // check for vertices to fix to remove DoF
157  bool gaugeFreedom = viewer->graph->gaugeFreedom();
158  g2o::OptimizableGraph::Vertex* gauge = viewer->graph->findGauge();
159  if (gaugeFreedom) {
160  if (! gauge) {
161  cerr << "cannot find a vertex to fix in this thing" << endl;
162  return;
163  } else {
164  cerr << "graph is fixed by node " << gauge->id() << endl;
165  gauge->setFixed(true);
166  }
167  } else {
168  cerr << "graph is fixed by priors or nodes are already fixed" << endl;
169  }
170 
171  viewer->graph->setVerbose(true);
172  //viewer->graph->computeActiveErrors();
173 }
174 
176 {
177  close();
178 }
179 
181 {
182  coOptimizer->clear();
183  _knownSolvers.clear();
184  const OptimizationAlgorithmFactory::CreatorList& knownSolvers = OptimizationAlgorithmFactory::instance()->creatorList();
185 
186  bool varFound = false;
187  string varType = "";
188  for (OptimizationAlgorithmFactory::CreatorList::const_iterator it = knownSolvers.begin(); it != knownSolvers.end(); ++it) {
189  const OptimizationAlgorithmProperty& sp = (*it)->property();
190  if (sp.name == "gn_var" || sp.name == "gn_var_cholmod") {
191  varType = sp.type;
192  varFound = true;
193  break;
194  }
195  }
196 
197  if (varFound) {
198  for (OptimizationAlgorithmFactory::CreatorList::const_iterator it = knownSolvers.begin(); it != knownSolvers.end(); ++it) {
199  const OptimizationAlgorithmProperty& sp = (*it)->property();
200  if (sp.type == varType) {
201  coOptimizer->addItem(QString::fromStdString(sp.name));
202  _knownSolvers.push_back(sp);
203  }
204  }
205  }
206 
207  map<string, vector<OptimizationAlgorithmProperty> > solverLookUp;
208 
209  for (OptimizationAlgorithmFactory::CreatorList::const_iterator it = knownSolvers.begin(); it != knownSolvers.end(); ++it) {
210  const OptimizationAlgorithmProperty& sp = (*it)->property();
211  if (varFound && varType == sp.type)
212  continue;
213  solverLookUp[sp.type].push_back(sp);
214  }
215 
216  for (map<string, vector<OptimizationAlgorithmProperty> >::iterator it = solverLookUp.begin(); it != solverLookUp.end(); ++it) {
217  if (_knownSolvers.size() > 0) {
218  coOptimizer->insertSeparator(coOptimizer->count());
220  }
221  const vector<OptimizationAlgorithmProperty>& vsp = it->second;
222  for (size_t j = 0; j < vsp.size(); ++j) {
223  coOptimizer->addItem(QString::fromStdString(vsp[j].name));
224  _knownSolvers.push_back(vsp[j]);
225  }
226  }
227 }
228 
229 bool MainWindow::load(const QString& filename)
230 {
231  ifstream ifs(filename.toStdString().c_str());
232  if (! ifs)
233  return false;
234  viewer->graph->clear();
235  bool loadStatus = viewer->graph->load(ifs);
236  if (! loadStatus)
237  return false;
238  _lastSolver = -1;
239  viewer->setUpdateDisplay(true);
240  SparseOptimizer* optimizer = viewer->graph;
241 
242  // update the solvers which are suitable for this graph
243  set<int> vertDims = optimizer->dimensions();
244  for (size_t i = 0; i < _knownSolvers.size(); ++i) {
246  if (sp.name == "" && sp.desc == "")
247  continue;
248 
249  bool suitableSolver = optimizer->isSolverSuitable(sp, vertDims);
250  qobject_cast<QStandardItemModel *>(coOptimizer->model())->item(i)->setEnabled(suitableSolver);
251  }
252  return loadStatus;
253 }
254 
255 bool MainWindow::allocateSolver(bool& allocatedNewSolver)
256 {
257  if (coOptimizer->count() == 0) {
258  cerr << "No solvers available" << endl;
259  return false;
260  }
261  int currentIndex = coOptimizer->currentIndex();
262  bool enabled = qobject_cast<QStandardItemModel *>(coOptimizer->model())->item(currentIndex)->isEnabled();
263 
264  if (! enabled) {
265  cerr << "selected solver is not enabled" << endl;
266  return false;
267  }
268 
269  if (currentIndex == _lastSolver)
270  return true;
271 
272  allocatedNewSolver = true;
273  QString strSolver = coOptimizer->currentText();
274 
275  // delete the old optimization algorithm
276  OptimizationAlgorithm* algorithmPointer = const_cast<OptimizationAlgorithm*>(viewer->graph->algorithm());
277  viewer->graph->setAlgorithm(0);
278  delete algorithmPointer;
279 
280  // create the new algorithm
281  OptimizationAlgorithmFactory* solverFactory = OptimizationAlgorithmFactory::instance();
282  _currentSolver = solverFactory->construct(strSolver.toStdString(), _currentOptimizationAlgorithmProperty);
283  viewer->graph->setAlgorithm(_currentSolver);
284 
285  _lastSolver = currentIndex;
286  return true;
287 }
288 
290 {
291  SparseOptimizer* optimizer = viewer->graph;
293  cerr << "Marginalizing Landmarks" << endl;
294  for (SparseOptimizer::VertexIDMap::const_iterator it = optimizer->vertices().begin(); it != optimizer->vertices().end(); ++it) {
295  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(it->second);
296  int vdim = v->dimension();
298  }
299  }
300  else {
301  cerr << "Preparing (no marginalization of Landmarks)" << endl;
302  for (SparseOptimizer::VertexIDMap::const_iterator it = optimizer->vertices().begin(); it != optimizer->vertices().end(); ++it) {
303  OptimizableGraph::Vertex* v = static_cast<OptimizableGraph::Vertex*>(it->second);
304  v->setMarginalized(false);
305  }
306  }
307  viewer->graph->initializeOptimization();
308  return true;
309 }
310 
312 {
313  SparseOptimizer* optimizer = viewer->graph;
314  bool robustKernel = cbRobustKernel->isChecked();
315  double huberWidth = leKernelWidth->text().toDouble();
316  //odometry edges are those whose node ids differ by 1
317 
318  bool onlyLoop = cbOnlyLoop->isChecked();
319 
320  if (robustKernel) {
321  QString strRobustKernel = coRobustKernel->currentText();
322  AbstractRobustKernelCreator* creator = RobustKernelFactory::instance()->creator(strRobustKernel.toStdString());
323  if (! creator) {
324  cerr << strRobustKernel.toStdString() << " is not a valid robust kernel" << endl;
325  return;
326  }
327  for (SparseOptimizer::EdgeSet::const_iterator it = optimizer->edges().begin(); it != optimizer->edges().end(); ++it) {
328  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
329  if (onlyLoop) {
330  if (e->vertices().size() >= 2 && std::abs(e->vertex(0)->id() - e->vertex(1)->id()) != 1) {
331  e->setRobustKernel(creator->construct());
332  e->robustKernel()->setDelta(huberWidth);
333  }
334  } else {
335  e->setRobustKernel(creator->construct());
336  e->robustKernel()->setDelta(huberWidth);
337  }
338  }
339  } else {
340  for (SparseOptimizer::EdgeSet::const_iterator it = optimizer->edges().begin(); it != optimizer->edges().end(); ++it) {
341  OptimizableGraph::Edge* e = static_cast<OptimizableGraph::Edge*>(*it);
342  e->setRobustKernel(0);
343  }
344  }
345 }
346 
348 {
349  _forceStopFlag = true;
350 }
351 
352 bool MainWindow::loadFromFile(const QString& filename)
353 {
354  viewer->graph->clear();
355  bool loadStatus = load(filename);
356  cerr << "loaded " << filename.toStdString() << " with " << viewer->graph->vertices().size()
357  << " vertices and " << viewer->graph->edges().size() << " measurements" << endl;
358  viewer->updateGL();
359  fixGraph();
360  return loadStatus;
361 }
362 
364 {
365  viewer->setBackgroundColor(QColor::fromRgb(255, 255, 255));
366  viewer->updateGL();
367 }
368 
370 {
371  viewer->setBackgroundColor(QColor::fromRgb(51, 51, 51));
372  viewer->updateGL();
373 }
374 
376 {
377  if (! _viewerPropertiesWidget) {
379  _viewerPropertiesWidget->setWindowTitle(tr("Drawing Options"));
380  }
382  _viewerPropertiesWidget->show();
383 }
384 
386 {
389  _optimizerPropertiesWidget->setWindowTitle(tr("Internal Solver Properties"));
390  }
391  bool allocatedNewSolver;
392  bool allocateStatus = allocateSolver(allocatedNewSolver);
393  if (! allocateStatus) {
394  cerr << "Error while allocating solver" << endl;
395  return;
396  }
397  if (allocatedNewSolver)
398  prepare();
399  if (_currentSolver) {
400  _optimizerPropertiesWidget->setProperties(const_cast<g2o::PropertyMap*>(&_currentSolver->properties()));
401  } else {
403  }
405 }
406 
408 {
409  QString selectedFilter;
410  QString filename = QFileDialog::getSaveFileName(this, "Save screen to a file", "viewer.png",
411  "PNG files (*.png);;JPG files (*.jpg);;EPS files (*.eps)", &selectedFilter);
412 
413  if (! filename.isNull()) {
414  // extract the file format from the filter options
415  int spacePos = selectedFilter.indexOf(' ');
416  assert(spacePos > 0 && "extracting the image format failed");
417  QString format = selectedFilter.left(spacePos);
418  // setting up the snapshot and save to file
419  if (format == "JPG") {
420  viewer->setSnapshotQuality(90);
421  } else {
422  viewer->setSnapshotQuality(-1);
423  }
424  viewer->setSnapshotFormat(format);
425  viewer->saveSnapshot(filename);
426  cerr << "saved snapshot " << filename.toStdString() << "(" << format.toStdString() << ")" << endl;
427  }
428 }
429 
431 {
432  QString filename = QFileDialog::getOpenFileName(this, "Load State", "camera.xml", "Camera/State file (*.xml)");
433  if (!filename.isEmpty()) {
434  viewer->setStateFileName(filename);
435  viewer->restoreStateFromFile();
436  viewer->setStateFileName(QString::null);
437  viewer->updateGL();
438  cerr << "Loaded state from " << filename.toStdString() << endl;
439  }
440 }
441 
443 {
444  QString filename = QFileDialog::getSaveFileName(this, "Save State", "camera.xml", "Camera/State file (*.xml)");
445  if (!filename.isEmpty()) {
446  viewer->setStateFileName(filename);
447  viewer->saveStateToFile();
448  viewer->setStateFileName(QString::null);
449  cerr << "Saved state to " << filename.toStdString() << endl;
450  }
451 }
452 
454 {
455  coRobustKernel->clear();
456  std::vector<std::string> kernels;
457  RobustKernelFactory::instance()->fillKnownKernels(kernels);
458  for (size_t i = 0; i < kernels.size(); ++i) {
459  coRobustKernel->addItem(QString::fromStdString(kernels[i]));
460  }
461 }
int id() const
returns the id
Definition: hyper_graph.h:148
void updateRobustKernels()
const Vertex * vertex(size_t i) const
Definition: hyper_graph.h:186
#define __PRETTY_FUNCTION__
Definition: macros.h:89
const OptimizableGraph * graph() const
const PropertyMap & properties() const
return the properties of the solver
Abstract interface for allocating a robust kernel.
std::string name
name of the solver, e.g., var
describe the properties of a solver
bool loadFromFile(const QString &filename)
void on_btnOptimize_clicked()
Definition: main_window.cpp:77
void on_actionProperties_triggered(bool)
void fixGraph()
void updateDisplayedSolvers()
void on_actionLoad_Viewer_State_triggered(bool)
int landmarkDim
dimension of the landmar vertices (-1 if variable)
bool prepare()
void on_actionWhite_Background_triggered(bool)
void on_btnSetZero_clicked()
void on_actionSave_Screenshot_triggered(bool)
void setRobustKernel(RobustKernel *ptr)
create solvers based on their short name
const VertexIDMap & vertices() const
Definition: hyper_graph.h:225
void on_btnOptimizerParamaters_clicked()
g2o::OptimizationAlgorithmProperty _currentOptimizationAlgorithmProperty
Definition: main_window.h:90
bool allocateSolver(bool &allocatedNewSolver)
int dimension() const
dimension of the estimated state belonging to this node
const VertexContainer & vertices() const
Definition: hyper_graph.h:178
bool isSolverSuitable(const OptimizationAlgorithmProperty &solverProperty, const std::set< int > &vertDims=std::set< int >()) const
RobustKernel * robustKernel() const
if NOT NULL, error of this edge will be robustifed with the kernel
const EdgeSet & edges() const
Definition: hyper_graph.h:230
void on_actionSave_Viewer_State_triggered(bool)
PropertiesWidget * _optimizerPropertiesWidget
Definition: main_window.h:94
std::vector< g2o::OptimizationAlgorithmProperty > _knownSolvers
Definition: main_window.h:87
A general case Vertex for optimization.
void setRobustKernel()
void setMarginalized(bool marginalized)
true => this node should be marginalized out during the optimization
void on_btnInitialGuess_clicked()
void on_actionDefault_Background_triggered(bool)
bool _forceStopFlag
Definition: main_window.h:89
void setProperties(g2o::PropertyMap *properties)
void on_actionLoad_triggered(bool)
Definition: main_window.cpp:56
g2o::OptimizationAlgorithm * _currentSolver
Definition: main_window.h:91
void setViewer(g2o::G2oQGLViewer *viewer)
virtual void setDelta(double delta)
bool requiresMarginalize
whether the solver requires marginalization of landmarks
virtual RobustKernel * construct()=0
void setFixed(bool fixed)
true => this node should be considered fixed during the optimization
std::list< AbstractOptimizationAlgorithmCreator * > CreatorList
cost for traversing only odometry edges.
bool load(const QString &filename)
std::string desc
short description of the solver
Generic interface for a non-linear solver operating on a graph.
void on_btnForceStop_clicked()
void on_actionSave_triggered(bool)
Definition: main_window.cpp:64
MainWindow(QWidget *parent=0, Qt::WindowFlags flags=0)
Definition: main_window.cpp:41
std::set< int > dimensions() const
int _lastSolver
Definition: main_window.h:88
ViewerPropertiesWidget * _viewerPropertiesWidget
Definition: main_window.h:93
OptimizationAlgorithm * construct(const std::string &tag, OptimizationAlgorithmProperty &solverProperty) const
std::string type
type of solver, e.g., "CSparse Cholesky", "PCG"
void on_actionQuit_triggered(bool)