gtsam  4.0.0
gtsam
SmartFactorBase.h
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2 
3  * GTSAM Copyright 2010, 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 
21 #pragma once
22 
23 #include <gtsam/slam/JacobianFactorQ.h>
24 #include <gtsam/slam/JacobianFactorSVD.h>
26 
30 
31 #include <boost/optional.hpp>
32 #include <boost/serialization/optional.hpp>
33 #include <boost/make_shared.hpp>
34 #include <vector>
35 
36 namespace gtsam {
37 
46 template<class CAMERA>
48 
49 private:
50  typedef NonlinearFactor Base;
52  typedef typename CAMERA::Measurement Z;
53 
54 public:
55 
56  static const int Dim = traits<CAMERA>::dimension;
57  static const int ZDim = traits<Z>::dimension;
58  typedef Eigen::Matrix<double, ZDim, Dim> MatrixZD; // F blocks (derivatives wrpt camera)
59 
60 protected:
67  SharedIsotropic noiseModel_;
68 
74  std::vector<Z> measured_;
75 
77  boost::optional<Pose3> body_P_sensor_;
78 
80  // Cache for Fblocks, to avoid a malloc ever time we re-linearize
81  mutable std::vector<MatrixZD> Fblocks;
82 
83 public:
84 
85  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
86 
88  typedef boost::shared_ptr<This> shared_ptr;
89 
92 
95 
97  SmartFactorBase(const SharedNoiseModel& sharedNoiseModel,
98  boost::optional<Pose3> body_P_sensor = boost::none,
99  size_t expectedNumberCameras = 10)
100  : body_P_sensor_(body_P_sensor), Fblocks(expectedNumberCameras) {
101 
102  if (!sharedNoiseModel)
103  throw std::runtime_error("SmartFactorBase: sharedNoiseModel is required");
104 
105  SharedIsotropic sharedIsotropic = boost::dynamic_pointer_cast<
106  noiseModel::Isotropic>(sharedNoiseModel);
107 
108  if (!sharedIsotropic)
109  throw std::runtime_error("SmartFactorBase: needs isotropic");
110 
111  noiseModel_ = sharedIsotropic;
112  }
113 
115  virtual ~SmartFactorBase() {
116  }
117 
124  void add(const Z& measured_i, const Key& cameraKey_i) {
125  this->measured_.push_back(measured_i);
126  this->keys_.push_back(cameraKey_i);
127  }
128 
132  void add(std::vector<Z>& measurements, std::vector<Key>& cameraKeys) {
133  for (size_t i = 0; i < measurements.size(); i++) {
134  this->measured_.push_back(measurements.at(i));
135  this->keys_.push_back(cameraKeys.at(i));
136  }
137  }
138 
143  template<class SFM_TRACK>
144  void add(const SFM_TRACK& trackToAdd) {
145  for (size_t k = 0; k < trackToAdd.number_measurements(); k++) {
146  this->measured_.push_back(trackToAdd.measurements[k].second);
147  this->keys_.push_back(trackToAdd.measurements[k].first);
148  }
149  }
150 
152  virtual size_t dim() const {
153  return ZDim * this->measured_.size();
154  }
155 
157  const std::vector<Z>& measured() const {
158  return measured_;
159  }
160 
162  virtual Cameras cameras(const Values& values) const {
163  Cameras cameras;
164  for(const Key& k: this->keys_)
165  cameras.push_back(values.at<CAMERA>(k));
166  return cameras;
167  }
168 
174  void print(const std::string& s = "", const KeyFormatter& keyFormatter =
175  DefaultKeyFormatter) const {
176  std::cout << s << "SmartFactorBase, z = \n";
177  for (size_t k = 0; k < measured_.size(); ++k) {
178  std::cout << "measurement, p = " << measured_[k] << "\t";
179  noiseModel_->print("noise model = ");
180  }
181  if(body_P_sensor_)
182  body_P_sensor_->print("body_P_sensor_:\n");
183  Base::print("", keyFormatter);
184  }
185 
187  virtual bool equals(const NonlinearFactor& p, double tol = 1e-9) const {
188  const This *e = dynamic_cast<const This*>(&p);
189 
190  bool areMeasurementsEqual = true;
191  for (size_t i = 0; i < measured_.size(); i++) {
192  if (traits<Z>::Equals(this->measured_.at(i), e->measured_.at(i), tol) == false)
193  areMeasurementsEqual = false;
194  break;
195  }
196  return e && Base::equals(p, tol) && areMeasurementsEqual;
197  }
198 
200  template<class POINT>
201  Vector unwhitenedError(const Cameras& cameras, const POINT& point,
202  boost::optional<typename Cameras::FBlocks&> Fs = boost::none, //
203  boost::optional<Matrix&> E = boost::none) const {
204  Vector ue = cameras.reprojectionError(point, measured_, Fs, E);
205  if(body_P_sensor_){
206  for(size_t i=0; i < Fs->size(); i++){
207  Pose3 w_Pose_body = (cameras[i].pose()).compose(body_P_sensor_->inverse());
208  Matrix J(6, 6);
209  Pose3 world_P_body = w_Pose_body.compose(*body_P_sensor_, J);
210  Fs->at(i) = Fs->at(i) * J;
211  }
212  }
213  return ue;
214  }
215 
220  template<class POINT>
221  Vector whitenedError(const Cameras& cameras, const POINT& point) const {
222  Vector e = cameras.reprojectionError(point, measured_);
223  if (noiseModel_)
224  noiseModel_->whitenInPlace(e);
225  return e;
226  }
227 
234  template<class POINT>
235  double totalReprojectionError(const Cameras& cameras,
236  const POINT& point) const {
237  Vector e = whitenedError(cameras, point);
238  return 0.5 * e.dot(e);
239  }
240 
242  static Matrix PointCov(Matrix& E) {
243  return (E.transpose() * E).inverse();
244  }
245 
252  template<class POINT>
253  void computeJacobians(std::vector<MatrixZD>& Fblocks, Matrix& E, Vector& b,
254  const Cameras& cameras, const POINT& point) const {
255  // Project into Camera set and calculate derivatives
256  // As in expressionFactor, RHS vector b = - (h(x_bar) - z) = z-h(x_bar)
257  // Indeed, nonlinear error |h(x_bar+dx)-z| ~ |h(x_bar) + A*dx - z|
258  // = |A*dx - (z-h(x_bar))|
259  b = -unwhitenedError(cameras, point, Fblocks, E);
260  }
261 
263  template<class POINT>
264  void computeJacobiansSVD(std::vector<MatrixZD>& Fblocks, Matrix& Enull,
265  Vector& b, const Cameras& cameras, const POINT& point) const {
266 
267  Matrix E;
268  computeJacobians(Fblocks, E, b, cameras, point);
269 
270  static const int N = FixedDimension<POINT>::value; // 2 (Unit3) or 3 (Point3)
271 
272  // Do SVD on A
273  Eigen::JacobiSVD<Matrix> svd(E, Eigen::ComputeFullU);
274  Vector s = svd.singularValues();
275  size_t m = this->keys_.size();
276  Enull = svd.matrixU().block(0, N, ZDim * m, ZDim * m - N); // last ZDim*m-N columns
277  }
278 
280  boost::shared_ptr<RegularHessianFactor<Dim> > createHessianFactor(
281  const Cameras& cameras, const Point3& point, const double lambda = 0.0,
282  bool diagonalDamping = false) const {
283 
284  Matrix E;
285  Vector b;
286  computeJacobians(Fblocks, E, b, cameras, point);
287 
288  // build augmented hessian
289  SymmetricBlockMatrix augmentedHessian = Cameras::SchurComplement(Fblocks, E, b);
290 
291  return boost::make_shared<RegularHessianFactor<Dim> >(keys_,
292  augmentedHessian);
293  }
294 
300  void updateAugmentedHessian(const Cameras& cameras, const Point3& point,
301  const double lambda, bool diagonalDamping,
302  SymmetricBlockMatrix& augmentedHessian,
303  const FastVector<Key> allKeys) const {
304  Matrix E;
305  Vector b;
306  computeJacobians(Fblocks, E, b, cameras, point);
307  Cameras::UpdateSchurComplement(Fblocks, E, b, allKeys, keys_, augmentedHessian);
308  }
309 
311  void whitenJacobians(std::vector<MatrixZD>& F, Matrix& E, Vector& b) const {
312  noiseModel_->WhitenSystem(E, b);
313  // TODO make WhitenInPlace work with any dense matrix type
314  for (size_t i = 0; i < F.size(); i++)
315  F[i] = noiseModel_->Whiten(F[i]);
316  }
317 
319  boost::shared_ptr<RegularImplicitSchurFactor<CAMERA> > //
320  createRegularImplicitSchurFactor(const Cameras& cameras, const Point3& point,
321  double lambda = 0.0, bool diagonalDamping = false) const {
322  Matrix E;
323  Vector b;
324  std::vector<MatrixZD> F;
325  computeJacobians(F, E, b, cameras, point);
326  whitenJacobians(F, E, b);
327  Matrix P = Cameras::PointCov(E, lambda, diagonalDamping);
328  return boost::make_shared<RegularImplicitSchurFactor<CAMERA> >(keys_, F, E,
329  P, b);
330  }
331 
335  boost::shared_ptr<JacobianFactorQ<Dim, ZDim> > createJacobianQFactor(
336  const Cameras& cameras, const Point3& point, double lambda = 0.0,
337  bool diagonalDamping = false) const {
338  Matrix E;
339  Vector b;
340  std::vector<MatrixZD> F;
341  computeJacobians(F, E, b, cameras, point);
342  const size_t M = b.size();
343  Matrix P = Cameras::PointCov(E, lambda, diagonalDamping);
344  SharedIsotropic n = noiseModel::Isotropic::Sigma(M, noiseModel_->sigma());
345  return boost::make_shared<JacobianFactorQ<Dim, ZDim> >(keys_, F, E, P, b, n);
346  }
347 
352  boost::shared_ptr<JacobianFactor> createJacobianSVDFactor(
353  const Cameras& cameras, const Point3& point, double lambda = 0.0) const {
354  size_t m = this->keys_.size();
355  std::vector<MatrixZD> F;
356  Vector b;
357  const size_t M = ZDim * m;
358  Matrix E0(M, M - 3);
359  computeJacobiansSVD(F, E0, b, cameras, point);
360  SharedIsotropic n = noiseModel::Isotropic::Sigma(M - 3,
361  noiseModel_->sigma());
362  return boost::make_shared<JacobianFactorSVD<Dim, ZDim> >(keys_, F, E0, b, n);
363  }
364 
366  static void FillDiagonalF(const std::vector<MatrixZD>& Fblocks, Matrix& F) {
367  size_t m = Fblocks.size();
368  F.resize(ZDim * m, Dim * m);
369  F.setZero();
370  for (size_t i = 0; i < m; ++i)
371  F.block<ZDim, Dim>(ZDim * i, Dim * i) = Fblocks.at(i);
372  }
373 
374 
375  Pose3 body_P_sensor() const{
376  if(body_P_sensor_)
377  return *body_P_sensor_;
378  else
379  return Pose3(); // if unspecified, the transformation is the identity
380  }
381 
382 private:
383 
385  friend class boost::serialization::access;
386  template<class ARCHIVE>
387  void serialize(ARCHIVE & ar, const unsigned int /*version*/) {
388  ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
389  ar & BOOST_SERIALIZATION_NVP(noiseModel_);
390  ar & BOOST_SERIALIZATION_NVP(measured_);
391  ar & BOOST_SERIALIZATION_NVP(body_P_sensor_);
392  }
393 };
394 // end class SmartFactorBase
395 
396 // Definitions need to avoid link errors (above are only declarations)
397 template<class CAMERA> const int SmartFactorBase<CAMERA>::Dim;
398 template<class CAMERA> const int SmartFactorBase<CAMERA>::ZDim;
399 
400 } // \ namespace gtsam
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
print
Definition: SmartFactorBase.h:174
Nonlinear factor base class.
Definition: NonlinearFactor.h:52
Base class to create smart factors on poses or cameras.
void svd(const Matrix &A, Matrix &U, Vector &S, Matrix &V)
SVD computes economy SVD A=U*S*V&#39;.
Definition: Matrix.cpp:554
This is the base class for all factor types.
Definition: Factor.h:51
virtual Cameras cameras(const Values &values) const
Collect all cameras: important that in key order.
Definition: SmartFactorBase.h:162
noiseModel::Base::shared_ptr SharedNoiseModel
Note, deliberately not in noiseModel namespace.
Definition: NoiseModel.h:1072
void computeJacobiansSVD(std::vector< MatrixZD > &Fblocks, Matrix &Enull, Vector &b, const Cameras &cameras, const POINT &point) const
SVD version.
Definition: SmartFactorBase.h:264
static SymmetricBlockMatrix SchurComplement(const FBlocks &Fs, const Matrix &E, const Eigen::Matrix< double, N, N > &P, const Vector &b)
Do Schur complement, given Jacobian as Fs,E,P, return SymmetricBlockMatrix G = F&#39; * F - F&#39; * E * P * ...
Definition: CameraSet.h:143
Vector reprojectionError(const POINT &point, const std::vector< Z > &measured, boost::optional< FBlocks & > Fs=boost::none, boost::optional< Matrix & > E=boost::none) const
Calculate vector [project2(point)-z] of re-projection errors.
Definition: CameraSet.h:130
An isotropic noise model corresponds to a scaled diagonal covariance To construct, use one of the static methods.
Definition: NoiseModel.h:519
static shared_ptr Sigma(size_t dim, double sigma, bool smart=true)
An isotropic noise model created by specifying a standard devation sigma.
Definition: NoiseModel.cpp:561
boost::shared_ptr< RegularHessianFactor< Dim > > createHessianFactor(const Cameras &cameras, const Point3 &point, const double lambda=0.0, bool diagonalDamping=false) const
Linearize to a Hessianfactor.
Definition: SmartFactorBase.h:280
Definition: Pose3.h:37
HessianFactor class with constant sized blocks.
double totalReprojectionError(const Cameras &cameras, const POINT &point) const
Calculate the error of the factor.
Definition: SmartFactorBase.h:235
Definition: Point3.h:45
Base class for smart factors This base class has no internal point, but it has a measurement, noise model and an optional sensor pose.
Definition: SmartFactorBase.h:47
boost::optional< Pose3 > body_P_sensor_
Pose of the camera in the body frame.
Definition: SmartFactorBase.h:77
A non-templated config holding any types of Manifold-group elements.
Definition: Values.h:70
Definition: SymmetricBlockMatrix.h:51
void add(const Z &measured_i, const Key &cameraKey_i)
Add a new measurement and pose key.
Definition: SmartFactorBase.h:124
void computeJacobians(std::vector< MatrixZD > &Fblocks, Matrix &E, Vector &b, const Cameras &cameras, const POINT &point) const
Compute F, E, and b (called below in both vanilla and SVD versions), where F is a vector of derivativ...
Definition: SmartFactorBase.h:253
boost::shared_ptr< JacobianFactorQ< Dim, ZDim > > createJacobianQFactor(const Cameras &cameras, const Point3 &point, double lambda=0.0, bool diagonalDamping=false) const
Return Jacobians as JacobianFactorQ.
Definition: SmartFactorBase.h:335
static Matrix PointCov(Matrix &E)
Computes Point Covariance P from E.
Definition: SmartFactorBase.h:242
std::vector< Z > measured_
2D measurement and noise model for each of the m views We keep a copy of measurements for I/O and com...
Definition: SmartFactorBase.h:74
Vector unwhitenedError(const Cameras &cameras, const POINT &point, boost::optional< typename Cameras::FBlocks & > Fs=boost::none, boost::optional< Matrix & > E=boost::none) const
Compute reprojection errors [h(x)-z] = [cameras.project(p)-z] and derivatives.
Definition: SmartFactorBase.h:201
virtual ~SmartFactorBase()
Virtual destructor, subclasses from NonlinearFactor.
Definition: SmartFactorBase.h:115
boost::shared_ptr< JacobianFactor > createJacobianSVDFactor(const Cameras &cameras, const Point3 &point, double lambda=0.0) const
Return Jacobians as JacobianFactorSVD TODO lambda is currently ignored.
Definition: SmartFactorBase.h:352
void add(std::vector< Z > &measurements, std::vector< Key > &cameraKeys)
Add a bunch of measurements, together with the camera keys.
Definition: SmartFactorBase.h:132
Vector whitenedError(const Cameras &cameras, const POINT &point) const
Calculate vector of re-projection errors [h(x)-z] = [cameras.project(p) - z] Noise model applied...
Definition: SmartFactorBase.h:221
void updateAugmentedHessian(const Cameras &cameras, const Point3 &point, const double lambda, bool diagonalDamping, SymmetricBlockMatrix &augmentedHessian, const FastVector< Key > allKeys) const
Add the contribution of the smart factor to a pre-allocated Hessian, using sparse linear algebra...
Definition: SmartFactorBase.h:300
virtual bool equals(const NonlinearFactor &p, double tol=1e-9) const
equals
Definition: SmartFactorBase.h:187
SmartFactorBase(const SharedNoiseModel &sharedNoiseModel, boost::optional< Pose3 > body_P_sensor=boost::none, size_t expectedNumberCameras=10)
Constructor.
Definition: SmartFactorBase.h:97
virtual void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const
print
Definition: NonlinearFactor.cpp:26
virtual size_t dim() const
get the dimension (number of rows!) of the factor
Definition: SmartFactorBase.h:152
A set of cameras, all with their own calibration.
Definition: CameraSet.h:34
void whitenJacobians(std::vector< MatrixZD > &F, Matrix &E, Vector &b) const
Whiten the Jacobians computed by computeJacobians using noiseModel_.
Definition: SmartFactorBase.h:311
static void FillDiagonalF(const std::vector< MatrixZD > &Fblocks, Matrix &F)
Create BIG block-diagonal matrix F from Fblocks.
Definition: SmartFactorBase.h:366
FastVector< Key > keys_
The keys involved in this factor.
Definition: Factor.h:69
SharedIsotropic noiseModel_
As of Feb 22, 2015, the noise model is the same for all measurements and is isotropic.
Definition: SmartFactorBase.h:67
static void UpdateSchurComplement(const FBlocks &Fs, const Matrix &E, const Eigen::Matrix< double, N, N > &P, const Vector &b, const FastVector< Key > &allKeys, const FastVector< Key > &keys, SymmetricBlockMatrix &augmentedHessian)
Applies Schur complement (exploiting block structure) to get a smart factor on cameras, and adds the contribution of the smart factor to a pre-allocated augmented Hessian.
Definition: CameraSet.h:240
ValueType at(Key j) const
Retrieve a variable by key j.
Definition: Values-inl.h:343
EIGEN_MAKE_ALIGNED_OPERATOR_NEW typedef boost::shared_ptr< This > shared_ptr
shorthand for a smart pointer to a factor
Definition: SmartFactorBase.h:88
virtual bool equals(const NonlinearFactor &f, double tol=1e-9) const
Check if two factors are equal.
Definition: NonlinearFactor.cpp:36
A manifold defines a space in which there is a notion of a linear tangent space that can be centered ...
Definition: concepts.h:30
void add(const SFM_TRACK &trackToAdd)
Adds an entire SfM_track (collection of cameras observing a single point).
Definition: SmartFactorBase.h:144
Give fixed size dimension of a type, fails at compile time if dynamic.
Definition: Manifold.h:164
SmartFactorBase()
Default Constructor, for serialization.
Definition: SmartFactorBase.h:94
static const int ZDim
Measurement dimension.
Definition: SmartFactorBase.h:57
static const int Dim
Camera dimension.
Definition: SmartFactorBase.h:56
static Matrix PointCov(const Matrix &E, const double lambda=0.0, bool diagonalDamping=false)
Computes Point Covariance P, with lambda parameter, dynamic version.
Definition: CameraSet.h:204
Non-linear factor base classes.
const std::vector< Z > & measured() const
return the measurements
Definition: SmartFactorBase.h:157
boost::shared_ptr< RegularImplicitSchurFactor< CAMERA > > createRegularImplicitSchurFactor(const Cameras &cameras, const Point3 &point, double lambda=0.0, bool diagonalDamping=false) const
Return Jacobians as RegularImplicitSchurFactor with raw access.
Definition: SmartFactorBase.h:320
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:57
A new type of linear factor (GaussianFactor), which is subclass of GaussianFactor.
CameraSet< CAMERA > Cameras
We use the new CameraSte data structure to refer to a set of cameras.
Definition: SmartFactorBase.h:91
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