GTSAM  4.0.2
C++ library for smoothing and mapping (SAM)
EssentialMatrixFactor.h
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010-2014, 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 
12 /*
13  * @file EssentialMatrixFactor.h
14  * @brief EssentialMatrixFactor class
15  * @author Frank Dellaert
16  * @author Ayush Baid
17  * @author Akshay Krishnan
18  * @date December 17, 2013
19  */
20 
21 #pragma once
22 
23 #include <gtsam/geometry/EssentialMatrix.h>
26 
27 #include <iostream>
28 
29 namespace gtsam {
30 
34 class EssentialMatrixFactor : public NoiseModelFactorN<EssentialMatrix> {
35  Vector3 vA_, vB_;
36 
39 
40  public:
41 
42  // Provide access to the Matrix& version of evaluateError:
43  using Base::evaluateError;
44 
53  EssentialMatrixFactor(Key key, const Point2& pA, const Point2& pB,
54  const SharedNoiseModel& model)
55  : Base(model, key) {
58  }
59 
69  template <class CALIBRATION>
70  EssentialMatrixFactor(Key key, const Point2& pA, const Point2& pB,
71  const SharedNoiseModel& model,
72  std::shared_ptr<CALIBRATION> K)
73  : Base(model, key) {
74  assert(K);
75  vA_ = EssentialMatrix::Homogeneous(K->calibrate(pA));
76  vB_ = EssentialMatrix::Homogeneous(K->calibrate(pB));
77  }
78 
80  gtsam::NonlinearFactor::shared_ptr clone() const override {
81  return std::static_pointer_cast<gtsam::NonlinearFactor>(
82  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
83  }
84 
86  void print(
87  const std::string& s = "",
88  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
89  Base::print(s);
90  std::cout << " EssentialMatrixFactor with measurements\n ("
91  << vA_.transpose() << ")' and (" << vB_.transpose() << ")'"
92  << std::endl;
93  }
94 
96  Vector evaluateError(
97  const EssentialMatrix& E, OptionalMatrixType H) const override {
98  Vector error(1);
99  error << E.error(vA_, vB_, H);
100  return error;
101  }
102 
103  public:
105 };
106 
112  : public NoiseModelFactorN<EssentialMatrix, double> {
113  Point3 dP1_;
114  Point2 pn_;
115  double f_;
116 
119 
120  public:
121 
122  // Provide access to the Matrix& version of evaluateError:
123  using Base::evaluateError;
124 
133  EssentialMatrixFactor2(Key key1, Key key2, const Point2& pA, const Point2& pB,
134  const SharedNoiseModel& model)
135  : Base(model, key1, key2),
136  dP1_(EssentialMatrix::Homogeneous(pA)),
137  pn_(pB) {
138  f_ = 1.0;
139  }
140 
150  template <class CALIBRATION>
151  EssentialMatrixFactor2(Key key1, Key key2, const Point2& pA, const Point2& pB,
152  const SharedNoiseModel& model,
153  std::shared_ptr<CALIBRATION> K)
154  : Base(model, key1, key2),
155  dP1_(EssentialMatrix::Homogeneous(K->calibrate(pA))),
156  pn_(K->calibrate(pB)) {
157  f_ = 0.5 * (K->fx() + K->fy());
158  }
159 
161  gtsam::NonlinearFactor::shared_ptr clone() const override {
162  return std::static_pointer_cast<gtsam::NonlinearFactor>(
163  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
164  }
165 
167  void print(
168  const std::string& s = "",
169  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
170  Base::print(s);
171  std::cout << " EssentialMatrixFactor2 with measurements\n ("
172  << dP1_.transpose() << ")' and (" << pn_.transpose() << ")'"
173  << std::endl;
174  }
175 
176  /*
177  * Vector of errors returns 2D vector
178  * @param E essential matrix
179  * @param d inverse depth d
180  */
181  Vector evaluateError(
182  const EssentialMatrix& E, const double& d,
183  OptionalMatrixType DE, OptionalMatrixType Dd) const override {
184  // We have point x,y in image 1
185  // Given a depth Z, the corresponding 3D point P1 = Z*(x,y,1) = (x,y,1)/d
186  // We then convert to second camera by P2 = 1R2'*(P1-1T2)
187  // The homogeneous coordinates of can be written as
188  // 2R1*(P1-1T2) == 2R1*d*(P1-1T2) == 2R1*((x,y,1)-d*1T2)
189  // where we multiplied with d which yields equivalent homogeneous
190  // coordinates. Note that this is just the homography 2R1 for d==0 The point
191  // d*P1 = (x,y,1) is computed in constructor as dP1_
192 
193  // Project to normalized image coordinates, then uncalibrate
194  Point2 pn(0, 0);
195  if (!DE && !Dd) {
196  Point3 _1T2 = E.direction().point3();
197  Point3 d1T2 = d * _1T2;
198  Point3 dP2 = E.rotation().unrotate(dP1_ - d1T2); // 2R1*((x,y,1)-d*1T2)
199  pn = PinholeBase::Project(dP2);
200 
201  } else {
202  // Calculate derivatives. TODO if slow: optimize with Mathematica
203  // 3*2 3*3 3*3
204  Matrix D_1T2_dir, DdP2_rot, DP2_point;
205 
206  Point3 _1T2 = E.direction().point3(D_1T2_dir);
207  Point3 d1T2 = d * _1T2;
208  Point3 dP2 = E.rotation().unrotate(dP1_ - d1T2, DdP2_rot, DP2_point);
209 
210  Matrix23 Dpn_dP2;
211  pn = PinholeBase::Project(dP2, Dpn_dP2);
212 
213  if (DE) {
214  Matrix DdP2_E(3, 5);
215  DdP2_E << DdP2_rot, -DP2_point * d * D_1T2_dir; // (3*3), (3*3) * (3*2)
216  *DE = f_ * Dpn_dP2 * DdP2_E; // (2*3) * (3*5)
217  }
218 
219  if (Dd) // efficient backwards computation:
220  // (2*3) * (3*3) * (3*1)
221  *Dd = -f_ * (Dpn_dP2 * (DP2_point * _1T2));
222  }
223  Point2 reprojectionError = pn - pn_;
224  return f_ * reprojectionError;
225  }
226 
227  public:
229 };
230 // EssentialMatrixFactor2
231 
240 
241  Rot3 cRb_;
242 
243  public:
244 
245  // Provide access to the Matrix& version of evaluateError:
246  using Base::evaluateError;
247 
257  EssentialMatrixFactor3(Key key1, Key key2, const Point2& pA, const Point2& pB,
258  const Rot3& cRb, const SharedNoiseModel& model)
259  : EssentialMatrixFactor2(key1, key2, pA, pB, model), cRb_(cRb) {}
260 
270  template <class CALIBRATION>
271  EssentialMatrixFactor3(Key key1, Key key2, const Point2& pA, const Point2& pB,
272  const Rot3& cRb, const SharedNoiseModel& model,
273  std::shared_ptr<CALIBRATION> K)
274  : EssentialMatrixFactor2(key1, key2, pA, pB, model, K), cRb_(cRb) {}
275 
277  gtsam::NonlinearFactor::shared_ptr clone() const override {
278  return std::static_pointer_cast<gtsam::NonlinearFactor>(
279  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
280  }
281 
283  void print(
284  const std::string& s = "",
285  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
286  Base::print(s);
287  std::cout << " EssentialMatrixFactor3 with rotation " << cRb_ << std::endl;
288  }
289 
290  /*
291  * Vector of errors returns 2D vector
292  * @param E essential matrix
293  * @param d inverse depth d
294  */
295  Vector evaluateError(
296  const EssentialMatrix& E, const double& d,
297  OptionalMatrixType DE, OptionalMatrixType Dd) const override {
298  if (!DE) {
299  // Convert E from body to camera frame
300  EssentialMatrix cameraE = cRb_ * E;
301  // Evaluate error
302  return Base::evaluateError(cameraE, d, OptionalNone, Dd);
303  } else {
304  // Version with derivatives
305  Matrix D_e_cameraE, D_cameraE_E; // 2*5, 5*5
306  EssentialMatrix cameraE = E.rotate(cRb_, D_cameraE_E);
307  // Using the pointer version of evaluateError since the Base class (EssentialMatrixFactor2)
308  // does not have the matrix reference version of evaluateError
309  Vector e = Base::evaluateError(cameraE, d, &D_e_cameraE, Dd);
310  *DE = D_e_cameraE * D_cameraE_E; // (2*5) * (5*5)
311  return e;
312  }
313  }
314 
315  public:
317 };
318 // EssentialMatrixFactor3
319 
333 template <class CALIBRATION>
335  : public NoiseModelFactorN<EssentialMatrix, CALIBRATION> {
336  private:
337  Point2 pA_, pB_;
338 
341 
342  static constexpr int DimK = FixedDimension<CALIBRATION>::value;
343  typedef Eigen::Matrix<double, 2, DimK> JacobianCalibration;
344 
345  public:
346 
347  // Provide access to the Matrix& version of evaluateError:
348  using Base::evaluateError;
349 
359  EssentialMatrixFactor4(Key keyE, Key keyK, const Point2& pA, const Point2& pB,
360  const SharedNoiseModel& model)
361  : Base(model, keyE, keyK), pA_(pA), pB_(pB) {}
362 
364  gtsam::NonlinearFactor::shared_ptr clone() const override {
365  return std::static_pointer_cast<gtsam::NonlinearFactor>(
366  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
367  }
368 
370  void print(
371  const std::string& s = "",
372  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
373  Base::print(s);
374  std::cout << " EssentialMatrixFactor4 with measurements\n ("
375  << pA_.transpose() << ")' and (" << pB_.transpose() << ")'"
376  << std::endl;
377  }
378 
389  const EssentialMatrix& E, const CALIBRATION& K,
390  OptionalMatrixType H1, OptionalMatrixType H2) const override {
391  // converting from pixel coordinates to normalized coordinates cA and cB
392  JacobianCalibration cA_H_K; // dcA/dK
393  JacobianCalibration cB_H_K; // dcB/dK
394  Point2 cA = K.calibrate(pA_, H2 ? &cA_H_K : 0, OptionalNone);
395  Point2 cB = K.calibrate(pB_, H2 ? &cB_H_K : 0, OptionalNone);
396 
397  // convert to homogeneous coordinates
398  Vector3 vA = EssentialMatrix::Homogeneous(cA);
399  Vector3 vB = EssentialMatrix::Homogeneous(cB);
400 
401  if (H2) {
402  // compute the jacobian of error w.r.t K
403 
404  // error function f = vA.T * E * vB
405  // H2 = df/dK = vB.T * E.T * dvA/dK + vA.T * E * dvB/dK
406  // where dvA/dK = dvA/dcA * dcA/dK, dVB/dK = dvB/dcB * dcB/dK
407  // and dvA/dcA = dvB/dcB = [[1, 0], [0, 1], [0, 0]]
408  *H2 = vB.transpose() * E.matrix().transpose().leftCols<2>() * cA_H_K +
409  vA.transpose() * E.matrix().leftCols<2>() * cB_H_K;
410  }
411 
412  Vector error(1);
413  error << E.error(vA, vB, H1);
414 
415  return error;
416  }
417 
418  public:
420 };
421 // EssentialMatrixFactor4
422 
423 } // namespace gtsam
Definition: NonlinearFactor.h:431
double error(const Values &c) const override
GTSAM_EXPORT EssentialMatrix rotate(const Rot3 &cRb, OptionalJacobian< 5, 5 > HE={}, OptionalJacobian< 5, 3 > HR={}) const
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: EssentialMatrixFactor.h:161
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print
Definition: EssentialMatrixFactor.h:370
Definition: EssentialMatrixFactor.h:237
const Unit3 & direction() const
Direction.
Definition: EssentialMatrix.h:115
Definition: Factor.h:69
Vector2 Point2
Definition: Point2.h:32
virtual Vector evaluateError(const ValueTypes &... x, OptionalMatrixTypeT< ValueTypes >... H) const=0
Give fixed size dimension of a type, fails at compile time if dynamic.
Definition: Manifold.h:161
Key key() const
Definition: NonlinearFactor.h:582
Definition: NonlinearFactor.h:68
EssentialMatrixFactor3(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const Rot3 &cRb, const SharedNoiseModel &model, std::shared_ptr< CALIBRATION > K)
Definition: EssentialMatrixFactor.h:271
static Point2 Project(const Point3 &pc, OptionalJacobian< 2, 3 > Dpoint={})
Rot3 is a 3D rotation represented as a rotation matrix if the preprocessor symbol GTSAM_USE_QUATERNIO...
Definition: Rot3.h:58
Vector evaluateError(const EssentialMatrix &E, const CALIBRATION &K, OptionalMatrixType H1, OptionalMatrixType H2) const override
Calculate the algebraic epipolar error pA&#39; (K^-1)&#39; E K pB.
Definition: EssentialMatrixFactor.h:388
static Vector3 Homogeneous(const Point2 &p)
Static function to convert Point2 to homogeneous coordinates.
Definition: EssentialMatrix.h:34
#define OptionalNone
Definition: NonlinearFactor.h:49
Base class for all pinhole cameras.
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: EssentialMatrixFactor.h:277
EssentialMatrixFactor(Key key, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model, std::shared_ptr< CALIBRATION > K)
Definition: EssentialMatrixFactor.h:70
Matrix * OptionalMatrixType
Definition: NonlinearFactor.h:55
Point3 unrotate(const Point3 &p, OptionalJacobian< 3, 3 > H1={}, OptionalJacobian< 3, 3 > H2={}) const
rotate point from world to rotated frame
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print
Definition: EssentialMatrixFactor.h:283
EssentialMatrixFactor(Key key, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model)
Definition: EssentialMatrixFactor.h:53
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: EssentialMatrixFactor.h:80
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print
Definition: EssentialMatrixFactor.h:86
EssentialMatrixFactor2(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model, std::shared_ptr< CALIBRATION > K)
Definition: EssentialMatrixFactor.h:151
const Rot3 & rotation() const
Rotation.
Definition: EssentialMatrix.h:110
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
Definition: EssentialMatrixFactor.h:34
EssentialMatrixFactor3(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const Rot3 &cRb, const SharedNoiseModel &model)
Definition: EssentialMatrixFactor.h:257
Definition: chartTesting.h:28
Definition: EssentialMatrix.h:26
EssentialMatrixFactor4(Key keyE, Key keyK, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model)
Definition: EssentialMatrixFactor.h:359
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
Non-linear factor base classes.
Definition: EssentialMatrixFactor.h:111
const Matrix3 & matrix() const
Return 3*3 matrix representation.
Definition: EssentialMatrix.h:120
gtsam::NonlinearFactor::shared_ptr clone() const override
Definition: EssentialMatrixFactor.h:364
Vector evaluateError(const EssentialMatrix &E, OptionalMatrixType H) const override
vector of errors returns 1D vector
Definition: EssentialMatrixFactor.h:96
#define GTSAM_MAKE_ALIGNED_OPERATOR_NEW
Definition: types.h:284
Point3 point3(OptionalJacobian< 3, 2 > H={}) const
Return unit-norm Point3.
Vector3 Point3
Definition: Point3.h:38
Definition: EssentialMatrixFactor.h:334
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
print
Definition: EssentialMatrixFactor.h:167
GTSAM_EXPORT double error(const Vector3 &vA, const Vector3 &vB, OptionalJacobian< 1, 5 > H={}) const
epipolar error, algebraic
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:102
noiseModel::Base::shared_ptr SharedNoiseModel
Definition: NoiseModel.h:741
EssentialMatrixFactor2(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model)
Definition: EssentialMatrixFactor.h:133