TranslationRecovery.cpp
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010-2020, Georgia Tech Research Corporation,
4  * Atlanta, Georgia 30332-0415
5  * All Rights Reserved
6  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)
7 
8  * See LICENSE for the license information
9 
10  * -------------------------------------------------------------------------- */
11 
19 #include <gtsam/base/DSFMap.h>
20 #include <gtsam/geometry/Point3.h>
21 #include <gtsam/geometry/Pose3.h>
22 #include <gtsam/geometry/Unit3.h>
28 #include <gtsam/nonlinear/Values.h>
32 #include <gtsam/slam/PriorFactor.h>
33 #include <gtsam/slam/expressions.h>
34 
35 #include <set>
36 #include <utility>
37 
38 using namespace gtsam;
39 using namespace std;
40 
41 // In Wrappers we have no access to this so have a default ready.
42 static std::mt19937 kRandomNumberGenerator(42);
43 
44 // Some relative translations may be zero. We treat nodes that have a zero
45 // relativeTranslation as a single node.
46 // A DSFMap is used to find sets of nodes that have a zero relative
47 // translation. Add the nodes in each edge to the DSFMap, and merge nodes that
48 // are connected by a zero relative translation.
50  const std::vector<BinaryMeasurement<Unit3>> &relativeTranslations) {
51  DSFMap<Key> sameTranslationDSF;
52  for (const auto &edge : relativeTranslations) {
53  Key key1 = sameTranslationDSF.find(edge.key1());
54  Key key2 = sameTranslationDSF.find(edge.key2());
55  if (key1 != key2 && edge.measured().equals(Unit3(0.0, 0.0, 0.0))) {
56  sameTranslationDSF.merge(key1, key2);
57  }
58  }
59  return sameTranslationDSF;
60 }
61 
62 // Removes zero-translation edges from measurements, and combines the nodes in
63 // these edges into a single node.
64 template <typename T>
65 std::vector<BinaryMeasurement<T>> removeSameTranslationNodes(
66  const std::vector<BinaryMeasurement<T>> &edges,
67  const DSFMap<Key> &sameTranslationDSFMap) {
68  std::vector<BinaryMeasurement<T>> newEdges;
69  for (const auto &edge : edges) {
70  Key key1 = sameTranslationDSFMap.find(edge.key1());
71  Key key2 = sameTranslationDSFMap.find(edge.key2());
72  if (key1 == key2) continue;
73  newEdges.emplace_back(key1, key2, edge.measured(), edge.noiseModel());
74  }
75  return newEdges;
76 }
77 
78 // Adds nodes that were not optimized for because they were connected
79 // to another node with a zero-translation edge in the input.
81  const DSFMap<Key> &sameTranslationDSFMap) {
82  Values final_result = result;
83  // Nodes that were not optimized are stored in sameTranslationNodes_ as a map
84  // from a key that was optimized to keys that were not optimized. Iterate over
85  // map and add results for keys not optimized.
86  for (const auto &optimizedAndDuplicateKeys : sameTranslationDSFMap.sets()) {
87  Key optimizedKey = optimizedAndDuplicateKeys.first;
88  std::set<Key> duplicateKeys = optimizedAndDuplicateKeys.second;
89  // Add the result for the duplicate key if it does not already exist.
90  for (const Key duplicateKey : duplicateKeys) {
91  if (final_result.exists(duplicateKey)) continue;
92  final_result.insert<Point3>(duplicateKey,
93  final_result.at<Point3>(optimizedKey));
94  }
95  }
96  return final_result;
97 }
98 
100  const std::vector<BinaryMeasurement<Unit3>> &relativeTranslations) const {
102 
103  // Add translation factors for input translation directions.
104  for (auto edge : relativeTranslations) {
105  graph.emplace_shared<TranslationFactor>(edge.key1(), edge.key2(),
106  edge.measured(), edge.noiseModel());
107  }
108  return graph;
109 }
110 
112  const std::vector<BinaryMeasurement<Unit3>> &relativeTranslations,
113  const double scale,
114  const std::vector<BinaryMeasurement<Point3>> &betweenTranslations,
116  const SharedNoiseModel &priorNoiseModel) const {
117  auto edge = relativeTranslations.begin();
118  if (edge == relativeTranslations.end()) return;
119  graph->emplace_shared<PriorFactor<Point3>>(edge->key1(), Point3(0, 0, 0),
120  priorNoiseModel);
121 
122  // Add a scale prior only if no other between factors were added.
123  if (betweenTranslations.empty()) {
125  edge->key2(), scale * edge->measured().point3(), edge->noiseModel());
126  return;
127  }
128 
129  // Add between factors for optional relative translations.
130  for (auto prior_edge : betweenTranslations) {
132  prior_edge.key1(), prior_edge.key2(), prior_edge.measured(),
133  prior_edge.noiseModel());
134  }
135 }
136 
138  const std::vector<BinaryMeasurement<Unit3>> &relativeTranslations,
139  const std::vector<BinaryMeasurement<Point3>> &betweenTranslations,
140  std::mt19937 *rng, const Values &initialValues) const {
141  uniform_real_distribution<double> randomVal(-1, 1);
142  // Create a lambda expression that checks whether value exists and randomly
143  // initializes if not.
144  Values initial;
145  auto insert = [&](Key j) {
146  if (initial.exists(j)) return;
147  if (initialValues.exists(j)) {
148  initial.insert<Point3>(j, initialValues.at<Point3>(j));
149  } else {
150  initial.insert<Point3>(
151  j, Point3(randomVal(*rng), randomVal(*rng), randomVal(*rng)));
152  }
153  // Assumes all nodes connected by zero-edges have the same initialization.
154  };
155 
156  // Loop over measurements and add a random translation
157  for (auto edge : relativeTranslations) {
158  insert(edge.key1());
159  insert(edge.key2());
160  }
161  // There may be nodes in betweenTranslations that do not have a measurement.
162  for (auto edge : betweenTranslations) {
163  insert(edge.key1());
164  insert(edge.key2());
165  }
166  return initial;
167 }
168 
170  const std::vector<BinaryMeasurement<Unit3>> &relativeTranslations,
171  const std::vector<BinaryMeasurement<Point3>> &betweenTranslations,
172  const Values &initialValues) const {
173  return initializeRandomly(relativeTranslations, betweenTranslations,
174  &kRandomNumberGenerator, initialValues);
175 }
176 
178  const TranslationEdges &relativeTranslations, const double scale,
179  const std::vector<BinaryMeasurement<Point3>> &betweenTranslations,
180  const Values &initialValues) const {
181  // Find edges that have a zero-translation, and recompute relativeTranslations
182  // and betweenTranslations by retaining only one node for every zero-edge.
183  DSFMap<Key> sameTranslationDSFMap =
184  getSameTranslationDSFMap(relativeTranslations);
185  const TranslationEdges nonzeroRelativeTranslations =
186  removeSameTranslationNodes(relativeTranslations, sameTranslationDSFMap);
187  const std::vector<BinaryMeasurement<Point3>> nonzeroBetweenTranslations =
188  removeSameTranslationNodes(betweenTranslations, sameTranslationDSFMap);
189 
190  // Create graph of translation factors.
191  NonlinearFactorGraph graph = buildGraph(nonzeroRelativeTranslations);
192 
193  // Add global frame prior and scale (either from betweenTranslations or
194  // scale).
195  addPrior(nonzeroRelativeTranslations, scale, nonzeroBetweenTranslations,
196  &graph);
197 
198  // Uses initial values from params if provided.
199  Values initial = initializeRandomly(
200  nonzeroRelativeTranslations, nonzeroBetweenTranslations, initialValues);
201 
202  // If there are no valid edges, but zero-distance edges exist, initialize one
203  // of the nodes in a connected component of zero-distance edges.
204  if (initial.empty() && !sameTranslationDSFMap.sets().empty()) {
205  for (const auto &optimizedAndDuplicateKeys : sameTranslationDSFMap.sets()) {
206  Key optimizedKey = optimizedAndDuplicateKeys.first;
207  initial.insert<Point3>(optimizedKey, Point3(0, 0, 0));
208  }
209  }
210 
211  LevenbergMarquardtOptimizer lm(graph, initial, lmParams_);
212  Values result = lm.optimize();
213  return addSameTranslationNodes(result, sameTranslationDSFMap);
214 }
215 
217  const Values &poses, const vector<KeyPair> &edges) {
218  auto edgeNoiseModel = noiseModel::Isotropic::Sigma(3, 0.01);
219  TranslationEdges relativeTranslations;
220  for (auto edge : edges) {
221  Key a, b;
222  tie(a, b) = edge;
223  const Pose3 wTa = poses.at<Pose3>(a), wTb = poses.at<Pose3>(b);
224  const Point3 Ta = wTa.translation(), Tb = wTb.translation();
225  const Unit3 w_aZb(Tb - Ta);
226  relativeTranslations.emplace_back(a, b, w_aZb, edgeNoiseModel);
227  }
228  return relativeTranslations;
229 }
vector< MFAS::KeyPair > edges
Definition: testMFAS.cpp:25
A insert(1, 2)=0
static std::mt19937 kRandomNumberGenerator(42)
const Point3 & translation(OptionalJacobian< 3, 6 > Hself={}) const
get translation
Definition: Pose3.cpp:308
Values initializeRandomly(const std::vector< BinaryMeasurement< Unit3 >> &relativeTranslations, const std::vector< BinaryMeasurement< Point3 >> &betweenTranslations, std::mt19937 *rng, const Values &initialValues=Values()) const
Create random initial translations.
IsDerived< DERIVEDFACTOR > emplace_shared(Args &&... args)
Emplace a shared pointer to factor of given type.
Definition: FactorGraph.h:196
A non-templated config holding any types of Manifold-group elements.
Factor Graph consisting of non-linear factors.
void merge(const KEY &x, const KEY &y)
Merge two sets.
Definition: DSFMap.h:87
std::vector< BinaryMeasurement< Unit3 > > TranslationEdges
const ValueType at(Key j) const
Definition: Values-inl.h:204
Values run(const TranslationEdges &relativeTranslations, const double scale=1.0, const std::vector< BinaryMeasurement< Point3 >> &betweenTranslations={}, const Values &initialValues=Values()) const
Build and optimize factor graph.
static std::mt19937 rng
Values initial
Definition: BFloat16.h:88
NonlinearFactorGraph graph
std::vector< BinaryMeasurement< T > > removeSameTranslationNodes(const std::vector< BinaryMeasurement< T >> &edges, const DSFMap< Key > &sameTranslationDSFMap)
static TranslationEdges SimulateMeasurements(const Values &poses, const std::vector< KeyPair > &edges)
Simulate translation direction measurements.
Values addSameTranslationNodes(const Values &result, const DSFMap< Key > &sameTranslationDSFMap)
Represents a 3D point on a unit sphere.
Definition: Unit3.h:42
DSFMap< Key > getSameTranslationDSFMap(const std::vector< BinaryMeasurement< Unit3 >> &relativeTranslations)
const Symbol key1('v', 1)
void addPrior(const std::vector< BinaryMeasurement< Unit3 >> &relativeTranslations, const double scale, const std::vector< BinaryMeasurement< Point3 >> &betweenTranslations, NonlinearFactorGraph *graph, const SharedNoiseModel &priorNoiseModel=noiseModel::Isotropic::Sigma(3, 0.01)) const
Add 3 factors to the graph:
Values result
A nonlinear optimizer that uses the Levenberg-Marquardt trust-region scheme.
NonlinearFactorGraph buildGraph(const std::vector< BinaryMeasurement< Unit3 >> &relativeTranslations) const
Build the factor graph to do the optimization.
const G & b
Definition: Group.h:86
Binary factor for a relative translation direction measurement.
traits
Definition: chartTesting.h:28
Non-linear factor base classes.
static double scale(double x, double a, double b, double t1, double t2)
Scale x from [a, b] to [t1, t2].
Definition: Chebyshev.cpp:35
std::map< KEY, Set > sets() const
return all sets, i.e. a partition of all elements
Definition: DSFMap.h:105
3D Point
void insert(Key j, const Value &val)
Definition: Values.cpp:155
Allow for arbitrary type in DSF.
Recovering translations in an epipolar graph when rotations are given.
Vector3 Point3
Definition: Point3.h:38
bool exists(Key j) const
Definition: Values.cpp:93
3D Pose
bool empty() const
Definition: Values.h:181
KEY find(const KEY &key) const
Given key, find the representative key for the set in which it lives.
Definition: DSFMap.h:81
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:102
std::ptrdiff_t j
noiseModel::Base::shared_ptr SharedNoiseModel
Definition: NoiseModel.h:741
static shared_ptr Sigma(size_t dim, double sigma, bool smart=true)
Definition: NoiseModel.cpp:594
graph addPrior(1, Pose2(0, 0, 0), priorNoise)
const Symbol key2('v', 2)


gtsam
Author(s):
autogenerated on Tue Jul 4 2023 02:40:24