gtsam
Loading...
Searching...
No Matches
TransferFactor.h
1/* ----------------------------------------------------------------------------
2 * GTSAM Copyright 2010-2024, 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 * See LICENSE for the license information
7 * -------------------------------------------------------------------------- */
8
9/*
10 * @file TransferFactor.h
11 * @brief TransferFactor class
12 * @author Frank Dellaert
13 * @date October 24, 2024
14 */
15
16#pragma once
17
19#include <gtsam/geometry/EssentialMatrix.h>
20#include <gtsam/geometry/FundamentalMatrix.h>
26
27#include <cstdint>
28#include <stdexcept>
29
30namespace gtsam {
31
35template <typename F>
36class TransferEdges {
37 protected:
38 EdgeKey edge1_, edge2_;
39 uint32_t c_;
40
41 // Return appropriate noise model
42 static SharedNoiseModel defaultNoiseModel(size_t dim,
43 const SharedNoiseModel& model) {
44 if (!model) return noiseModel::Unit::Create(dim);
45 if (model->dim() == dim) return model;
46 throw std::runtime_error("TransferFactor: noise model dimension mismatch.");
47 }
48
49 public:
50 TransferEdges(EdgeKey edge1, EdgeKey edge2)
51 : edge1_(edge1), edge2_(edge2), c_(ViewC(edge1, edge2)) {}
52
54 static size_t ViewA(const EdgeKey& edge1, const EdgeKey& edge2) {
55 size_t c = ViewC(edge1, edge2);
56 return (edge1.i() == c) ? edge1.j() : edge1.i();
57 }
58
60 static size_t ViewB(const EdgeKey& edge1, const EdgeKey& edge2) {
61 size_t c = ViewC(edge1, edge2);
62 return (edge2.i() == c) ? edge2.j() : edge2.i();
63 }
64
66 static size_t ViewC(const EdgeKey& edge1, const EdgeKey& edge2) {
67 if (edge1.i() == edge2.i() || edge1.i() == edge2.j())
68 return edge1.i();
69 else if (edge1.j() == edge2.i() || edge1.j() == edge2.j())
70 return edge1.j();
71 else
72 throw std::runtime_error(
73 "EssentialTransferFactorK: No common key in edge keys.");
74 }
75
77 std::pair<Matrix3, Matrix3> getMatrices(const F& F1, const F& F2) const {
78 // Determine whether to transpose F1
79 const Matrix3 Fca =
80 edge1_.i() == c_ ? F1.matrix() : F1.matrix().transpose();
81
82 // Determine whether to transpose F2
83 const Matrix3 Fcb =
84 edge2_.i() == c_ ? F2.matrix() : F2.matrix().transpose();
85
86 return {Fca, Fcb};
87 }
88};
89
97template <typename F>
98class TransferFactor : public NoiseModelFactorN<F, F>, public TransferEdges<F> {
99 public:
100 using Base = NoiseModelFactorN<F, F>;
101 using Triplet = std::tuple<Point2, Point2, Point2>;
102
103 protected:
104 std::vector<Triplet> triplets_;
105
106 public:
117 const std::vector<Triplet>& triplets,
118 const SharedNoiseModel& model = nullptr)
119 : Base(TransferEdges<F>::defaultNoiseModel(2 * triplets.size(), model),
120 edge1, edge2),
121 TransferEdges<F>(edge1, edge2),
122 triplets_(triplets) {}
123
125 Vector evaluateError(const F& F1, const F& F2,
126 OptionalMatrixType H1 = nullptr,
127 OptionalMatrixType H2 = nullptr) const override {
128 std::function<Vector(const F&, const F&)> errorFunction = [&](const F& f1,
129 const F& f2) {
130 Vector errors(2 * triplets_.size());
131 size_t idx = 0;
132 auto [Fca, Fcb] = this->getMatrices(f1, f2);
133 for (const auto& [pa, pb, pc] : triplets_) {
134 errors.segment<2>(idx) = EpipolarTransfer(Fca, pa, Fcb, pb) - pc;
135 idx += 2;
136 }
137 return errors;
138 };
139
140 if (H1) *H1 = numericalDerivative21(errorFunction, F1, F2);
141 if (H2) *H2 = numericalDerivative22(errorFunction, F1, F2);
142 return errorFunction(F1, F2);
143 }
144};
145
157template <typename K>
158class EssentialTransferFactor : public TransferFactor<EssentialMatrix> {
159 using EM = EssentialMatrix;
160 using Triplet = std::tuple<Point2, Point2, Point2>;
161 std::shared_ptr<K> calibration_;
162
163 public:
164 using Base = TransferFactor<EM>;
165 using This = EssentialTransferFactor<K>;
166 using shared_ptr = std::shared_ptr<This>;
167
179 const std::vector<Triplet>& triplets,
180 const std::shared_ptr<K>& calibration,
181 const SharedNoiseModel& model = nullptr)
182 : Base(edge1, edge2, triplets, model), calibration_(calibration) {}
183
185 Vector2 TransferError(const Matrix3& Eca, const Point2& pa,
186 const Matrix3& Ecb, const Point2& pb,
187 const Point2& pc) const {
188 const Point2 pA = calibration_->calibrate(pa);
189 const Point2 pB = calibration_->calibrate(pb);
190 const Point2 pC = EpipolarTransfer(Eca, pA, Ecb, pB);
191 return calibration_->uncalibrate(pC) - pc;
192 }
193
195 Vector evaluateError(const EM& E1, const EM& E2,
196 OptionalMatrixType H1 = nullptr,
197 OptionalMatrixType H2 = nullptr) const override {
198 std::function<Vector(const EM&, const EM&)> errorFunction =
199 [&](const EM& e1, const EM& e2) {
200 Vector errors(2 * this->triplets_.size());
201 size_t idx = 0;
202 auto [Eca, Ecb] = this->getMatrices(e1, e2);
203 for (const auto& [pa, pb, pc] : this->triplets_) {
204 errors.segment<2>(idx) = TransferError(Eca, pa, Ecb, pb, pc);
205 idx += 2;
206 }
207 return errors;
208 };
209
210 // Compute error
211 Vector errors = errorFunction(E1, E2);
212
213 // Compute Jacobians if requested
214 if (H1) *H1 = numericalDerivative21(errorFunction, E1, E2);
215 if (H2) *H2 = numericalDerivative22(errorFunction, E1, E2);
216
217 return errors;
218 }
219};
220
235template <typename K>
237 : public NoiseModelFactorN<EssentialMatrix, EssentialMatrix, K, K, K>,
238 TransferEdges<EssentialMatrix> {
239 using EM = EssentialMatrix;
240 using Triplet = std::tuple<Point2, Point2, Point2>;
241 std::vector<Triplet> triplets_;
242
243 public:
245 using This = EssentialTransferFactorK<K>;
246 using shared_ptr = std::shared_ptr<This>;
247
259 const std::vector<Triplet>& triplets,
260 const SharedNoiseModel& model = nullptr)
261 : Base(TransferEdges<EM>::defaultNoiseModel(2 * triplets.size(), model),
262 edge1, edge2,
263 Symbol('k', ViewA(edge1, edge2)), // calibration key for view a
264 Symbol('k', ViewB(edge1, edge2)), // calibration key for view b
265 Symbol('k', ViewC(edge1, edge2))), // calibration key for target c
266 TransferEdges<EM>(edge1, edge2),
267 triplets_(triplets) {}
268
281 const std::vector<Triplet>& triplets,
282 const SharedNoiseModel& model = nullptr)
283 : Base(TransferEdges<EM>::defaultNoiseModel(2 * triplets.size(), model),
284 edge1, edge2, keyK, keyK, keyK),
285 TransferEdges<EM>(edge1, edge2),
286 triplets_(triplets) {}
287
289 Vector2 TransferError(const Matrix3& Eca, const K& Ka, const Point2& pa,
290 const Matrix3& Ecb, const K& Kb, const Point2& pb,
291 const K& Kc, const Point2& pc) const {
292 const Point2 pA = Ka.calibrate(pa);
293 const Point2 pB = Kb.calibrate(pb);
294 const Point2 pC = EpipolarTransfer(Eca, pA, Ecb, pB);
295 return Kc.uncalibrate(pC) - pc;
296 }
297
299 Vector evaluateError(const EM& E1, const EM& E2, const K& Ka, const K& Kb,
300 const K& Kc, OptionalMatrixType H1 = nullptr,
301 OptionalMatrixType H2 = nullptr,
302 OptionalMatrixType H3 = nullptr,
303 OptionalMatrixType H4 = nullptr,
304 OptionalMatrixType H5 = nullptr) const override {
305 std::function<Vector(const EM&, const EM&, const K&, const K&, const K&)>
306 errorFunction = [&](const EM& e1, const EM& e2, const K& kA,
307 const K& kB, const K& kC) {
308 Vector errors(2 * triplets_.size());
309 size_t idx = 0;
310 auto [Eca, Ecb] = this->getMatrices(e1, e2);
311 for (const auto& [pa, pb, pc] : triplets_) {
312 errors.segment<2>(idx) =
313 TransferError(Eca, kA, pa, Ecb, kB, pb, kC, pc);
314 idx += 2;
315 }
316 return errors;
317 };
318
319 // Compute error
320 Vector errors = errorFunction(E1, E2, Ka, Kb, Kc);
321
322 // Compute Jacobians if requested
323 if (H1) *H1 = numericalDerivative51(errorFunction, E1, E2, Ka, Kb, Kc);
324 if (H2) *H2 = numericalDerivative52(errorFunction, E1, E2, Ka, Kb, Kc);
325 if (H3) *H3 = numericalDerivative53(errorFunction, E1, E2, Ka, Kb, Kc);
326 if (H4) *H4 = numericalDerivative54(errorFunction, E1, E2, Ka, Kb, Kc);
327 if (H5) *H5 = numericalDerivative55(errorFunction, E1, E2, Ka, Kb, Kc);
328
329 return errors;
330 }
331
333 size_t dim() const override { return 2 * triplets_.size(); }
334};
335
336} // namespace gtsam
Numerical derivative helpers for manifold-valued functions.
Base class for noise model factors with N variables.
Non-linear factor base classes.
internal::MatrixMN< traits< internal::OutputType< Y, F, X1, X2, X3, X4, X5 > >::dimension, N >::type numericalDerivative51(F &&h, const X1 &x1, const X2 &x2, const X3 &x3, const X4 &x4, const X5 &x5, double delta=1e-5)
Compute numerical derivative in argument 1 of 5-argument function.
Definition numericalDerivative.h:516
internal::MatrixMN< traits< internal::OutputType< Y, F, X1, X2, X3, X4, X5 > >::dimension, N >::type numericalDerivative52(F &&h, const X1 &x1, const X2 &x2, const X3 &x3, const X4 &x4, const X5 &x5, double delta=1e-5)
Compute numerical derivative in argument 2 of 5-argument function.
Definition numericalDerivative.h:550
internal::MatrixMN< traits< internal::OutputType< Y, F, X1, X2, X3, X4, X5 > >::dimension, N >::type numericalDerivative53(F &&h, const X1 &x1, const X2 &x2, const X3 &x3, const X4 &x4, const X5 &x5, double delta=1e-5)
Compute numerical derivative in argument 3 of 5-argument function.
Definition numericalDerivative.h:584
internal::MatrixMN< traits< internal::OutputType< Y, F, X1, X2 > >::dimension, N >::type numericalDerivative21(F &&h, const X1 &x1, const X2 &x2, double delta=1e-5)
Compute numerical derivative in argument 1 of binary function.
Definition numericalDerivative.h:236
internal::MatrixMN< traits< internal::OutputType< Y, F, X1, X2 > >::dimension, N >::type numericalDerivative22(F &&h, const X1 &x1, const X2 &x2, double delta=1e-5)
Compute numerical derivative in argument 2 of binary function.
Definition numericalDerivative.h:265
internal::MatrixMN< traits< internal::OutputType< Y, F, X1, X2, X3, X4, X5 > >::dimension, N >::type numericalDerivative55(F &&h, const X1 &x1, const X2 &x2, const X3 &x3, const X4 &x4, const X5 &x5, double delta=1e-5)
Compute numerical derivative in argument 5 of 5-argument function.
Definition numericalDerivative.h:652
internal::MatrixMN< traits< internal::OutputType< Y, F, X1, X2, X3, X4, X5 > >::dimension, N >::type numericalDerivative54(F &&h, const X1 &x1, const X2 &x2, const X3 &x3, const X4 &x4, const X5 &x5, double delta=1e-5)
Compute numerical derivative in argument 4 of 5-argument function.
Definition numericalDerivative.h:618
Global functions in a separate testing namespace.
Definition chartTesting.h:28
Matrix * OptionalMatrixType
This typedef will be used everywhere boost::optional<Matrix&> reference was used previously.
Definition NonlinearFactor.h:57
NoiseModelFactorT< Vector, ValueTypes... > NoiseModelFactorN
Noise model factor with N value types and dynamic-sized error vector.
Definition NoiseModelFactorN.h:561
Vector2 Point2
As of GTSAM 4, in order to make GTSAM more lean, it is now possible to just typedef Point2 to Vector2...
Definition Point2.h:32
noiseModel::Base::shared_ptr SharedNoiseModel
Aliases.
Definition NoiseModel.h:846
std::uint64_t Key
Integer nonlinear key type.
Definition types.h:43
Point2 EpipolarTransfer(const Matrix3 &Fca, const Point2 &pa, const Matrix3 &Fcb, const Point2 &pb)
Transfer projections from cameras a and b to camera c.
Definition FundamentalMatrix.cpp:15
An essential matrix is like a Pose3, except with translation up to scale It is named after the 3*3 ma...
Definition EssentialMatrix.h:26
Definition EdgeKey.h:25
std::uint32_t j() const
Retrieve low 32 bits.
Definition EdgeKey.h:58
std::uint32_t i() const
Retrieve high 32 bits.
Definition EdgeKey.h:55
size_t size() const
Definition Factor.h:160
Character and index key used to refer to variables.
Definition Symbol.h:37
static shared_ptr Create(size_t dim)
Create a unit covariance noise model.
Definition NoiseModel.h:673
Base class that holds the EdgeKeys and provides the getMatrices method.
Definition TransferFactor.h:36
static size_t ViewC(const EdgeKey &edge1, const EdgeKey &edge2)
Returns the view C index based on the EdgeKeys.
Definition TransferFactor.h:66
uint32_t c_
The transfer target.
Definition TransferFactor.h:39
std::pair< Matrix3, Matrix3 > getMatrices(const F &F1, const F &F2) const
Create Matrix3 objects based on EdgeKey configurations.
Definition TransferFactor.h:77
static size_t ViewA(const EdgeKey &edge1, const EdgeKey &edge2)
Returns the view A index based on the EdgeKeys.
Definition TransferFactor.h:54
static size_t ViewB(const EdgeKey &edge1, const EdgeKey &edge2)
Returns the view B index based on the EdgeKeys.
Definition TransferFactor.h:60
EdgeKey edge2_
The two EdgeKeys.
Definition TransferFactor.h:38
Vector evaluateError(const F &F1, const F &F2, OptionalMatrixType H1=nullptr, OptionalMatrixType H2=nullptr) const override
Vector of errors returns 2*N vector.
Definition TransferFactor.h:125
TransferFactor(EdgeKey edge1, EdgeKey edge2, const std::vector< Triplet > &triplets, const SharedNoiseModel &model=nullptr)
Constructor that accepts a vector of point triplets.
Definition TransferFactor.h:116
std::vector< Triplet > triplets_
Definition TransferFactor.h:104
Vector2 TransferError(const Matrix3 &Eca, const Point2 &pa, const Matrix3 &Ecb, const Point2 &pb, const Point2 &pc) const
Transfer points pa and pb to view c and evaluate error.
Definition TransferFactor.h:185
Vector evaluateError(const EM &E1, const EM &E2, OptionalMatrixType H1=nullptr, OptionalMatrixType H2=nullptr) const override
Evaluate error function.
Definition TransferFactor.h:195
EssentialTransferFactor(EdgeKey edge1, EdgeKey edge2, const std::vector< Triplet > &triplets, const std::shared_ptr< K > &calibration, const SharedNoiseModel &model=nullptr)
Constructor that accepts a vector of point triplets and a shared calibration.
Definition TransferFactor.h:178
Vector2 TransferError(const Matrix3 &Eca, const K &Ka, const Point2 &pa, const Matrix3 &Ecb, const K &Kb, const Point2 &pb, const K &Kc, const Point2 &pc) const
Transfer points pa and pb to view c and evaluate error.
Definition TransferFactor.h:289
size_t dim() const override
Return the dimension of the factor.
Definition TransferFactor.h:333
Vector evaluateError(const EM &E1, const EM &E2, const K &Ka, const K &Kb, const K &Kc, OptionalMatrixType H1=nullptr, OptionalMatrixType H2=nullptr, OptionalMatrixType H3=nullptr, OptionalMatrixType H4=nullptr, OptionalMatrixType H5=nullptr) const override
Evaluate error function.
Definition TransferFactor.h:299
EssentialTransferFactorK(EdgeKey edge1, EdgeKey edge2, Key keyK, const std::vector< Triplet > &triplets, const SharedNoiseModel &model=nullptr)
Constructor that accepts a vector of point triplets.
Definition TransferFactor.h:280
EssentialTransferFactorK(EdgeKey edge1, EdgeKey edge2, const std::vector< Triplet > &triplets, const SharedNoiseModel &model=nullptr)
Constructor that accepts a vector of point triplets.
Definition TransferFactor.h:258