gtsam  4.0.0
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 
11 #include <gtsam/geometry/EssentialMatrix.h>
13 #include <iostream>
14 
15 namespace gtsam {
16 
20 class EssentialMatrixFactor: public NoiseModelFactor1<EssentialMatrix> {
21 
22  Vector3 vA_, vB_;
23 
26 
27 public:
28 
36  EssentialMatrixFactor(Key key, const Point2& pA, const Point2& pB,
37  const SharedNoiseModel& model) :
38  Base(model, key) {
41  }
42 
51  template<class CALIBRATION>
52  EssentialMatrixFactor(Key key, const Point2& pA, const Point2& pB,
53  const SharedNoiseModel& model, boost::shared_ptr<CALIBRATION> K) :
54  Base(model, key) {
55  assert(K);
56  vA_ = EssentialMatrix::Homogeneous(K->calibrate(pA));
57  vB_ = EssentialMatrix::Homogeneous(K->calibrate(pB));
58  }
59 
61  virtual gtsam::NonlinearFactor::shared_ptr clone() const {
62  return boost::static_pointer_cast<gtsam::NonlinearFactor>(
63  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
64  }
65 
67  virtual void print(const std::string& s = "",
68  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const {
69  Base::print(s);
70  std::cout << " EssentialMatrixFactor with measurements\n ("
71  << vA_.transpose() << ")' and (" << vB_.transpose() << ")'"
72  << std::endl;
73  }
74 
76  Vector evaluateError(const EssentialMatrix& E, boost::optional<Matrix&> H =
77  boost::none) const {
78  Vector error(1);
79  error << E.error(vA_, vB_, H);
80  return error;
81  }
82 
83 };
84 
89 class EssentialMatrixFactor2: public NoiseModelFactor2<EssentialMatrix, double> {
90 
91  Point3 dP1_;
92  Point2 pn_;
93  double f_;
94 
97 
98 public:
99 
108  EssentialMatrixFactor2(Key key1, Key key2, const Point2& pA, const Point2& pB,
109  const SharedNoiseModel& model) :
110  Base(model, key1, key2), dP1_(EssentialMatrix::Homogeneous(pA)), pn_(pB) {
111  f_ = 1.0;
112  }
113 
123  template<class CALIBRATION>
124  EssentialMatrixFactor2(Key key1, Key key2, const Point2& pA, const Point2& pB,
125  const SharedNoiseModel& model, boost::shared_ptr<CALIBRATION> K) :
126  Base(model, key1, key2), dP1_(
127  EssentialMatrix::Homogeneous(K->calibrate(pA))), pn_(K->calibrate(pB)) {
128  f_ = 0.5 * (K->fx() + K->fy());
129  }
130 
132  virtual gtsam::NonlinearFactor::shared_ptr clone() const {
133  return boost::static_pointer_cast<gtsam::NonlinearFactor>(
134  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
135  }
136 
138  virtual void print(const std::string& s = "",
139  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const {
140  Base::print(s);
141  std::cout << " EssentialMatrixFactor2 with measurements\n ("
142  << dP1_.transpose() << ")' and (" << pn_.transpose()
143  << ")'" << std::endl;
144  }
145 
146  /*
147  * Vector of errors returns 2D vector
148  * @param E essential matrix
149  * @param d inverse depth d
150  */
151  Vector evaluateError(const EssentialMatrix& E, const double& d,
152  boost::optional<Matrix&> DE = boost::none, boost::optional<Matrix&> Dd =
153  boost::none) const {
154 
155  // We have point x,y in image 1
156  // Given a depth Z, the corresponding 3D point P1 = Z*(x,y,1) = (x,y,1)/d
157  // We then convert to second camera by P2 = 1R2'*(P1-1T2)
158  // The homogeneous coordinates of can be written as
159  // 2R1*(P1-1T2) == 2R1*d*(P1-1T2) == 2R1*((x,y,1)-d*1T2)
160  // where we multiplied with d which yields equivalent homogeneous coordinates.
161  // Note that this is just the homography 2R1 for d==0
162  // The point d*P1 = (x,y,1) is computed in constructor as dP1_
163 
164  // Project to normalized image coordinates, then uncalibrate
165  Point2 pn(0,0);
166  if (!DE && !Dd) {
167 
168  Point3 _1T2 = E.direction().point3();
169  Point3 d1T2 = d * _1T2;
170  Point3 dP2 = E.rotation().unrotate(dP1_ - d1T2); // 2R1*((x,y,1)-d*1T2)
171  pn = PinholeBase::Project(dP2);
172 
173  } else {
174 
175  // Calculate derivatives. TODO if slow: optimize with Mathematica
176  // 3*2 3*3 3*3
177  Matrix D_1T2_dir, DdP2_rot, DP2_point;
178 
179  Point3 _1T2 = E.direction().point3(D_1T2_dir);
180  Point3 d1T2 = d * _1T2;
181  Point3 dP2 = E.rotation().unrotate(dP1_ - d1T2, DdP2_rot, DP2_point);
182 
183  Matrix23 Dpn_dP2;
184  pn = PinholeBase::Project(dP2, Dpn_dP2);
185 
186  if (DE) {
187  Matrix DdP2_E(3, 5);
188  DdP2_E << DdP2_rot, -DP2_point * d * D_1T2_dir; // (3*3), (3*3) * (3*2)
189  *DE = f_ * Dpn_dP2 * DdP2_E; // (2*3) * (3*5)
190  }
191 
192  if (Dd) // efficient backwards computation:
193  // (2*3) * (3*3) * (3*1)
194  *Dd = -f_ * (Dpn_dP2 * (DP2_point * _1T2));
195 
196  }
197  Point2 reprojectionError = pn - pn_;
198  return f_ * reprojectionError;
199  }
200 
201 };
202 // EssentialMatrixFactor2
203 
210 
213 
214  Rot3 cRb_;
215 
216 public:
217 
227  EssentialMatrixFactor3(Key key1, Key key2, const Point2& pA, const Point2& pB,
228  const Rot3& cRb, const SharedNoiseModel& model) :
229  EssentialMatrixFactor2(key1, key2, pA, pB, model), cRb_(cRb) {
230  }
231 
241  template<class CALIBRATION>
242  EssentialMatrixFactor3(Key key1, Key key2, const Point2& pA, const Point2& pB,
243  const Rot3& cRb, const SharedNoiseModel& model,
244  boost::shared_ptr<CALIBRATION> K) :
245  EssentialMatrixFactor2(key1, key2, pA, pB, model, K), cRb_(cRb) {
246  }
247 
249  virtual gtsam::NonlinearFactor::shared_ptr clone() const {
250  return boost::static_pointer_cast<gtsam::NonlinearFactor>(
251  gtsam::NonlinearFactor::shared_ptr(new This(*this)));
252  }
253 
255  virtual void print(const std::string& s = "",
256  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const {
257  Base::print(s);
258  std::cout << " EssentialMatrixFactor3 with rotation " << cRb_ << std::endl;
259  }
260 
261  /*
262  * Vector of errors returns 2D vector
263  * @param E essential matrix
264  * @param d inverse depth d
265  */
266  Vector evaluateError(const EssentialMatrix& E, const double& d,
267  boost::optional<Matrix&> DE = boost::none, boost::optional<Matrix&> Dd =
268  boost::none) const {
269  if (!DE) {
270  // Convert E from body to camera frame
271  EssentialMatrix cameraE = cRb_ * E;
272  // Evaluate error
273  return Base::evaluateError(cameraE, d, boost::none, Dd);
274  } else {
275  // Version with derivatives
276  Matrix D_e_cameraE, D_cameraE_E; // 2*5, 5*5
277  EssentialMatrix cameraE = E.rotate(cRb_, D_cameraE_E);
278  Vector e = Base::evaluateError(cameraE, d, D_e_cameraE, Dd);
279  *DE = D_e_cameraE * D_cameraE_E; // (2*5) * (5*5)
280  return e;
281  }
282  }
283 
284 };
285 // EssentialMatrixFactor3
286 
287 }// gtsam
288 
Nonlinear factor base class.
Definition: NonlinearFactor.h:52
virtual Vector evaluateError(const X &x, boost::optional< Matrix & > H=boost::none) const =0
Override this method to finish implementing a unary factor.
This is the base class for all factor types.
Definition: Factor.h:51
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, even if pc behind image plane.
Definition: CalibratedCamera.cpp:88
EssentialMatrixFactor2(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model)
Constructor.
Definition: EssentialMatrixFactor.h:108
EssentialMatrixFactor3(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const Rot3 &cRb, const SharedNoiseModel &model)
Constructor.
Definition: EssentialMatrixFactor.h:227
noiseModel::Base::shared_ptr SharedNoiseModel
Note, deliberately not in noiseModel namespace.
Definition: NoiseModel.h:1072
virtual double error(const Values &c) const
Calculate the error of the factor.
Definition: NonlinearFactor.cpp:97
EssentialMatrix rotate(const Rot3 &cRb, OptionalJacobian< 5, 5 > HE=boost::none, OptionalJacobian< 5, 3 > HR=boost::none) const
Given essential matrix E in camera frame B, convert to body frame C.
Definition: EssentialMatrix.cpp:73
virtual void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
print
Definition: EssentialMatrixFactor.h:255
Binary factor that optimizes for E and inverse depth d: assumes measurement in image 2 is perfect...
Definition: EssentialMatrixFactor.h:209
const Unit3 & direction() const
Direction.
Definition: EssentialMatrix.h:115
Definition: Point3.h:45
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:134
virtual void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
print
Definition: EssentialMatrixFactor.h:67
virtual void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
Print.
Definition: NonlinearFactor.cpp:63
EssentialMatrixFactor(Key key, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model, boost::shared_ptr< CALIBRATION > K)
Constructor.
Definition: EssentialMatrixFactor.h:52
virtual gtsam::NonlinearFactor::shared_ptr clone() const
Definition: EssentialMatrixFactor.h:249
Vector evaluateError(const EssentialMatrix &E, const double &d, boost::optional< Matrix & > DE=boost::none, boost::optional< Matrix & > Dd=boost::none) const
Override this method to finish implementing a binary factor.
Definition: EssentialMatrixFactor.h:151
Point3 point3(OptionalJacobian< 3, 2 > H=boost::none) const
Return unit-norm Point3.
Definition: Unit3.cpp:134
EssentialMatrixFactor(Key key, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model)
Constructor.
Definition: EssentialMatrixFactor.h:36
Vector evaluateError(const EssentialMatrix &E, const double &d, boost::optional< Matrix & > DE=boost::none, boost::optional< Matrix & > Dd=boost::none) const
Override this method to finish implementing a binary factor.
Definition: EssentialMatrixFactor.h:266
const Rot3 & rotation() const
Rotation.
Definition: EssentialMatrix.h:110
Definition: Point2.h:40
A convenient base class for creating your own NoiseModelFactor with 2 variables.
Definition: NonlinearFactor.h:345
An essential matrix is like a Pose3, except with translation up to scale It is named after the 3*3 ma...
Definition: EssentialMatrix.h:24
virtual gtsam::NonlinearFactor::shared_ptr clone() const
Definition: EssentialMatrixFactor.h:132
Vector evaluateError(const EssentialMatrix &E, boost::optional< Matrix & > H=boost::none) const
vector of errors returns 1D vector
Definition: EssentialMatrixFactor.h:76
virtual void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
print
Definition: EssentialMatrixFactor.h:138
Binary factor that optimizes for E and inverse depth d: assumes measurement in image 2 is perfect...
Definition: EssentialMatrixFactor.h:89
Definition: Rot3.h:56
EssentialMatrixFactor2(Key key1, Key key2, const Point2 &pA, const Point2 &pB, const SharedNoiseModel &model, boost::shared_ptr< CALIBRATION > K)
Constructor.
Definition: EssentialMatrixFactor.h:124
A convenient base class for creating your own NoiseModelFactor with 1 variable.
Definition: NonlinearFactor.h:276
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:242
Non-linear factor base classes.
A simple camera class with a Cal3_S2 calibration.
static Vector3 Homogeneous(const Point2 &p)
Static function to convert Point2 to homogeneous coordinates.
Definition: EssentialMatrix.h:38
virtual gtsam::NonlinearFactor::shared_ptr clone() const
Definition: EssentialMatrixFactor.h:61
double error(const Vector3 &vA, const Vector3 &vB, OptionalJacobian< 1, 5 > H=boost::none) const
epipolar error, algebraic
Definition: EssentialMatrix.cpp:104
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:57
Factor that evaluates epipolar error p&#39;Ep for given essential matrix.
Definition: EssentialMatrixFactor.h:20
Global functions in a separate testing namespace.
Definition: chartTesting.h:28
boost::function< std::string(Key)> KeyFormatter
Typedef for a function to format a key, i.e. to convert it to a string.
Definition: Key.h:33