g2o
g2o_incremental.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 // g2o is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published
6 // by the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // g2o is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #include <iostream>
18 #include <cassert>
19 #include <csignal>
20 
21 #include "g2o/stuff/macros.h"
22 #include "g2o/stuff/command_args.h"
23 #include "g2o/stuff/string_tools.h"
24 #include "g2o/stuff/tictoc.h"
25 
27 
30 
31 static bool hasToStop=false;
32 
33 using namespace std;
34 using namespace g2o;
35 
40 {
41  int fromId;
42  int toId;
43  std::vector<double> measurement;
44  std::vector<double> information;
45 };
46 
51 {
52  bool operator()(const EdgeInformation& e1, const EdgeInformation& e2)
53  {
54  int i11 = e1.fromId, i12 = e1.toId;
55  if (i11 > i12)
56  swap(i11, i12);
57  int i21 = e2.fromId, i22 = e2.toId;
58  if (i21 > i22)
59  swap(i21, i22);
60  if (i12 < i22)
61  return true;
62  if (i12 > i22)
63  return false;
64  return i11 < i21;
65  }
66 };
67 
68 void sigquit_handler(int sig)
69 {
70  if (sig == SIGINT) {
71  hasToStop = 1;
72  static int cnt = 0;
73  if (cnt++ == 2) {
74  cerr << __PRETTY_FUNCTION__ << " forcing exit" << endl;
75  exit(1);
76  }
77  }
78 }
79 
80 int main(int argc, char** argv)
81 {
82  string inputFilename;
83  string outputFilename;
84  int updateEachN;
85  int batchEachN;
86  bool verbose;
87  bool vis;
88  // command line parsing
89  CommandArgs arg;
90  arg.param("batch", batchEachN, 100, "solve by a batch Cholesky after inserting N nodes");
91  arg.param("update", updateEachN, 10, "update the graph after inserting N nodes");
92  arg.param("v", verbose, false, "verbose output of the optimization process");
93  arg.param("g", vis, false, "gnuplot visualization");
94  arg.param("o", outputFilename, "", "output the final graph");
95  arg.param("i", inputFilename, "", "input file (default g2o format), if not given read via stdin");
96 
97  arg.parseArgs(argc, argv);
98 
100  optimizer.setVerbose(verbose);
101  optimizer.setForceStopFlag(&hasToStop);
102  optimizer.vizWithGnuplot = vis;
103 
104  G2oSlamInterface slamInterface(&optimizer);
105  slamInterface.setUpdateGraphEachN(updateEachN);
106  slamInterface.setBatchSolveEachN(batchEachN);
107 
108  cerr << "Updating every " << updateEachN << endl;
109  cerr << "Batch step every " << batchEachN << endl;
110 
111  if (inputFilename.size() > 0) { // operating on a file
112  vector<EdgeInformation> edgesFromGraph;
113 
114  // HACK force tictoc statistics
115 #ifdef _MSC_VER
116  _putenv_s("G2O_ENABLE_TICTOC", "1");
117 #else
118  setenv("G2O_ENABLE_TICTOC", "1", 1);
119 #endif
120 
121  // parse the edge from the file
122  int graphDimension = 0;
123  cerr << "Parsing " << inputFilename << " ... ";
124  tictoc("parsing");
125  ifstream ifs(inputFilename.c_str());
126  if (!ifs) {
127  cerr << "Failure to open " << inputFilename << endl;
128  return 1;
129  }
130  stringstream currentLine;
131  while (readLine(ifs, currentLine)) {
132  string token;
133  currentLine >> token;
134  if (token == "EDGE_SE2") {
135  graphDimension = 3;
136  edgesFromGraph.push_back(EdgeInformation());
137  EdgeInformation& currentEdge = edgesFromGraph.back();
138  currentLine >> currentEdge.fromId >> currentEdge.toId;
139  currentEdge.measurement.resize(3);
140  currentLine >> currentEdge.measurement[0] >> currentEdge.measurement[1] >> currentEdge.measurement[2];
141  currentEdge.information.resize(6);
142  for (int i = 0; i < 6; ++i)
143  currentLine >> currentEdge.information[i];
144  } else if (token == "EDGE_SE3:QUAT") {
145  graphDimension = 6;
146  edgesFromGraph.push_back(EdgeInformation());
147  EdgeInformation& currentEdge = edgesFromGraph.back();
148  currentLine >> currentEdge.fromId >> currentEdge.toId;
149  currentEdge.measurement.resize(7);
150  for (size_t i = 0; i < currentEdge.measurement.size(); ++i)
151  currentLine >> currentEdge.measurement[i];
152  currentEdge.information.resize(21);
153  for (size_t i = 0; i < currentEdge.information.size(); ++i)
154  currentLine >> currentEdge.information[i];
155  }
156  }
157  assert(graphDimension > 0);
158  sort(edgesFromGraph.begin(), edgesFromGraph.end(), IncrementalEdgesCompare());
159  tictoc("parsing");
160  cerr << "done." << endl;
161 
162  // adding edges to the graph. Add all edges connecting a node and then call optimize
163  tictoc("inc_optimize");
164  bool freshlySolved = false;
165  int lastNode = 2;
166  slamInterface.addNode("", 0, graphDimension, vector<double>());
167  for (vector<EdgeInformation>::const_iterator it = edgesFromGraph.begin(); it != edgesFromGraph.end(); ++it) {
168  const EdgeInformation& e = *it;
169  int minNodeId = max(e.fromId, e.toId);
170  if (minNodeId > lastNode) {
171  //cerr << "try to solve" << endl;
172  lastNode = minNodeId;
173  freshlySolved = true;
174  G2oSlamInterface::SolveResult solverState = slamInterface.solve();
175  if (!verbose) {
176  switch (solverState) {
177  case G2oSlamInterface::SOLVED:
178  cout << "."; //<< flush;
179  break;
180  case G2oSlamInterface::SOLVED_BATCH:
181  cout << "b " << optimizer.vertices().size() << endl;
182  break;
183  default:
184  break;
185  }
186  }
187  }
188  //cerr << "adding " << e.fromId << " " << e.toId << endl;
189  slamInterface.addEdge("", 0, graphDimension, e.fromId, e.toId, e.measurement, e.information);
190  freshlySolved = false;
191  }
192  if (! freshlySolved) {
193  G2oSlamInterface::SolveResult solverState = slamInterface.solve();
194  if (!verbose) {
195  switch (solverState) {
196  case G2oSlamInterface::SOLVED:
197  cout << "." << endl;
198  break;
199  case G2oSlamInterface::SOLVED_BATCH:
200  cout << "b " << optimizer.vertices().size() << endl;
201  break;
202  default:
203  break;
204  }
205  }
206  }
207  tictoc("inc_optimize");
208  } else {
209  // Reading the protocol via stdin
210  SlamParser::ParserInterface parserInterface(&slamInterface);
211  while (parserInterface.parseCommand(cin)) {}
212  }
213 
214  if (outputFilename.size() > 0) {
215  cerr << "Saving " << outputFilename << endl;
216  optimizer.save(outputFilename.c_str());
217  }
218 
219  return 0;
220 }
bool operator()(const EdgeInformation &e1, const EdgeInformation &e2)
#define __PRETTY_FUNCTION__
Definition: macros.h:89
bool addEdge(const std::string &tag, int id, int dimension, int v1, int v2, const std::vector< double > &measurement, const std::vector< double > &information)
Command line parsing of argc and argv.
Definition: command_args.h:46
std::vector< double > information
bool addNode(const std::string &tag, int id, int dimension, const std::vector< double > &values)
static bool hasToStop
SlamParser::Parser::token token
Store the information parsed from a g2o file.
std::vector< double > measurement
top-level interface to the parser
const VertexIDMap & vertices() const
Definition: hyper_graph.h:225
bool parseArgs(int argc, char **argv, bool exitOnError=true)
virtual bool save(std::ostream &os, int level=0) const
save the graph to a stream. Again uses the Factory system.
void setVerbose(bool verbose)
bool parseCommand(std::istream &input)
double tictoc(const char *algorithmPart)
Profile the timing of certain parts of your algorithm.
Definition: tictoc.cpp:115
void setForceStopFlag(bool *flag)
int readLine(std::istream &is, std::stringstream &currentLine)
void param(const std::string &name, bool &p, bool defValue, const std::string &desc)
void sigquit_handler(int sig)
int main(int argc, char **argv)
Sort Edges for inserting them sequentially.
Definition: g2o.cpp:67