dataset.cpp
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2  * GTSAM Copyright 2010, Georgia Tech Research Corporation,
3  * Atlanta, Georgia 30332-0415
4  * All Rights Reserved
5  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
6 
7  * See LICENSE for the license information
8 
9  * -------------------------------------------------------------------------- */
10 
23 #include <gtsam/slam/dataset.h>
24 
25 #include <gtsam/geometry/Point3.h>
26 #include <gtsam/geometry/Pose2.h>
27 #include <gtsam/geometry/Rot3.h>
28 
31 
32 #include <gtsam/linear/Sampler.h>
33 
35 #include <gtsam/inference/Symbol.h>
36 
38 #include <gtsam/base/Lie.h>
39 #include <gtsam/base/Matrix.h>
40 #include <gtsam/base/Value.h>
41 #include <gtsam/base/Vector.h>
42 #include <gtsam/base/types.h>
43 
44 #include <boost/assign/list_inserter.hpp>
45 #include <boost/filesystem/operations.hpp>
46 #include <boost/filesystem/path.hpp>
47 #include <boost/optional.hpp>
48 
49 #include <cmath>
50 #include <fstream>
51 #include <iostream>
52 #include <stdexcept>
53 
54 using namespace std;
55 namespace fs = boost::filesystem;
59 
60 #define LINESIZE 81920
61 
62 namespace gtsam {
63 
64 /* ************************************************************************* */
65 string findExampleDataFile(const string &name) {
66  // Search source tree and installed location
67  vector<string> rootsToSearch;
68 
69  // Constants below are defined by CMake, see gtsam/gtsam/CMakeLists.txt
70  rootsToSearch.push_back(GTSAM_SOURCE_TREE_DATASET_DIR);
71  rootsToSearch.push_back(GTSAM_INSTALLED_DATASET_DIR);
72 
73  // Search for filename as given, and with .graph and .txt extensions
74  vector<string> namesToSearch;
75  namesToSearch.push_back(name);
76  namesToSearch.push_back(name + ".graph");
77  namesToSearch.push_back(name + ".txt");
78  namesToSearch.push_back(name + ".out");
79  namesToSearch.push_back(name + ".xml");
80  namesToSearch.push_back(name + ".g2o");
81 
82  // Find first name that exists
83  for (const fs::path root : rootsToSearch) {
84  for (const fs::path name : namesToSearch) {
85  if (fs::is_regular_file(root / name))
86  return (root / name).string();
87  }
88  }
89 
90  // If we did not return already, then we did not find the file
91  throw invalid_argument(
92  "gtsam::findExampleDataFile could not find a matching "
93  "file in\n" GTSAM_SOURCE_TREE_DATASET_DIR
94  " or\n" GTSAM_INSTALLED_DATASET_DIR " named\n" +
95  name + ", " + name + ".g2o, " + ", " + name + ".graph, or " + name +
96  ".txt");
97 }
98 
99 /* ************************************************************************* */
100 string createRewrittenFileName(const string &name) {
101  // Search source tree and installed location
102  if (!exists(fs::path(name))) {
103  throw invalid_argument(
104  "gtsam::createRewrittenFileName could not find a matching file in\n" +
105  name);
106  }
107 
108  fs::path p(name);
109  fs::path newpath = fs::path(p.parent_path().string()) /
110  fs::path(p.stem().string() + "-rewritten.txt");
111 
112  return newpath.string();
113 }
114 
115 /* ************************************************************************* */
116 // Type for parser functions used in parseLines below.
117 template <typename T>
118 using Parser =
119  std::function<boost::optional<T>(istream &is, const string &tag)>;
120 
121 // Parse a file by calling the parse(is, tag) function for every line.
122 // The result of calling the function is ignored, so typically parse function
123 // works via a side effect, like adding a factor into a graph etc.
124 template <typename T>
125 static void parseLines(const string &filename, Parser<T> parse) {
126  ifstream is(filename.c_str());
127  if (!is)
128  throw invalid_argument("parse: can not find file " + filename);
129  string tag;
130  while (is >> tag) {
131  parse(is, tag); // ignore return value
132  is.ignore(LINESIZE, '\n');
133  }
134 }
135 
136 /* ************************************************************************* */
137 // Parse types T into a size_t-indexed map
138 template <typename T>
139 map<size_t, T> parseToMap(const string &filename, Parser<pair<size_t, T>> parse,
140  size_t maxIndex) {
141  map<size_t, T> result;
142  Parser<pair<size_t, T>> emplace = [&](istream &is, const string &tag) {
143  if (auto t = parse(is, tag)) {
144  if (!maxIndex || t->first <= maxIndex)
145  result.emplace(*t);
146  }
147  return boost::none;
148  };
149  parseLines(filename, emplace);
150  return result;
151 }
152 
153 /* ************************************************************************* */
154 // Parse a file and push results on a vector
155 template <typename T>
156 static vector<T> parseToVector(const string &filename, Parser<T> parse) {
157  vector<T> result;
158  Parser<T> add = [&result, parse](istream &is, const string &tag) {
159  if (auto t = parse(is, tag))
160  result.push_back(*t);
161  return boost::none;
162  };
163  parseLines(filename, add);
164  return result;
165 }
166 
167 /* ************************************************************************* */
168 boost::optional<IndexedPose> parseVertexPose(istream &is, const string &tag) {
169  if ((tag == "VERTEX2") || (tag == "VERTEX_SE2") || (tag == "VERTEX")) {
170  size_t id;
171  double x, y, yaw;
172  if (!(is >> id >> x >> y >> yaw)) {
173  throw std::runtime_error("parseVertexPose encountered malformed line");
174  }
175  return IndexedPose(id, Pose2(x, y, yaw));
176  } else {
177  return boost::none;
178  }
179 }
180 
181 template <>
182 std::map<size_t, Pose2> parseVariables<Pose2>(const std::string &filename,
183  size_t maxIndex) {
184  return parseToMap<Pose2>(filename, parseVertexPose, maxIndex);
185 }
186 
187 /* ************************************************************************* */
188 boost::optional<IndexedLandmark> parseVertexLandmark(istream &is,
189  const string &tag) {
190  if (tag == "VERTEX_XY") {
191  size_t id;
192  double x, y;
193  if (!(is >> id >> x >> y)) {
194  throw std::runtime_error(
195  "parseVertexLandmark encountered malformed line");
196  }
197  return IndexedLandmark(id, Point2(x, y));
198  } else {
199  return boost::none;
200  }
201 }
202 
203 template <>
204 std::map<size_t, Point2> parseVariables<Point2>(const std::string &filename,
205  size_t maxIndex) {
206  return parseToMap<Point2>(filename, parseVertexLandmark, maxIndex);
207 }
208 
209 /* ************************************************************************* */
210 // Interpret noise parameters according to flags
211 static SharedNoiseModel
212 createNoiseModel(const Vector6 v, bool smart, NoiseFormat noiseFormat,
213  KernelFunctionType kernelFunctionType) {
214  if (noiseFormat == NoiseFormatAUTO) {
215  // Try to guess covariance matrix layout
216  if (v(0) != 0.0 && v(1) == 0.0 && v(2) != 0.0 && //
217  v(3) != 0.0 && v(4) == 0.0 && v(5) == 0.0) {
218  noiseFormat = NoiseFormatGRAPH;
219  } else if (v(0) != 0.0 && v(1) == 0.0 && v(2) == 0.0 && //
220  v(3) != 0.0 && v(4) == 0.0 && v(5) != 0.0) {
221  noiseFormat = NoiseFormatCOV;
222  } else {
223  throw std::invalid_argument(
224  "load2D: unrecognized covariance matrix format in dataset file. "
225  "Please specify the noise format.");
226  }
227  }
228 
229  // Read matrix and check that diagonal entries are non-zero
230  Matrix3 M;
231  switch (noiseFormat) {
232  case NoiseFormatG2O:
233  case NoiseFormatCOV:
234  // i.e., [v(0) v(1) v(2);
235  // v(1)' v(3) v(4);
236  // v(2)' v(4)' v(5) ]
237  if (v(0) == 0.0 || v(3) == 0.0 || v(5) == 0.0)
238  throw runtime_error(
239  "load2D::readNoiseModel looks like this is not G2O matrix order");
240  M << v(0), v(1), v(2), v(1), v(3), v(4), v(2), v(4), v(5);
241  break;
242  case NoiseFormatTORO:
243  case NoiseFormatGRAPH:
244  // http://www.openslam.org/toro.html
245  // inf_ff inf_fs inf_ss inf_rr inf_fr inf_sr
246  // i.e., [v(0) v(1) v(4);
247  // v(1)' v(2) v(5);
248  // v(4)' v(5)' v(3) ]
249  if (v(0) == 0.0 || v(2) == 0.0 || v(3) == 0.0)
250  throw invalid_argument(
251  "load2D::readNoiseModel looks like this is not TORO matrix order");
252  M << v(0), v(1), v(4), v(1), v(2), v(5), v(4), v(5), v(3);
253  break;
254  default:
255  throw runtime_error("load2D: invalid noise format");
256  }
257 
258  // Now, create a Gaussian noise model
259  // The smart flag will try to detect a simpler model, e.g., unit
261  switch (noiseFormat) {
262  case NoiseFormatG2O:
263  case NoiseFormatTORO:
264  // In both cases, what is stored in file is the information matrix
265  model = noiseModel::Gaussian::Information(M, smart);
266  break;
267  case NoiseFormatGRAPH:
268  case NoiseFormatCOV:
269  // These cases expect covariance matrix
270  model = noiseModel::Gaussian::Covariance(M, smart);
271  break;
272  default:
273  throw invalid_argument("load2D: invalid noise format");
274  }
275 
276  switch (kernelFunctionType) {
278  return model;
279  break;
281  return noiseModel::Robust::Create(
282  noiseModel::mEstimator::Huber::Create(1.345), model);
283  break;
285  return noiseModel::Robust::Create(
286  noiseModel::mEstimator::Tukey::Create(4.6851), model);
287  break;
288  default:
289  throw invalid_argument("load2D: invalid kernel function type");
290  }
291 }
292 
293 /* ************************************************************************* */
294 boost::optional<IndexedEdge> parseEdge(istream &is, const string &tag) {
295  if ((tag == "EDGE2") || (tag == "EDGE") || (tag == "EDGE_SE2") ||
296  (tag == "ODOMETRY")) {
297 
298  size_t id1, id2;
299  double x, y, yaw;
300  if (!(is >> id1 >> id2 >> x >> y >> yaw)) {
301  throw std::runtime_error("parseEdge encountered malformed line");
302  }
303  return IndexedEdge({id1, id2}, Pose2(x, y, yaw));
304  } else {
305  return boost::none;
306  }
307 }
308 
309 /* ************************************************************************* */
310 // Measurement parsers are implemented as a functor, as they have several
311 // options to filter and create the measurement model.
312 template <typename T> struct ParseMeasurement;
313 
314 /* ************************************************************************* */
315 // Converting from Measurement to BetweenFactor is generic
316 template <typename T> struct ParseFactor : ParseMeasurement<T> {
318  : ParseMeasurement<T>(parent) {}
319 
320  // We parse a measurement then convert
321  typename boost::optional<typename BetweenFactor<T>::shared_ptr>
322  operator()(istream &is, const string &tag) {
323  if (auto m = ParseMeasurement<T>::operator()(is, tag))
324  return boost::make_shared<BetweenFactor<T>>(
325  m->key1(), m->key2(), m->measured(), m->noiseModel());
326  else
327  return boost::none;
328  }
329 };
330 
331 /* ************************************************************************* */
332 // Pose2 measurement parser
333 template <> struct ParseMeasurement<Pose2> {
334  // The arguments
335  boost::shared_ptr<Sampler> sampler;
336  size_t maxIndex;
337 
338  // For noise model creation
339  bool smart;
342 
343  // If this is not null, will use instead of parsed model:
345 
346  // The actual parser
347  boost::optional<BinaryMeasurement<Pose2>> operator()(istream &is,
348  const string &tag) {
349  auto edge = parseEdge(is, tag);
350  if (!edge)
351  return boost::none;
352 
353  // parse noise model
354  Vector6 v;
355  is >> v(0) >> v(1) >> v(2) >> v(3) >> v(4) >> v(5);
356 
357  // optional filter
358  size_t id1, id2;
359  tie(id1, id2) = edge->first;
360  if (maxIndex && (id1 > maxIndex || id2 > maxIndex))
361  return boost::none;
362 
363  // Get pose and optionally add noise
364  Pose2 &pose = edge->second;
365  if (sampler)
366  pose = pose.retract(sampler->sample());
367 
368  // emplace measurement
369  auto modelFromFile =
370  createNoiseModel(v, smart, noiseFormat, kernelFunctionType);
371  return BinaryMeasurement<Pose2>(id1, id2, pose,
372  model ? model : modelFromFile);
373  }
374 };
375 
376 /* ************************************************************************* */
377 // Create a sampler to corrupt a measurement
378 boost::shared_ptr<Sampler> createSampler(const SharedNoiseModel &model) {
379  auto noise = boost::dynamic_pointer_cast<noiseModel::Diagonal>(model);
380  if (!noise)
381  throw invalid_argument("gtsam::load: invalid noise model for adding noise"
382  "(current version assumes diagonal noise model)!");
383  return boost::shared_ptr<Sampler>(new Sampler(noise));
384 }
385 
386 /* ************************************************************************* */
387 // Implementation of parseMeasurements for Pose2
388 template <>
389 std::vector<BinaryMeasurement<Pose2>>
390 parseMeasurements(const std::string &filename,
392  size_t maxIndex) {
393  ParseMeasurement<Pose2> parse{model ? createSampler(model) : nullptr,
394  maxIndex, true, NoiseFormatAUTO,
396  return parseToVector<BinaryMeasurement<Pose2>>(filename, parse);
397 }
398 
399 /* ************************************************************************* */
400 // Implementation of parseMeasurements for Rot2, which converts from Pose2
401 
402 // Extract Rot2 measurement from Pose2 measurement
404  auto gaussian =
405  boost::dynamic_pointer_cast<noiseModel::Gaussian>(p.noiseModel());
406  if (!gaussian)
407  throw std::invalid_argument(
408  "parseMeasurements<Rot2> can only convert Pose2 measurements "
409  "with Gaussian noise models.");
410  const Matrix3 M = gaussian->covariance();
411  return BinaryMeasurement<Rot2>(p.key1(), p.key2(), p.measured().rotation(),
412  noiseModel::Isotropic::Variance(1, M(2, 2)));
413 }
414 
415 template <>
416 std::vector<BinaryMeasurement<Rot2>>
417 parseMeasurements(const std::string &filename,
419  size_t maxIndex) {
420  auto poses = parseMeasurements<Pose2>(filename, model, maxIndex);
421  std::vector<BinaryMeasurement<Rot2>> result;
422  result.reserve(poses.size());
423  for (const auto &p : poses)
424  result.push_back(convert(p));
425  return result;
426 }
427 
428 /* ************************************************************************* */
429 // Implementation of parseFactors for Pose2
430 template <>
431 std::vector<BetweenFactor<Pose2>::shared_ptr>
432 parseFactors<Pose2>(const std::string &filename,
434  size_t maxIndex) {
435  ParseFactor<Pose2> parse({model ? createSampler(model) : nullptr, maxIndex,
437  nullptr});
438  return parseToVector<BetweenFactor<Pose2>::shared_ptr>(filename, parse);
439 }
440 
441 /* ************************************************************************* */
443 
444 template <> struct ParseMeasurement<BearingRange2D> {
445  // arguments
446  size_t maxIndex;
447 
448  // The actual parser
449  boost::optional<BinaryMeasurement<BearingRange2D>>
450  operator()(istream &is, const string &tag) {
451  if (tag != "BR" && tag != "LANDMARK")
452  return boost::none;
453 
454  size_t id1, id2;
455  is >> id1 >> id2;
456  double bearing, range, bearing_std, range_std;
457 
458  if (tag == "BR") {
459  is >> bearing >> range >> bearing_std >> range_std;
460  }
461 
462  // A landmark measurement, converted to bearing-range
463  if (tag == "LANDMARK") {
464  double lmx, lmy;
465  double v1, v2, v3;
466 
467  is >> lmx >> lmy >> v1 >> v2 >> v3;
468 
469  // Convert x,y to bearing,range
470  bearing = atan2(lmy, lmx);
471  range = sqrt(lmx * lmx + lmy * lmy);
472 
473  // In our experience, the x-y covariance on landmark sightings is not
474  // very good, so assume it describes the uncertainty at a range of 10m,
475  // and convert that to bearing/range uncertainty.
476  if (std::abs(v1 - v3) < 1e-4) {
477  bearing_std = sqrt(v1 / 10.0);
478  range_std = sqrt(v1);
479  } else {
480  // TODO(frank): we are ignoring the non-uniform covariance
481  bearing_std = 1;
482  range_std = 1;
483  }
484  }
485 
486  // optional filter
487  if (maxIndex && id1 > maxIndex)
488  return boost::none;
489 
490  // Create noise model
491  auto measurementNoise = noiseModel::Diagonal::Sigmas(
492  (Vector(2) << bearing_std, range_std).finished());
493 
495  id1, L(id2), BearingRange2D(bearing, range), measurementNoise);
496  }
497 };
498 
499 /* ************************************************************************* */
500 GraphAndValues load2D(const string &filename, SharedNoiseModel model,
501  size_t maxIndex, bool addNoise, bool smart,
502  NoiseFormat noiseFormat,
503  KernelFunctionType kernelFunctionType) {
504 
505  // Single pass for poses and landmarks.
506  auto initial = boost::make_shared<Values>();
507  Parser<int> insert = [maxIndex, &initial](istream &is, const string &tag) {
508  if (auto indexedPose = parseVertexPose(is, tag)) {
509  if (!maxIndex || indexedPose->first <= maxIndex)
510  initial->insert(indexedPose->first, indexedPose->second);
511  } else if (auto indexedLandmark = parseVertexLandmark(is, tag)) {
512  if (!maxIndex || indexedLandmark->first <= maxIndex)
513  initial->insert(L(indexedLandmark->first), indexedLandmark->second);
514  }
515  return 0;
516  };
517  parseLines(filename, insert);
518 
519  // Single pass for Pose2 and bearing-range factors.
520  auto graph = boost::make_shared<NonlinearFactorGraph>();
521 
522  // Instantiate factor parser
523  ParseFactor<Pose2> parseBetweenFactor(
524  {addNoise ? createSampler(model) : nullptr, maxIndex, smart, noiseFormat,
525  kernelFunctionType, model});
526 
527  // Instantiate bearing-range parser
528  ParseMeasurement<BearingRange2D> parseBearingRange{maxIndex};
529 
530  // Combine in a single parser that adds factors to `graph`, but also inserts
531  // new variables into `initial` when needed.
532  Parser<int> parse = [&](istream &is, const string &tag) {
533  if (auto f = parseBetweenFactor(is, tag)) {
534  graph->push_back(*f);
535 
536  // Insert vertices if pure odometry file
537  Key key1 = (*f)->key1(), key2 = (*f)->key2();
538  if (!initial->exists(key1))
539  initial->insert(key1, Pose2());
540  if (!initial->exists(key2))
541  initial->insert(key2, initial->at<Pose2>(key1) * (*f)->measured());
542  } else if (auto m = parseBearingRange(is, tag)) {
543  Key key1 = m->key1(), key2 = m->key2();
544  BearingRange2D br = m->measured();
545  graph->emplace_shared<BearingRangeFactor<Pose2, Point2>>(key1, key2, br,
546  m->noiseModel());
547 
548  // Insert poses or points if they do not exist yet
549  if (!initial->exists(key1))
550  initial->insert(key1, Pose2());
551  if (!initial->exists(key2)) {
552  Pose2 pose = initial->at<Pose2>(key1);
553  Point2 local = br.bearing() * Point2(br.range(), 0);
554  Point2 global = pose.transformFrom(local);
555  initial->insert(key2, global);
556  }
557  }
558  return 0;
559  };
560 
561  parseLines(filename, parse);
562 
563  return make_pair(graph, initial);
564 }
565 
566 /* ************************************************************************* */
567 GraphAndValues load2D(pair<string, SharedNoiseModel> dataset, size_t maxIndex,
568  bool addNoise, bool smart, NoiseFormat noiseFormat,
569  KernelFunctionType kernelFunctionType) {
570  return load2D(dataset.first, dataset.second, maxIndex, addNoise, smart,
571  noiseFormat, kernelFunctionType);
572 }
573 
574 /* ************************************************************************* */
575 GraphAndValues load2D_robust(const string &filename,
576  const noiseModel::Base::shared_ptr &model,
577  size_t maxIndex) {
578  return load2D(filename, model, maxIndex);
579 }
580 
581 /* ************************************************************************* */
582 void save2D(const NonlinearFactorGraph &graph, const Values &config,
584  const string &filename) {
585 
586  fstream stream(filename.c_str(), fstream::out);
587 
588  // save poses
589  for (const auto key_value : config) {
590  const Pose2 &pose = key_value.value.cast<Pose2>();
591  stream << "VERTEX2 " << key_value.key << " " << pose.x() << " " << pose.y()
592  << " " << pose.theta() << endl;
593  }
594 
595  // save edges
596  // TODO(frank): why don't we use model in factor?
597  Matrix3 R = model->R();
598  Matrix3 RR = R.transpose() * R;
599  for (auto f : graph) {
600  auto factor = boost::dynamic_pointer_cast<BetweenFactor<Pose2>>(f);
601  if (!factor)
602  continue;
603 
604  const Pose2 pose = factor->measured().inverse();
605  stream << "EDGE2 " << factor->key2() << " " << factor->key1() << " "
606  << pose.x() << " " << pose.y() << " " << pose.theta() << " "
607  << RR(0, 0) << " " << RR(0, 1) << " " << RR(1, 1) << " " << RR(2, 2)
608  << " " << RR(0, 2) << " " << RR(1, 2) << endl;
609  }
610 
611  stream.close();
612 }
613 
614 /* ************************************************************************* */
615 GraphAndValues readG2o(const string &g2oFile, const bool is3D,
616  KernelFunctionType kernelFunctionType) {
617  if (is3D) {
618  return load3D(g2oFile);
619  } else {
620  // just call load2D
621  size_t maxIndex = 0;
622  bool addNoise = false;
623  bool smart = true;
624  return load2D(g2oFile, SharedNoiseModel(), maxIndex, addNoise, smart,
625  NoiseFormatG2O, kernelFunctionType);
626  }
627 }
628 
629 /* ************************************************************************* */
630 void writeG2o(const NonlinearFactorGraph &graph, const Values &estimate,
631  const string &filename) {
632  fstream stream(filename.c_str(), fstream::out);
633 
634  // Use a lambda here to more easily modify behavior in future.
635  auto index = [](gtsam::Key key) { return Symbol(key).index(); };
636 
637  // save 2D poses
638  for (const auto key_value : estimate) {
639  auto p = dynamic_cast<const GenericValue<Pose2> *>(&key_value.value);
640  if (!p)
641  continue;
642  const Pose2 &pose = p->value();
643  stream << "VERTEX_SE2 " << index(key_value.key) << " " << pose.x() << " "
644  << pose.y() << " " << pose.theta() << endl;
645  }
646 
647  // save 3D poses
648  for (const auto key_value : estimate) {
649  auto p = dynamic_cast<const GenericValue<Pose3> *>(&key_value.value);
650  if (!p)
651  continue;
652  const Pose3 &pose = p->value();
653  const Point3 t = pose.translation();
654  const auto q = pose.rotation().toQuaternion();
655  stream << "VERTEX_SE3:QUAT " << index(key_value.key) << " " << t.x() << " "
656  << t.y() << " " << t.z() << " " << q.x() << " " << q.y() << " "
657  << q.z() << " " << q.w() << endl;
658  }
659 
660  // save 2D landmarks
661  for (const auto key_value : estimate) {
662  auto p = dynamic_cast<const GenericValue<Point2> *>(&key_value.value);
663  if (!p)
664  continue;
665  const Point2 &point = p->value();
666  stream << "VERTEX_XY " << index(key_value.key) << " " << point.x() << " "
667  << point.y() << endl;
668  }
669 
670  // save 3D landmarks
671  for (const auto key_value : estimate) {
672  auto p = dynamic_cast<const GenericValue<Point3> *>(&key_value.value);
673  if (!p)
674  continue;
675  const Point3 &point = p->value();
676  stream << "VERTEX_TRACKXYZ " << index(key_value.key) << " " << point.x()
677  << " " << point.y() << " " << point.z() << endl;
678  }
679 
680  // save edges (2D or 3D)
681  for (const auto &factor_ : graph) {
682  auto factor = boost::dynamic_pointer_cast<BetweenFactor<Pose2>>(factor_);
683  if (factor) {
684  SharedNoiseModel model = factor->noiseModel();
685  auto gaussianModel =
686  boost::dynamic_pointer_cast<noiseModel::Gaussian>(model);
687  if (!gaussianModel) {
688  model->print("model\n");
689  throw invalid_argument("writeG2o: invalid noise model!");
690  }
691  Matrix3 Info = gaussianModel->R().transpose() * gaussianModel->R();
692  Pose2 pose = factor->measured(); //.inverse();
693  stream << "EDGE_SE2 " << index(factor->key1()) << " "
694  << index(factor->key2()) << " " << pose.x() << " " << pose.y()
695  << " " << pose.theta();
696  for (size_t i = 0; i < 3; i++) {
697  for (size_t j = i; j < 3; j++) {
698  stream << " " << Info(i, j);
699  }
700  }
701  stream << endl;
702  }
703 
704  auto factor3D = boost::dynamic_pointer_cast<BetweenFactor<Pose3>>(factor_);
705 
706  if (factor3D) {
707  SharedNoiseModel model = factor3D->noiseModel();
708 
709  boost::shared_ptr<noiseModel::Gaussian> gaussianModel =
710  boost::dynamic_pointer_cast<noiseModel::Gaussian>(model);
711  if (!gaussianModel) {
712  model->print("model\n");
713  throw invalid_argument("writeG2o: invalid noise model!");
714  }
715  Matrix6 Info = gaussianModel->R().transpose() * gaussianModel->R();
716  const Pose3 pose3D = factor3D->measured();
717  const Point3 p = pose3D.translation();
718  const auto q = pose3D.rotation().toQuaternion();
719  stream << "EDGE_SE3:QUAT " << index(factor3D->key1()) << " "
720  << index(factor3D->key2()) << " " << p.x() << " " << p.y() << " "
721  << p.z() << " " << q.x() << " " << q.y() << " " << q.z() << " "
722  << q.w();
723 
724  Matrix6 InfoG2o = I_6x6;
725  InfoG2o.block<3, 3>(0, 0) = Info.block<3, 3>(3, 3); // cov translation
726  InfoG2o.block<3, 3>(3, 3) = Info.block<3, 3>(0, 0); // cov rotation
727  InfoG2o.block<3, 3>(0, 3) = Info.block<3, 3>(0, 3); // off diagonal
728  InfoG2o.block<3, 3>(3, 0) = Info.block<3, 3>(3, 0); // off diagonal
729 
730  for (size_t i = 0; i < 6; i++) {
731  for (size_t j = i; j < 6; j++) {
732  stream << " " << InfoG2o(i, j);
733  }
734  }
735  stream << endl;
736  }
737  }
738  stream.close();
739 }
740 
741 /* ************************************************************************* */
742 // parse quaternion in x,y,z,w order, and normalize to unit length
743 istream &operator>>(istream &is, Quaternion &q) {
744  double x, y, z, w;
745  is >> x >> y >> z >> w;
746  const double norm = sqrt(w * w + x * x + y * y + z * z), f = 1.0 / norm;
747  q = Quaternion(f * w, f * x, f * y, f * z);
748  return is;
749 }
750 
751 /* ************************************************************************* */
752 // parse Rot3 from roll, pitch, yaw
753 istream &operator>>(istream &is, Rot3 &R) {
754  double yaw, pitch, roll;
755  is >> roll >> pitch >> yaw; // notice order !
756  R = Rot3::Ypr(yaw, pitch, roll);
757  return is;
758 }
759 
760 /* ************************************************************************* */
761 boost::optional<pair<size_t, Pose3>> parseVertexPose3(istream &is,
762  const string &tag) {
763  if (tag == "VERTEX3") {
764  size_t id;
765  double x, y, z;
766  Rot3 R;
767  is >> id >> x >> y >> z >> R;
768  return make_pair(id, Pose3(R, {x, y, z}));
769  } else if (tag == "VERTEX_SE3:QUAT") {
770  size_t id;
771  double x, y, z;
772  Quaternion q;
773  is >> id >> x >> y >> z >> q;
774  return make_pair(id, Pose3(q, {x, y, z}));
775  } else
776  return boost::none;
777 }
778 
779 template <>
780 std::map<size_t, Pose3> parseVariables<Pose3>(const std::string &filename,
781  size_t maxIndex) {
782  return parseToMap<Pose3>(filename, parseVertexPose3, maxIndex);
783 }
784 
785 /* ************************************************************************* */
786 boost::optional<pair<size_t, Point3>> parseVertexPoint3(istream &is,
787  const string &tag) {
788  if (tag == "VERTEX_TRACKXYZ") {
789  size_t id;
790  double x, y, z;
791  is >> id >> x >> y >> z;
792  return make_pair(id, Point3(x, y, z));
793  } else
794  return boost::none;
795 }
796 
797 template <>
798 std::map<size_t, Point3> parseVariables<Point3>(const std::string &filename,
799  size_t maxIndex) {
800  return parseToMap<Point3>(filename, parseVertexPoint3, maxIndex);
801 }
802 
803 /* ************************************************************************* */
804 // Parse a symmetric covariance matrix (onlyupper-triangular part is stored)
805 istream &operator>>(istream &is, Matrix6 &m) {
806  for (size_t i = 0; i < 6; i++)
807  for (size_t j = i; j < 6; j++) {
808  is >> m(i, j);
809  m(j, i) = m(i, j);
810  }
811  return is;
812 }
813 
814 /* ************************************************************************* */
815 // Pose3 measurement parser
816 template <> struct ParseMeasurement<Pose3> {
817  // The arguments
818  boost::shared_ptr<Sampler> sampler;
819  size_t maxIndex;
820 
821  // The actual parser
822  boost::optional<BinaryMeasurement<Pose3>> operator()(istream &is,
823  const string &tag) {
824  if (tag != "EDGE3" && tag != "EDGE_SE3:QUAT")
825  return boost::none;
826 
827  // parse ids and optionally filter
828  size_t id1, id2;
829  is >> id1 >> id2;
830  if (maxIndex && (id1 > maxIndex || id2 > maxIndex))
831  return boost::none;
832 
833  Matrix6 m;
834  if (tag == "EDGE3") {
835  double x, y, z;
836  Rot3 R;
837  is >> x >> y >> z >> R >> m;
838  Pose3 T12(R, {x, y, z});
839  // optionally add noise
840  if (sampler)
841  T12 = T12.retract(sampler->sample());
842 
843  return BinaryMeasurement<Pose3>(id1, id2, T12,
844  noiseModel::Gaussian::Information(m));
845  } else if (tag == "EDGE_SE3:QUAT") {
846  double x, y, z;
847  Quaternion q;
848  is >> x >> y >> z >> q >> m;
849 
850  Pose3 T12(q, {x, y, z});
851  // optionally add noise
852  if (sampler)
853  T12 = T12.retract(sampler->sample());
854 
855  // EDGE_SE3:QUAT stores covariance in t,R order, unlike GTSAM:
856  Matrix6 mgtsam;
857  mgtsam.block<3, 3>(0, 0) = m.block<3, 3>(3, 3); // cov rotation
858  mgtsam.block<3, 3>(3, 3) = m.block<3, 3>(0, 0); // cov translation
859  mgtsam.block<3, 3>(0, 3) = m.block<3, 3>(0, 3); // off diagonal
860  mgtsam.block<3, 3>(3, 0) = m.block<3, 3>(3, 0); // off diagonal
861  SharedNoiseModel model = noiseModel::Gaussian::Information(mgtsam);
862 
864  id1, id2, T12, noiseModel::Gaussian::Information(mgtsam));
865  } else
866  return boost::none;
867  }
868 };
869 
870 /* ************************************************************************* */
871 // Implementation of parseMeasurements for Pose3
872 template <>
873 std::vector<BinaryMeasurement<Pose3>>
874 parseMeasurements(const std::string &filename,
876  size_t maxIndex) {
877  ParseMeasurement<Pose3> parse{model ? createSampler(model) : nullptr,
878  maxIndex};
879  return parseToVector<BinaryMeasurement<Pose3>>(filename, parse);
880 }
881 
882 /* ************************************************************************* */
883 // Implementation of parseMeasurements for Rot3, which converts from Pose3
884 
885 // Extract Rot3 measurement from Pose3 measurement
887  auto gaussian =
888  boost::dynamic_pointer_cast<noiseModel::Gaussian>(p.noiseModel());
889  if (!gaussian)
890  throw std::invalid_argument(
891  "parseMeasurements<Rot3> can only convert Pose3 measurements "
892  "with Gaussian noise models.");
893  const Matrix6 M = gaussian->covariance();
895  p.key1(), p.key2(), p.measured().rotation(),
896  noiseModel::Gaussian::Covariance(M.block<3, 3>(0, 0), true));
897 }
898 
899 template <>
900 std::vector<BinaryMeasurement<Rot3>>
901 parseMeasurements(const std::string &filename,
903  size_t maxIndex) {
904  auto poses = parseMeasurements<Pose3>(filename, model, maxIndex);
905  std::vector<BinaryMeasurement<Rot3>> result;
906  result.reserve(poses.size());
907  for (const auto &p : poses)
908  result.push_back(convert(p));
909  return result;
910 }
911 
912 /* ************************************************************************* */
913 // Implementation of parseFactors for Pose3
914 template <>
915 std::vector<BetweenFactor<Pose3>::shared_ptr>
916 parseFactors<Pose3>(const std::string &filename,
918  size_t maxIndex) {
919  ParseFactor<Pose3> parse({model ? createSampler(model) : nullptr, maxIndex});
920  return parseToVector<BetweenFactor<Pose3>::shared_ptr>(filename, parse);
921 }
922 
923 /* ************************************************************************* */
924 GraphAndValues load3D(const string &filename) {
925  auto graph = boost::make_shared<NonlinearFactorGraph>();
926  auto initial = boost::make_shared<Values>();
927 
928  // Instantiate factor parser. maxIndex is always zero for load3D.
929  ParseFactor<Pose3> parseFactor({nullptr, 0});
930 
931  // Single pass for variables and factors. Unlike 2D version, does *not* insert
932  // variables into `initial` if referenced but not present.
933  Parser<int> parse = [&](istream &is, const string &tag) {
934  if (auto indexedPose = parseVertexPose3(is, tag)) {
935  initial->insert(indexedPose->first, indexedPose->second);
936  } else if (auto indexedLandmark = parseVertexPoint3(is, tag)) {
937  initial->insert(L(indexedLandmark->first), indexedLandmark->second);
938  } else if (auto factor = parseFactor(is, tag)) {
939  graph->push_back(*factor);
940  }
941  return 0;
942  };
943  parseLines(filename, parse);
944 
945  return make_pair(graph, initial);
946 }
947 
948 /* ************************************************************************* */
949 Rot3 openGLFixedRotation() { // this is due to different convention for
950  // cameras in gtsam and openGL
951  /* R = [ 1 0 0
952  * 0 -1 0
953  * 0 0 -1]
954  */
955  Matrix3 R_mat = Matrix3::Zero(3, 3);
956  R_mat(0, 0) = 1.0;
957  R_mat(1, 1) = -1.0;
958  R_mat(2, 2) = -1.0;
959  return Rot3(R_mat);
960 }
961 
962 /* ************************************************************************* */
963 Pose3 openGL2gtsam(const Rot3 &R, double tx, double ty, double tz) {
964  Rot3 R90 = openGLFixedRotation();
965  Rot3 wRc = (R.inverse()).compose(R90);
966 
967  // Our camera-to-world translation wTc = -R'*t
968  return Pose3(wRc, R.unrotate(Point3(-tx, -ty, -tz)));
969 }
970 
971 /* ************************************************************************* */
972 Pose3 gtsam2openGL(const Rot3 &R, double tx, double ty, double tz) {
973  Rot3 R90 = openGLFixedRotation();
974  Rot3 cRw_openGL = R90.compose(R.inverse());
975  Point3 t_openGL = cRw_openGL.rotate(Point3(-tx, -ty, -tz));
976  return Pose3(cRw_openGL, t_openGL);
977 }
978 
979 /* ************************************************************************* */
980 Pose3 gtsam2openGL(const Pose3 &PoseGTSAM) {
981  return gtsam2openGL(PoseGTSAM.rotation(), PoseGTSAM.x(), PoseGTSAM.y(),
982  PoseGTSAM.z());
983 }
984 
985 /* ************************************************************************* */
986 bool readBundler(const string &filename, SfmData &data) {
987  // Load the data file
988  ifstream is(filename.c_str(), ifstream::in);
989  if (!is) {
990  cout << "Error in readBundler: can not find the file!!" << endl;
991  return false;
992  }
993 
994  // Ignore the first line
995  char aux[500];
996  is.getline(aux, 500);
997 
998  // Get the number of camera poses and 3D points
999  size_t nrPoses, nrPoints;
1000  is >> nrPoses >> nrPoints;
1001 
1002  // Get the information for the camera poses
1003  for (size_t i = 0; i < nrPoses; i++) {
1004  // Get the focal length and the radial distortion parameters
1005  float f, k1, k2;
1006  is >> f >> k1 >> k2;
1007  Cal3Bundler K(f, k1, k2);
1008 
1009  // Get the rotation matrix
1010  float r11, r12, r13;
1011  float r21, r22, r23;
1012  float r31, r32, r33;
1013  is >> r11 >> r12 >> r13 >> r21 >> r22 >> r23 >> r31 >> r32 >> r33;
1014 
1015  // Bundler-OpenGL rotation matrix
1016  Rot3 R(r11, r12, r13, r21, r22, r23, r31, r32, r33);
1017 
1018  // Check for all-zero R, in which case quit
1019  if (r11 == 0 && r12 == 0 && r13 == 0) {
1020  cout << "Error in readBundler: zero rotation matrix for pose " << i
1021  << endl;
1022  return false;
1023  }
1024 
1025  // Get the translation vector
1026  float tx, ty, tz;
1027  is >> tx >> ty >> tz;
1028 
1029  Pose3 pose = openGL2gtsam(R, tx, ty, tz);
1030 
1031  data.cameras.emplace_back(pose, K);
1032  }
1033 
1034  // Get the information for the 3D points
1035  data.tracks.reserve(nrPoints);
1036  for (size_t j = 0; j < nrPoints; j++) {
1037  SfmTrack track;
1038 
1039  // Get the 3D position
1040  float x, y, z;
1041  is >> x >> y >> z;
1042  track.p = Point3(x, y, z);
1043 
1044  // Get the color information
1045  float r, g, b;
1046  is >> r >> g >> b;
1047  track.r = r / 255.f;
1048  track.g = g / 255.f;
1049  track.b = b / 255.f;
1050 
1051  // Now get the visibility information
1052  size_t nvisible = 0;
1053  is >> nvisible;
1054 
1055  track.measurements.reserve(nvisible);
1056  track.siftIndices.reserve(nvisible);
1057  for (size_t k = 0; k < nvisible; k++) {
1058  size_t cam_idx = 0, point_idx = 0;
1059  float u, v;
1060  is >> cam_idx >> point_idx >> u >> v;
1061  track.measurements.emplace_back(cam_idx, Point2(u, -v));
1062  track.siftIndices.emplace_back(cam_idx, point_idx);
1063  }
1064 
1065  data.tracks.push_back(track);
1066  }
1067 
1068  is.close();
1069  return true;
1070 }
1071 
1072 /* ************************************************************************* */
1073 bool readBAL(const string &filename, SfmData &data) {
1074  // Load the data file
1075  ifstream is(filename.c_str(), ifstream::in);
1076  if (!is) {
1077  cout << "Error in readBAL: can not find the file!!" << endl;
1078  return false;
1079  }
1080 
1081  // Get the number of camera poses and 3D points
1082  size_t nrPoses, nrPoints, nrObservations;
1083  is >> nrPoses >> nrPoints >> nrObservations;
1084 
1085  data.tracks.resize(nrPoints);
1086 
1087  // Get the information for the observations
1088  for (size_t k = 0; k < nrObservations; k++) {
1089  size_t i = 0, j = 0;
1090  float u, v;
1091  is >> i >> j >> u >> v;
1092  data.tracks[j].measurements.emplace_back(i, Point2(u, -v));
1093  }
1094 
1095  // Get the information for the camera poses
1096  for (size_t i = 0; i < nrPoses; i++) {
1097  // Get the Rodrigues vector
1098  float wx, wy, wz;
1099  is >> wx >> wy >> wz;
1100  Rot3 R = Rot3::Rodrigues(wx, wy, wz); // BAL-OpenGL rotation matrix
1101 
1102  // Get the translation vector
1103  float tx, ty, tz;
1104  is >> tx >> ty >> tz;
1105 
1106  Pose3 pose = openGL2gtsam(R, tx, ty, tz);
1107 
1108  // Get the focal length and the radial distortion parameters
1109  float f, k1, k2;
1110  is >> f >> k1 >> k2;
1111  Cal3Bundler K(f, k1, k2);
1112 
1113  data.cameras.emplace_back(pose, K);
1114  }
1115 
1116  // Get the information for the 3D points
1117  for (size_t j = 0; j < nrPoints; j++) {
1118  // Get the 3D position
1119  float x, y, z;
1120  is >> x >> y >> z;
1121  SfmTrack &track = data.tracks[j];
1122  track.p = Point3(x, y, z);
1123  track.r = 0.4f;
1124  track.g = 0.4f;
1125  track.b = 0.4f;
1126  }
1127 
1128  is.close();
1129  return true;
1130 }
1131 
1132 /* ************************************************************************* */
1133 SfmData readBal(const string &filename) {
1134  SfmData data;
1135  readBAL(filename, data);
1136  return data;
1137 }
1138 
1139 /* ************************************************************************* */
1140 bool writeBAL(const string &filename, SfmData &data) {
1141  // Open the output file
1142  ofstream os;
1143  os.open(filename.c_str());
1144  os.precision(20);
1145  if (!os.is_open()) {
1146  cout << "Error in writeBAL: can not open the file!!" << endl;
1147  return false;
1148  }
1149 
1150  // Write the number of camera poses and 3D points
1151  size_t nrObservations = 0;
1152  for (size_t j = 0; j < data.number_tracks(); j++) {
1153  nrObservations += data.tracks[j].number_measurements();
1154  }
1155 
1156  // Write observations
1157  os << data.number_cameras() << " " << data.number_tracks() << " "
1158  << nrObservations << endl;
1159  os << endl;
1160 
1161  for (size_t j = 0; j < data.number_tracks(); j++) { // for each 3D point j
1162  const SfmTrack &track = data.tracks[j];
1163 
1164  for (size_t k = 0; k < track.number_measurements();
1165  k++) { // for each observation of the 3D point j
1166  size_t i = track.measurements[k].first; // camera id
1167  double u0 = data.cameras[i].calibration().px();
1168  double v0 = data.cameras[i].calibration().py();
1169 
1170  if (u0 != 0 || v0 != 0) {
1171  cout << "writeBAL has not been tested for calibration with nonzero "
1172  "(u0,v0)"
1173  << endl;
1174  }
1175 
1176  double pixelBALx = track.measurements[k].second.x() -
1177  u0; // center of image is the origin
1178  double pixelBALy = -(track.measurements[k].second.y() -
1179  v0); // center of image is the origin
1180  Point2 pixelMeasurement(pixelBALx, pixelBALy);
1181  os << i /*camera id*/ << " " << j /*point id*/ << " "
1182  << pixelMeasurement.x() /*u of the pixel*/ << " "
1183  << pixelMeasurement.y() /*v of the pixel*/ << endl;
1184  }
1185  }
1186  os << endl;
1187 
1188  // Write cameras
1189  for (size_t i = 0; i < data.number_cameras(); i++) { // for each camera
1190  Pose3 poseGTSAM = data.cameras[i].pose();
1191  Cal3Bundler cameraCalibration = data.cameras[i].calibration();
1192  Pose3 poseOpenGL = gtsam2openGL(poseGTSAM);
1193  os << Rot3::Logmap(poseOpenGL.rotation()) << endl;
1194  os << poseOpenGL.translation().x() << endl;
1195  os << poseOpenGL.translation().y() << endl;
1196  os << poseOpenGL.translation().z() << endl;
1197  os << cameraCalibration.fx() << endl;
1198  os << cameraCalibration.k1() << endl;
1199  os << cameraCalibration.k2() << endl;
1200  os << endl;
1201  }
1202 
1203  // Write the points
1204  for (size_t j = 0; j < data.number_tracks(); j++) { // for each 3D point j
1205  Point3 point = data.tracks[j].p;
1206  os << point.x() << endl;
1207  os << point.y() << endl;
1208  os << point.z() << endl;
1209  os << endl;
1210  }
1211 
1212  os.close();
1213  return true;
1214 }
1215 
1216 bool writeBALfromValues(const string &filename, const SfmData &data,
1217  Values &values) {
1219  SfmData dataValues = data;
1220 
1221  // Store poses or cameras in SfmData
1222  size_t nrPoses = values.count<Pose3>();
1223  if (nrPoses ==
1224  dataValues.number_cameras()) { // we only estimated camera poses
1225  for (size_t i = 0; i < dataValues.number_cameras();
1226  i++) { // for each camera
1227  Pose3 pose = values.at<Pose3>(X(i));
1228  Cal3Bundler K = dataValues.cameras[i].calibration();
1229  Camera camera(pose, K);
1230  dataValues.cameras[i] = camera;
1231  }
1232  } else {
1233  size_t nrCameras = values.count<Camera>();
1234  if (nrCameras == dataValues.number_cameras()) { // we only estimated camera
1235  // poses and calibration
1236  for (size_t i = 0; i < nrCameras; i++) { // for each camera
1237  Key cameraKey = i; // symbol('c',i);
1238  Camera camera = values.at<Camera>(cameraKey);
1239  dataValues.cameras[i] = camera;
1240  }
1241  } else {
1242  cout << "writeBALfromValues: different number of cameras in "
1243  "SfM_dataValues (#cameras "
1244  << dataValues.number_cameras() << ") and values (#cameras "
1245  << nrPoses << ", #poses " << nrCameras << ")!!" << endl;
1246  return false;
1247  }
1248  }
1249 
1250  // Store 3D points in SfmData
1251  size_t nrPoints = values.count<Point3>(),
1252  nrTracks = dataValues.number_tracks();
1253  if (nrPoints != nrTracks) {
1254  cout << "writeBALfromValues: different number of points in "
1255  "SfM_dataValues (#points= "
1256  << nrTracks << ") and values (#points " << nrPoints << ")!!" << endl;
1257  }
1258 
1259  for (size_t j = 0; j < nrTracks; j++) { // for each point
1260  Key pointKey = P(j);
1261  if (values.exists(pointKey)) {
1262  Point3 point = values.at<Point3>(pointKey);
1263  dataValues.tracks[j].p = point;
1264  } else {
1265  dataValues.tracks[j].r = 1.0;
1266  dataValues.tracks[j].g = 0.0;
1267  dataValues.tracks[j].b = 0.0;
1268  dataValues.tracks[j].p = Point3(0, 0, 0);
1269  }
1270  }
1271 
1272  // Write SfmData to file
1273  return writeBAL(filename, dataValues);
1274 }
1275 
1277  Values initial;
1278  size_t i = 0; // NO POINTS: j = 0;
1279  for (const SfmCamera &camera : db.cameras)
1280  initial.insert(i++, camera);
1281  return initial;
1282 }
1283 
1285  Values initial;
1286  size_t i = 0, j = 0;
1287  for (const SfmCamera &camera : db.cameras)
1288  initial.insert((i++), camera);
1289  for (const SfmTrack &track : db.tracks)
1290  initial.insert(P(j++), track.p);
1291  return initial;
1292 }
1293 
1294 // Wrapper-friendly versions of parseFactors<Pose2> and parseFactors<Pose2>
1296 parse2DFactors(const std::string &filename,
1297  const noiseModel::Diagonal::shared_ptr &model, size_t maxIndex) {
1298  return parseFactors<Pose2>(filename, model, maxIndex);
1299 }
1300 
1302 parse3DFactors(const std::string &filename,
1303  const noiseModel::Diagonal::shared_ptr &model, size_t maxIndex) {
1304  return parseFactors<Pose3>(filename, model, maxIndex);
1305 }
1306 
1307 #ifdef GTSAM_ALLOW_DEPRECATED_SINCE_V41
1308 std::map<size_t, Pose3> parse3DPoses(const std::string &filename,
1309  size_t maxIndex) {
1310  return parseVariables<Pose3>(filename, maxIndex);
1311 }
1312 
1313 std::map<size_t, Point3> parse3DLandmarks(const std::string &filename,
1314  size_t maxIndex) {
1315  return parseVariables<Point3>(filename, maxIndex);
1316 }
1317 #endif
1318 } // namespace gtsam
const SharedNoiseModel & noiseModel() const
Matrix3f m
std::vector< BetweenFactor< Pose3 >::shared_ptr > BetweenFactorPose3s
Definition: dataset.h:500
std::pair< NonlinearFactorGraph::shared_ptr, Values::shared_ptr > GraphAndValues
Definition: dataset.h:143
void writeG2o(const NonlinearFactorGraph &graph, const Values &estimate, const string &filename)
This function writes a g2o file from NonlinearFactorGraph and a Values structure. ...
Definition: dataset.cpp:630
const T & measured() const
std::vector< BetweenFactor< Pose2 >::shared_ptr > parseFactors< Pose2 >(const std::string &filename, const noiseModel::Diagonal::shared_ptr &model, size_t maxIndex)
Definition: dataset.cpp:432
Matrix< RealScalar, Dynamic, Dynamic > M
Definition: bench_gemm.cpp:38
A insert(1, 2)=0
Typedefs for easier changing of types.
default: toro-style order, but covariance matrix !
Definition: dataset.h:68
bool writeBAL(const string &filename, SfmData &data)
This function writes a "Bundle Adjustment in the Large" (BAL) file from a SfmData structure...
Definition: dataset.cpp:1140
bool exists(Key j) const
Definition: Values.cpp:104
Scalar * y
Vector v2
std::vector< BetweenFactor< Pose3 >::shared_ptr > parseFactors< Pose3 >(const std::string &filename, const noiseModel::Diagonal::shared_ptr &model, size_t maxIndex)
Definition: dataset.cpp:916
Scalar * b
Definition: benchVecAdd.cpp:17
double y() const
get y
Definition: Pose2.h:218
static vector< T > parseToVector(const string &filename, Parser< T > parse)
Definition: dataset.cpp:156
Define the structure for SfM data.
Definition: dataset.h:326
Vector v1
boost::shared_ptr< Sampler > sampler
Definition: dataset.cpp:335
istream & operator>>(istream &is, Matrix6 &m)
Definition: dataset.cpp:805
KernelFunctionType
Robust kernel type to wrap around quadratic noise model.
Definition: dataset.h:74
double k1() const
distorsion parameter k1
Definition: Cal3Bundler.h:84
noiseModel::Diagonal::shared_ptr model
Q id(Eigen::AngleAxisd(0, Q_z_axis))
void insert(Key j, const Value &val)
Definition: Values.cpp:140
GraphAndValues load2D(pair< string, SharedNoiseModel > dataset, size_t maxIndex, bool addNoise, bool smart, NoiseFormat noiseFormat, KernelFunctionType kernelFunctionType)
Definition: dataset.cpp:567
Key P(std::uint64_t j)
#define LINESIZE
Definition: dataset.cpp:60
Vector2 Point2
Definition: Point2.h:27
ArrayXcf v
Definition: Cwise_arg.cpp:1
boost::optional< IndexedEdge > parseEdge(istream &is, const string &tag)
Definition: dataset.cpp:294
BetweenFactorPose3s parse3DFactors(const std::string &filename, const noiseModel::Diagonal::shared_ptr &model, size_t maxIndex)
Definition: dataset.cpp:1302
Rot2 R(Rot2::fromAngle(0.1))
Point3 unrotate(const Point3 &p, OptionalJacobian< 3, 3 > H1=boost::none, OptionalJacobian< 3, 3 > H2=boost::none) const
rotate point from world to rotated frame
Definition: Rot3.cpp:136
std::pair< size_t, Pose2 > IndexedPose
Return type for auxiliary functions.
Definition: dataset.h:111
leaf::MyValues values
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
static Cal3_S2 K(500, 500, 0.1, 640/2, 480/2)
Values initial
boost::optional< pair< size_t, Pose3 > > parseVertexPose3(istream &is, const string &tag)
Definition: dataset.cpp:761
BetweenFactorPose2s parse2DFactors(const std::string &filename, const noiseModel::Diagonal::shared_ptr &model, size_t maxIndex)
Definition: dataset.cpp:1296
MatrixXd L
Definition: LLT_example.cpp:6
Definition: Half.h:150
SfmData readBal(const string &filename)
This function parses a "Bundle Adjustment in the Large" (BAL) file and returns the data as a SfmData ...
Definition: dataset.cpp:1133
double k2() const
distorsion parameter k2
Definition: Cal3Bundler.h:87
Key X(std::uint64_t j)
const Point3 & translation(OptionalJacobian< 3, 6 > Hself=boost::none) const
get translation
Definition: Pose3.cpp:259
GraphAndValues load2D_robust(const string &filename, const noiseModel::Base::shared_ptr &model, size_t maxIndex)
Definition: dataset.cpp:575
boost::optional< BinaryMeasurement< BearingRange2D > > operator()(istream &is, const string &tag)
Definition: dataset.cpp:450
Try to guess covariance matrix layout.
Definition: dataset.h:70
Point3 rotate(const Point3 &p, OptionalJacobian< 3, 3 > H1=boost::none, OptionalJacobian< 3, 3 > H2=boost::none) const
Definition: Rot3M.cpp:149
const mpreal root(const mpreal &x, unsigned long int k, mp_rnd_t r=mpreal::get_default_rnd())
Definition: mpreal.h:2194
boost::optional< typename BetweenFactor< T >::shared_ptr > operator()(istream &is, const string &tag)
Definition: dataset.cpp:322
NonlinearFactorGraph graph
ParseFactor(const ParseMeasurement< T > &parent)
Definition: dataset.cpp:317
const gtsam::Key pointKey
const SharedNoiseModel & noiseModel() const
access to the noise model
BearingFactor3D factor3D(poseKey, pointKey, measurement3D, model3D)
void g(const string &key, int i)
Definition: testBTree.cpp:43
graph add(boost::make_shared< UnaryFactor >(1, 0.0, 0.0, unaryNoise))
T compose(const T &t1, const T &t2)
Definition: lieProxies.h:39
static SharedNoiseModel createNoiseModel(const Vector6 v, bool smart, NoiseFormat noiseFormat, KernelFunctionType kernelFunctionType)
Definition: dataset.cpp:212
Rot3 inverse() const
inverse of a rotation
Definition: Rot3.h:311
std::vector< SfmTrack > tracks
Sparse set of points.
Definition: dataset.h:328
double x() const
get x
Definition: Pose3.h:269
NoiseFormat
Indicates how noise parameters are stored in file.
Definition: dataset.h:65
Point3 point(10, 0,-5)
string findExampleDataFile(const string &name)
Definition: dataset.cpp:65
const Symbol key1('v', 1)
size_t number_tracks() const
The number of reconstructed 3D points.
Definition: dataset.h:333
Vector v3
std::pair< std::pair< size_t, size_t >, Pose2 > IndexedEdge
Definition: dataset.h:113
static std::map< timestep_t, std::vector< stereo_meas_t > > dataset
Class compose(const Class &g) const
Definition: Lie.h:47
boost::optional< BinaryMeasurement< Pose3 > > operator()(istream &is, const string &tag)
Definition: dataset.cpp:822
Information matrix, but inf_ff inf_fs inf_ss inf_rr inf_fr inf_sr.
Definition: dataset.h:67
Define the structure for the 3D points.
Definition: dataset.h:220
Values result
const ValueType at(Key j) const
Definition: Values-inl.h:342
std::function< boost::optional< T >(istream &is, const string &tag)> Parser
Definition: dataset.cpp:119
Rot3 openGLFixedRotation()
Definition: dataset.cpp:949
std::vector< BinaryMeasurement< Rot3 > > parseMeasurements(const std::string &filename, const noiseModel::Diagonal::shared_ptr &model, size_t maxIndex)
Definition: dataset.cpp:901
double theta() const
get theta
Definition: Pose2.h:221
static const Pose3 pose(Rot3(Vector3(1,-1,-1).asDiagonal()), Point3(0, 0, 0.5))
bool convert(const int &y)
KernelFunctionType kernelFunctionType
Definition: dataset.cpp:341
std::pair< size_t, Point2 > IndexedLandmark
Definition: dataset.h:112
double y() const
get y
Definition: Pose3.h:274
int data[]
Point2(* f)(const Point3 &, OptionalJacobian< 2, 3 >)
boost::optional< BinaryMeasurement< Pose2 > > operator()(istream &is, const string &tag)
Definition: dataset.cpp:347
Array< double, 1, 3 > e(1./3., 0.5, 2.)
EIGEN_DEVICE_FUNC const Scalar & q
void save2D(const NonlinearFactorGraph &graph, const Values &config, const noiseModel::Diagonal::shared_ptr model, const string &filename)
Definition: dataset.cpp:582
Pose3 gtsam2openGL(const Pose3 &PoseGTSAM)
This function converts a GTSAM camera pose to an openGL camera pose.
Definition: dataset.cpp:980
sampling from a NoiseModel
void print(const std::string &name) const override
Definition: NoiseModel.cpp:136
size_t number_measurements() const
Total number of measurements in this track.
Definition: dataset.h:233
boost::shared_ptr< Sampler > createSampler(const SharedNoiseModel &model)
Definition: dataset.cpp:378
string createRewrittenFileName(const string &name)
Definition: dataset.cpp:100
static const double u0
boost::shared_ptr< Diagonal > shared_ptr
Definition: NoiseModel.h:301
BearingRange< Pose2, Point2 > BearingRange2D
Values initialCamerasEstimate(const SfmData &db)
This function creates initial values for cameras from db.
Definition: dataset.cpp:1276
RowVector3d w
Base class and basic functions for Lie types.
boost::shared_ptr< Base > shared_ptr
Definition: NoiseModel.h:56
Jet< T, N > atan2(const Jet< T, N > &g, const Jet< T, N > &f)
Definition: jet.h:556
size_t count() const
Definition: Values.h:398
boost::optional< pair< size_t, Point3 > > parseVertexPoint3(istream &is, const string &tag)
Definition: dataset.cpp:786
traits
Definition: chartTesting.h:28
typedef and functions to augment Eigen&#39;s VectorXd
Class retract(const TangentVector &v) const
retract as required by manifold concept: applies v at *this
Definition: Lie.h:130
GTSAM_EXPORT Point2 transformFrom(const Point2 &point, OptionalJacobian< 2, 3 > Dpose=boost::none, OptionalJacobian< 2, 2 > Dpoint=boost::none) const
Definition: Pose2.cpp:218
std::vector< SfmCamera > cameras
Set of cameras.
Definition: dataset.h:327
double x() const
get x
Definition: Pose2.h:215
Covariance matrix C11, C12, C13, C22, C23, C33.
Definition: dataset.h:69
map< size_t, T > parseToMap(const string &filename, Parser< pair< size_t, T >> parse, size_t maxIndex)
Definition: dataset.cpp:139
Information matrix I11, I12, I13, I22, I23, I33.
Definition: dataset.h:66
Non-linear factor base classes.
ofstream os("timeSchurFactors.csv")
Pose3 openGL2gtsam(const Rot3 &R, double tx, double ty, double tz)
This function converts an openGL camera pose to an GTSAM camera pose.
Definition: dataset.cpp:963
std::vector< SiftIndex > siftIndices
Definition: dataset.h:227
The quaternion class used to represent 3D orientations and rotations.
std::vector< BetweenFactor< Pose2 >::shared_ptr > BetweenFactorPose2s
Definition: dataset.h:494
static const double v0
std::map< size_t, Point3 > parseVariables< Point3 >(const std::string &filename, size_t maxIndex)
Definition: dataset.cpp:798
const Symbol key2('v', 2)
Key L(std::uint64_t j)
Point3 p
3D position of the point
Definition: dataset.h:224
Factor Graph Base Class.
3D Point
float * p
float b
RGB color of the 3D point.
Definition: dataset.h:225
The base class for any variable that can be optimized or used in a factor.
std::map< size_t, Pose2 > parseVariables< Pose2 >(const std::string &filename, size_t maxIndex)
Definition: dataset.cpp:182
std::map< size_t, Pose3 > parseVariables< Pose3 >(const std::string &filename, size_t maxIndex)
Definition: dataset.cpp:780
double fx() const
focal length x
Definition: Cal3.h:139
Annotation for function names.
Definition: attr.h:36
Vector3 Point3
Definition: Point3.h:35
Values initialCamerasAndPointsEstimate(const SfmData &db)
This function creates initial values for cameras and points from db.
Definition: dataset.cpp:1284
2D Pose
GraphAndValues readG2o(const string &g2oFile, const bool is3D, KernelFunctionType kernelFunctionType)
This function parses a g2o file and stores the measurements into a NonlinearFactorGraph and the initi...
Definition: dataset.cpp:615
static void parseLines(const string &filename, Parser< T > parse)
Definition: dataset.cpp:125
bool readBundler(const string &filename, SfmData &data)
This function parses a bundler output file and stores the data into a SfmData structure.
Definition: dataset.cpp:986
static const CalibratedCamera camera(kDefaultPose)
#define X
Definition: icosphere.cpp:20
set noclip points set clip one set noclip two set bar set border lt lw set xdata set ydata set zdata set x2data set y2data set boxwidth set dummy x
#define abs(x)
Definition: datatypes.h:17
GraphAndValues load3D(const string &filename)
Load TORO 3D Graph.
Definition: dataset.cpp:924
Eigen::Matrix< double, Eigen::Dynamic, 1 > Vector
def parse(input_path, output_path, quiet=False, generate_xml_flag=True)
Definition: parse_xml.py:10
std::map< size_t, Point2 > parseVariables< Point2 >(const std::string &filename, size_t maxIndex)
Definition: dataset.cpp:204
boost::optional< IndexedLandmark > parseVertexLandmark(istream &is, const string &tag)
Definition: dataset.cpp:188
utility functions for loading datasets
gtsam::Quaternion toQuaternion() const
Definition: Rot3M.cpp:233
std::vector< SfmMeasurement > measurements
The 2D image projections (id,(u,v))
Definition: dataset.h:226
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:61
std::ptrdiff_t j
Point2 t(10, 10)
noiseModel::Base::shared_ptr SharedNoiseModel
Definition: NoiseModel.h:734
boost::shared_ptr< Sampler > sampler
Definition: dataset.cpp:818
const Rot3 & rotation(OptionalJacobian< 3, 6 > Hself=boost::none) const
get rotation
Definition: Pose3.cpp:266
3D rotation represented as a rotation matrix or quaternion
boost::optional< IndexedPose > parseVertexPose(istream &is, const string &tag)
Definition: dataset.cpp:168
bool readBAL(const string &filename, SfmData &data)
This function parses a "Bundle Adjustment in the Large" (BAL) file and stores the data into a SfmData...
Definition: dataset.cpp:1073
double z() const
get z
Definition: Pose3.h:279
std::uint64_t index() const
bool writeBALfromValues(const string &filename, const SfmData &data, Values &values)
This function writes a "Bundle Adjustment in the Large" (BAL) file from a SfmData structure and a val...
Definition: dataset.cpp:1216
Eigen::Quaternion< double, Eigen::DontAlign > Quaternion
size_t number_cameras() const
Definition: dataset.h:329


gtsam
Author(s):
autogenerated on Sat May 8 2021 02:41:56