gtsam 4.1.1
gtsam
EssentialMatrixFactor.h
1/*
2 * @file EssentialMatrixFactor.cpp
3 * @brief EssentialMatrixFactor class
4 * @author Frank Dellaert
5 * @date December 17, 2013
6 */
7
8#pragma once
9
10#include <gtsam/geometry/EssentialMatrix.h>
13
14#include <iostream>
15
16namespace gtsam {
17
21class EssentialMatrixFactor : public NoiseModelFactor1<EssentialMatrix> {
22 Vector3 vA_, vB_;
23
26
27 public:
36 EssentialMatrixFactor(Key key, const Point2& pA, const Point2& pB,
37 const SharedNoiseModel& model)
38 : Base(model, key) {
41 }
42
52 template <class CALIBRATION>
53 EssentialMatrixFactor(Key key, const Point2& pA, const Point2& pB,
54 const SharedNoiseModel& model,
55 boost::shared_ptr<CALIBRATION> K)
56 : Base(model, key) {
57 assert(K);
58 vA_ = EssentialMatrix::Homogeneous(K->calibrate(pA));
59 vB_ = EssentialMatrix::Homogeneous(K->calibrate(pB));
60 }
61
63 gtsam::NonlinearFactor::shared_ptr clone() const override {
64 return boost::static_pointer_cast<gtsam::NonlinearFactor>(
65 gtsam::NonlinearFactor::shared_ptr(new This(*this)));
66 }
67
69 void print(
70 const std::string& s = "",
71 const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
72 Base::print(s);
73 std::cout << " EssentialMatrixFactor with measurements\n ("
74 << vA_.transpose() << ")' and (" << vB_.transpose() << ")'"
75 << std::endl;
76 }
77
80 const EssentialMatrix& E,
81 boost::optional<Matrix&> H = boost::none) const override {
82 Vector error(1);
83 error << E.error(vA_, vB_, H);
84 return error;
85 }
86
87 public:
89};
90
96 : public NoiseModelFactor2<EssentialMatrix, double> {
97 Point3 dP1_;
98 Point2 pn_;
99 double f_;
100
103
104 public:
113 EssentialMatrixFactor2(Key key1, Key key2, const Point2& pA, const Point2& pB,
114 const SharedNoiseModel& model)
115 : Base(model, key1, key2),
116 dP1_(EssentialMatrix::Homogeneous(pA)),
117 pn_(pB) {
118 f_ = 1.0;
119 }
120
130 template <class CALIBRATION>
131 EssentialMatrixFactor2(Key key1, Key key2, const Point2& pA, const Point2& pB,
132 const SharedNoiseModel& model,
133 boost::shared_ptr<CALIBRATION> K)
134 : Base(model, key1, key2),
135 dP1_(EssentialMatrix::Homogeneous(K->calibrate(pA))),
136 pn_(K->calibrate(pB)) {
137 f_ = 0.5 * (K->fx() + K->fy());
138 }
139
141 gtsam::NonlinearFactor::shared_ptr clone() const override {
142 return boost::static_pointer_cast<gtsam::NonlinearFactor>(
143 gtsam::NonlinearFactor::shared_ptr(new This(*this)));
144 }
145
147 void print(
148 const std::string& s = "",
149 const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
150 Base::print(s);
151 std::cout << " EssentialMatrixFactor2 with measurements\n ("
152 << dP1_.transpose() << ")' and (" << pn_.transpose() << ")'"
153 << std::endl;
154 }
155
156 /*
157 * Vector of errors returns 2D vector
158 * @param E essential matrix
159 * @param d inverse depth d
160 */
162 const EssentialMatrix& E, const double& d,
163 boost::optional<Matrix&> DE = boost::none,
164 boost::optional<Matrix&> Dd = boost::none) const override {
165 // We have point x,y in image 1
166 // Given a depth Z, the corresponding 3D point P1 = Z*(x,y,1) = (x,y,1)/d
167 // We then convert to second camera by P2 = 1R2'*(P1-1T2)
168 // The homogeneous coordinates of can be written as
169 // 2R1*(P1-1T2) == 2R1*d*(P1-1T2) == 2R1*((x,y,1)-d*1T2)
170 // where we multiplied with d which yields equivalent homogeneous
171 // coordinates. Note that this is just the homography 2R1 for d==0 The point
172 // d*P1 = (x,y,1) is computed in constructor as dP1_
173
174 // Project to normalized image coordinates, then uncalibrate
175 Point2 pn(0, 0);
176 if (!DE && !Dd) {
177 Point3 _1T2 = E.direction().point3();
178 Point3 d1T2 = d * _1T2;
179 Point3 dP2 = E.rotation().unrotate(dP1_ - d1T2); // 2R1*((x,y,1)-d*1T2)
180 pn = PinholeBase::Project(dP2);
181
182 } else {
183 // Calculate derivatives. TODO if slow: optimize with Mathematica
184 // 3*2 3*3 3*3
185 Matrix D_1T2_dir, DdP2_rot, DP2_point;
186
187 Point3 _1T2 = E.direction().point3(D_1T2_dir);
188 Point3 d1T2 = d * _1T2;
189 Point3 dP2 = E.rotation().unrotate(dP1_ - d1T2, DdP2_rot, DP2_point);
190
191 Matrix23 Dpn_dP2;
192 pn = PinholeBase::Project(dP2, Dpn_dP2);
193
194 if (DE) {
195 Matrix DdP2_E(3, 5);
196 DdP2_E << DdP2_rot, -DP2_point * d * D_1T2_dir; // (3*3), (3*3) * (3*2)
197 *DE = f_ * Dpn_dP2 * DdP2_E; // (2*3) * (3*5)
198 }
199
200 if (Dd) // efficient backwards computation:
201 // (2*3) * (3*3) * (3*1)
202 *Dd = -f_ * (Dpn_dP2 * (DP2_point * _1T2));
203 }
204 Point2 reprojectionError = pn - pn_;
205 return f_ * reprojectionError;
206 }
207
208 public:
210};
211// EssentialMatrixFactor2
212
221
222 Rot3 cRb_;
223
224 public:
234 EssentialMatrixFactor3(Key key1, Key key2, const Point2& pA, const Point2& pB,
235 const Rot3& cRb, const SharedNoiseModel& model)
236 : EssentialMatrixFactor2(key1, key2, pA, pB, model), cRb_(cRb) {}
237
247 template <class CALIBRATION>
248 EssentialMatrixFactor3(Key key1, Key key2, const Point2& pA, const Point2& pB,
249 const Rot3& cRb, const SharedNoiseModel& model,
250 boost::shared_ptr<CALIBRATION> K)
251 : EssentialMatrixFactor2(key1, key2, pA, pB, model, K), cRb_(cRb) {}
252
254 gtsam::NonlinearFactor::shared_ptr clone() const override {
255 return boost::static_pointer_cast<gtsam::NonlinearFactor>(
256 gtsam::NonlinearFactor::shared_ptr(new This(*this)));
257 }
258
260 void print(
261 const std::string& s = "",
262 const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
263 Base::print(s);
264 std::cout << " EssentialMatrixFactor3 with rotation " << cRb_ << std::endl;
265 }
266
267 /*
268 * Vector of errors returns 2D vector
269 * @param E essential matrix
270 * @param d inverse depth d
271 */
273 const EssentialMatrix& E, const double& d,
274 boost::optional<Matrix&> DE = boost::none,
275 boost::optional<Matrix&> Dd = boost::none) const override {
276 if (!DE) {
277 // Convert E from body to camera frame
278 EssentialMatrix cameraE = cRb_ * E;
279 // Evaluate error
280 return Base::evaluateError(cameraE, d, boost::none, Dd);
281 } else {
282 // Version with derivatives
283 Matrix D_e_cameraE, D_cameraE_E; // 2*5, 5*5
284 EssentialMatrix cameraE = E.rotate(cRb_, D_cameraE_E);
285 Vector e = Base::evaluateError(cameraE, d, D_e_cameraE, Dd);
286 *DE = D_e_cameraE * D_cameraE_E; // (2*5) * (5*5)
287 return e;
288 }
289 }
290
291 public:
293};
294// EssentialMatrixFactor3
295
309template <class CALIBRATION>
311 : public NoiseModelFactor2<EssentialMatrix, CALIBRATION> {
312 private:
313 Point2 pA_, pB_;
314
317
318 static constexpr int DimK = FixedDimension<CALIBRATION>::value;
319 typedef Eigen::Matrix<double, 2, DimK> JacobianCalibration;
320
321 public:
331 EssentialMatrixFactor4(Key keyE, Key keyK, const Point2& pA, const Point2& pB,
332 const SharedNoiseModel& model)
333 : Base(model, keyE, keyK), pA_(pA), pB_(pB) {}
334
336 gtsam::NonlinearFactor::shared_ptr clone() const override {
337 return boost::static_pointer_cast<gtsam::NonlinearFactor>(
338 gtsam::NonlinearFactor::shared_ptr(new This(*this)));
339 }
340
342 void print(
343 const std::string& s = "",
344 const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
345 Base::print(s);
346 std::cout << " EssentialMatrixFactor4 with measurements\n ("
347 << pA_.transpose() << ")' and (" << pB_.transpose() << ")'"
348 << std::endl;
349 }
350
361 const EssentialMatrix& E, const CALIBRATION& K,
362 boost::optional<Matrix&> H1 = boost::none,
363 boost::optional<Matrix&> H2 = boost::none) const override {
364 // converting from pixel coordinates to normalized coordinates cA and cB
365 JacobianCalibration cA_H_K; // dcA/dK
366 JacobianCalibration cB_H_K; // dcB/dK
367 Point2 cA = K.calibrate(pA_, H2 ? &cA_H_K : 0, boost::none);
368 Point2 cB = K.calibrate(pB_, H2 ? &cB_H_K : 0, boost::none);
369
370 // convert to homogeneous coordinates
371 Vector3 vA = EssentialMatrix::Homogeneous(cA);
372 Vector3 vB = EssentialMatrix::Homogeneous(cB);
373
374 if (H2) {
375 // compute the jacobian of error w.r.t K
376
377 // error function f = vA.T * E * vB
378 // H2 = df/dK = vB.T * E.T * dvA/dK + vA.T * E * dvB/dK
379 // where dvA/dK = dvA/dcA * dcA/dK, dVB/dK = dvB/dcB * dcB/dK
380 // and dvA/dcA = dvB/dcB = [[1, 0], [0, 1], [0, 0]]
381 *H2 = vB.transpose() * E.matrix().transpose().leftCols<2>() * cA_H_K +
382 vA.transpose() * E.matrix().leftCols<2>() * cB_H_K;
383 }
384
385 Vector error(1);
386 error << E.error(vA, vB, H1);
387
388 return error;
389 }
390
391 public:
393};
394// EssentialMatrixFactor4
395
396} // namespace gtsam
#define GTSAM_MAKE_ALIGNED_OPERATOR_NEW
This marks a GTSAM object to require alignment.
Definition: types.h:277
Base class for all pinhole cameras.
Non-linear factor base classes.
Global functions in a separate testing namespace.
Definition: chartTesting.h:28
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:27
Vector3 Point3
As of GTSAM 4, in order to make GTSAM more lean, it is now possible to just typedef Point3 to Vector3...
Definition: Point3.h:35
noiseModel::Base::shared_ptr SharedNoiseModel
Note, deliberately not in noiseModel namespace.
Definition: NoiseModel.h:736
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:69
std::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition: Key.h:35
Give fixed size dimension of a type, fails at compile time if dynamic.
Definition: Manifold.h:164
static Point2 Project(const Point3 &pc, OptionalJacobian< 2, 3 > Dpoint=boost::none)
Project from 3D point in camera coordinates into image Does not throw a CheiralityException,...
Definition: CalibratedCamera.cpp:88
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
static Vector3 Homogeneous(const Point2 &p)
Static function to convert Point2 to homogeneous coordinates.
Definition: EssentialMatrix.h:34
Definition: Rot3.h:59
This is the base class for all factor types.
Definition: Factor.h:56
double error(const Values &c) const override
Calculate the error of the factor.
Definition: NonlinearFactor.cpp:127
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
Print.
Definition: NonlinearFactor.cpp:63
A convenient base class for creating your own NoiseModelFactor with 1 variable.
Definition: NonlinearFactor.h:285
A convenient base class for creating your own NoiseModelFactor with 2 variables.
Definition: NonlinearFactor.h:369
Key key1() const
methods to retrieve both keys
Definition: NonlinearFactor.h:401
Factor that evaluates epipolar error p'Ep for given essential matrix.
Definition: EssentialMatrixFactor.h:21
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: EssentialMatrixFactor.h:63
EssentialMatrixFactor(Key key, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model)
Constructor.
Definition: EssentialMatrixFactor.h:36
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print
Definition: EssentialMatrixFactor.h:69
EssentialMatrixFactor(Key key, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model, boost::shared_ptr< CALIBRATION > K)
Constructor.
Definition: EssentialMatrixFactor.h:53
Vector evaluateError(const EssentialMatrix &E, boost::optional< Matrix & > H=boost::none) const override
vector of errors returns 1D vector
Definition: EssentialMatrixFactor.h:79
Binary factor that optimizes for E and inverse depth d: assumes measurement in image 2 is perfect,...
Definition: EssentialMatrixFactor.h:96
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: EssentialMatrixFactor.h:141
Vector evaluateError(const EssentialMatrix &E, const double &d, boost::optional< Matrix & > DE=boost::none, boost::optional< Matrix & > Dd=boost::none) const override
Override this method to finish implementing a binary factor.
Definition: EssentialMatrixFactor.h:161
EssentialMatrixFactor2(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model, boost::shared_ptr< CALIBRATION > K)
Constructor.
Definition: EssentialMatrixFactor.h:131
EssentialMatrixFactor2(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model)
Constructor.
Definition: EssentialMatrixFactor.h:113
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print
Definition: EssentialMatrixFactor.h:147
Binary factor that optimizes for E and inverse depth d: assumes measurement in image 2 is perfect,...
Definition: EssentialMatrixFactor.h:218
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print
Definition: EssentialMatrixFactor.h:260
EssentialMatrixFactor3(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const Rot3 &cRb, const SharedNoiseModel &model)
Constructor.
Definition: EssentialMatrixFactor.h:234
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: EssentialMatrixFactor.h:254
Vector evaluateError(const EssentialMatrix &E, const double &d, boost::optional< Matrix & > DE=boost::none, boost::optional< Matrix & > Dd=boost::none) const override
Override this method to finish implementing a binary factor.
Definition: EssentialMatrixFactor.h:272
EssentialMatrixFactor3(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const Rot3 &cRb, const SharedNoiseModel &model, boost::shared_ptr< CALIBRATION > K)
Constructor.
Definition: EssentialMatrixFactor.h:248
Binary factor that optimizes for E and calibration K using the algebraic epipolar error (K^-1 pA)'E (...
Definition: EssentialMatrixFactor.h:311
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print
Definition: EssentialMatrixFactor.h:342
Vector evaluateError(const EssentialMatrix &E, const CALIBRATION &K, boost::optional< Matrix & > H1=boost::none, boost::optional< Matrix & > H2=boost::none) const override
Calculate the algebraic epipolar error pA' (K^-1)' E K pB.
Definition: EssentialMatrixFactor.h:360
EssentialMatrixFactor4(Key keyE, Key keyK, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model)
Constructor.
Definition: EssentialMatrixFactor.h:331
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: EssentialMatrixFactor.h:336