GTSAM  4.0.2
C++ library for smoothing and mapping (SAM)
SmartProjectionRigFactor.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 
25 #pragma once
26 
28 
29 namespace gtsam {
51 template <class CAMERA>
53  private:
56  typedef typename CAMERA::CalibrationType CALIBRATION;
57  typedef typename CAMERA::Measurement MEASUREMENT;
58  typedef typename CAMERA::MeasurementVector MEASUREMENTS;
59 
60  static const int DimPose = 6;
61  static const int ZDim = 2;
62 
63  protected:
66 
68  std::shared_ptr<typename Base::Cameras> cameraRig_;
69 
73 
74  public:
75  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
76 
77  typedef CAMERA Camera;
78  typedef CameraSet<CAMERA> Cameras;
79 
81  typedef std::shared_ptr<This> shared_ptr;
82 
85 
95  const SharedNoiseModel& sharedNoiseModel,
96  const std::shared_ptr<Cameras>& cameraRig,
98  : Base(sharedNoiseModel, params), cameraRig_(cameraRig) {
99  // throw exception if configuration is not supported by this factor
100  if (Base::params_.degeneracyMode != gtsam::ZERO_ON_DEGENERACY)
101  throw std::runtime_error(
102  "SmartProjectionRigFactor: "
103  "degeneracyMode must be set to ZERO_ON_DEGENERACY");
104  if (Base::params_.linearizationMode != gtsam::HESSIAN)
105  throw std::runtime_error(
106  "SmartProjectionRigFactor: "
107  "linearizationMode must be set to HESSIAN");
108  }
109 
120  void add(const MEASUREMENT& measured, const Key& poseKey,
121  const size_t& cameraId = 0) {
122  // store measurement and key
123  this->measured_.push_back(measured);
124  this->nonUniqueKeys_.push_back(poseKey);
125 
126  // also store keys in the keys_ vector: these keys are assumed to be
127  // unique, so we avoid duplicates here
128  if (std::find(this->keys_.begin(), this->keys_.end(), poseKey) ==
129  this->keys_.end())
130  this->keys_.push_back(poseKey); // add only unique keys
131 
132  // store id of the camera taking the measurement
133  cameraIds_.push_back(cameraId);
134  }
135 
146  void add(const MEASUREMENTS& measurements, const KeyVector& poseKeys,
148  if (poseKeys.size() != measurements.size() ||
149  (poseKeys.size() != cameraIds.size() && cameraIds.size() != 0)) {
150  throw std::runtime_error(
151  "SmartProjectionRigFactor: "
152  "trying to add inconsistent inputs");
153  }
154  if (cameraIds.size() == 0 && cameraRig_->size() > 1) {
155  throw std::runtime_error(
156  "SmartProjectionRigFactor: "
157  "camera rig includes multiple camera "
158  "but add did not input cameraIds");
159  }
160  for (size_t i = 0; i < measurements.size(); i++) {
161  add(measurements[i], poseKeys[i],
162  cameraIds.size() == 0 ? 0 : cameraIds[i]);
163  }
164  }
165 
168  const KeyVector& nonUniqueKeys() const { return nonUniqueKeys_; }
169 
171  const std::shared_ptr<Cameras>& cameraRig() const { return cameraRig_; }
172 
174  const FastVector<size_t>& cameraIds() const { return cameraIds_; }
175 
181  void print(
182  const std::string& s = "",
183  const KeyFormatter& keyFormatter = DefaultKeyFormatter) const override {
184  std::cout << s << "SmartProjectionRigFactor: \n ";
185  for (size_t i = 0; i < nonUniqueKeys_.size(); i++) {
186  std::cout << "-- Measurement nr " << i << std::endl;
187  std::cout << "key: " << keyFormatter(nonUniqueKeys_[i]) << std::endl;
188  std::cout << "cameraId: " << cameraIds_[i] << std::endl;
189  (*cameraRig_)[cameraIds_[i]].print("camera in rig:\n");
190  }
191  Base::print("", keyFormatter);
192  }
193 
195  bool equals(const NonlinearFactor& p, double tol = 1e-9) const override {
196  const This* e = dynamic_cast<const This*>(&p);
197  return e && Base::equals(p, tol) && nonUniqueKeys_ == e->nonUniqueKeys() &&
198  cameraRig_->equals(*(e->cameraRig())) &&
199  std::equal(cameraIds_.begin(), cameraIds_.end(),
200  e->cameraIds().begin());
201  }
202 
209  typename Base::Cameras cameras(const Values& values) const override {
210  typename Base::Cameras cameras;
211  cameras.reserve(nonUniqueKeys_.size()); // preallocate
212  for (size_t i = 0; i < nonUniqueKeys_.size(); i++) {
213  const typename Base::Camera& camera_i = (*cameraRig_)[cameraIds_[i]];
214  const Pose3 world_P_sensor_i =
215  values.at<Pose3>(nonUniqueKeys_[i]) // = world_P_body
216  * camera_i.pose(); // = body_P_cam_i
217  cameras.emplace_back(world_P_sensor_i,
218  make_shared<typename CAMERA::CalibrationType>(
219  camera_i.calibration()));
220  }
221  return cameras;
222  }
223 
227  double error(const Values& values) const override {
228  if (this->active(values)) {
229  return this->totalReprojectionError(this->cameras(values));
230  } else { // else of active flag
231  return 0.0;
232  }
233  }
234 
244  void computeJacobiansWithTriangulatedPoint(typename Base::FBlocks& Fs,
245  Matrix& E, Vector& b,
246  const Cameras& cameras) const {
247  if (!this->result_) {
248  throw("computeJacobiansWithTriangulatedPoint");
249  } else { // valid result: compute jacobians
250  b = -cameras.reprojectionError(*this->result_, this->measured_, Fs, E);
251  for (size_t i = 0; i < Fs.size(); i++) {
252  const Pose3& body_P_sensor = (*cameraRig_)[cameraIds_[i]].pose();
253  const Pose3 world_P_body = cameras[i].pose() * body_P_sensor.inverse();
254  Eigen::Matrix<double, DimPose, DimPose> H;
255  world_P_body.compose(body_P_sensor, H);
256  Fs.at(i) = Fs.at(i) * H;
257  }
258  }
259  }
260 
262  std::shared_ptr<RegularHessianFactor<DimPose> > createHessianFactor(
263  const Values& values, const double& lambda = 0.0,
264  bool diagonalDamping = false) const {
265  // we may have multiple observation sharing the same keys (e.g., 2 cameras
266  // measuring from the same body pose), hence the number of unique keys may
267  // be smaller than nrMeasurements
268  size_t nrUniqueKeys =
269  this->keys_
270  .size(); // note: by construction, keys_ only contains unique keys
271 
272  Cameras cameras = this->cameras(values);
273 
274  // Create structures for Hessian Factors
275  std::vector<size_t> js;
276  std::vector<Matrix> Gs(nrUniqueKeys * (nrUniqueKeys + 1) / 2);
277  std::vector<Vector> gs(nrUniqueKeys);
278 
279  if (this->measured_.size() != cameras.size()) // 1 observation per camera
280  throw std::runtime_error(
281  "SmartProjectionRigFactor: "
282  "measured_.size() inconsistent with input");
283 
284  // triangulate 3D point at given linearization point
285  this->triangulateSafe(cameras);
286 
287  if (!this->result_) { // failed: return "empty/zero" Hessian
288  if (this->params_.degeneracyMode == ZERO_ON_DEGENERACY) {
289  for (Matrix& m : Gs) m = Matrix::Zero(DimPose, DimPose);
290  for (Vector& v : gs) v = Vector::Zero(DimPose);
291  return std::make_shared<RegularHessianFactor<DimPose> >(this->keys_,
292  Gs, gs, 0.0);
293  } else {
294  throw std::runtime_error(
295  "SmartProjectionRigFactor: "
296  "only supported degeneracy mode is ZERO_ON_DEGENERACY");
297  }
298  }
299 
300  // compute Jacobian given triangulated 3D Point
301  typename Base::FBlocks Fs;
302  Matrix E;
303  Vector b;
304  this->computeJacobiansWithTriangulatedPoint(Fs, E, b, cameras);
305 
306  // Whiten using noise model
307  this->noiseModel_->WhitenSystem(E, b);
308  for (size_t i = 0; i < Fs.size(); i++) {
309  Fs[i] = this->noiseModel_->Whiten(Fs[i]);
310  }
311 
312  const Matrix3 P = Base::Cameras::PointCov(E, lambda, diagonalDamping);
313 
314  // Build augmented Hessian (with last row/column being the information
315  // vector) Note: we need to get the augumented hessian wrt the unique keys
316  // in key_
317  SymmetricBlockMatrix augmentedHessianUniqueKeys =
318  Base::Cameras::template SchurComplementAndRearrangeBlocks<3, 6, 6>(
319  Fs, E, P, b, nonUniqueKeys_, this->keys_);
320 
321  return std::make_shared<RegularHessianFactor<DimPose> >(
322  this->keys_, augmentedHessianUniqueKeys);
323  }
324 
332  std::shared_ptr<GaussianFactor> linearizeDamped(
333  const Values& values, const double& lambda = 0.0) const {
334  // depending on flag set on construction we may linearize to different
335  // linear factors
336  switch (this->params_.linearizationMode) {
337  case HESSIAN:
338  return this->createHessianFactor(values, lambda);
339  default:
340  throw std::runtime_error(
341  "SmartProjectionRigFactor: unknown linearization mode");
342  }
343  }
344 
346  std::shared_ptr<GaussianFactor> linearize(
347  const Values& values) const override {
348  return this->linearizeDamped(values);
349  }
350 
351  private:
352 #ifdef GTSAM_ENABLE_BOOST_SERIALIZATION
353  friend class boost::serialization::access;
355  template <class ARCHIVE>
356  void serialize(ARCHIVE& ar, const unsigned int /*version*/) {
357  ar& BOOST_SERIALIZATION_BASE_OBJECT_NVP(Base);
358  // ar& BOOST_SERIALIZATION_NVP(nonUniqueKeys_);
359  // ar& BOOST_SERIALIZATION_NVP(cameraRig_);
360  // ar& BOOST_SERIALIZATION_NVP(cameraIds_);
361  }
362 #endif
363 };
364 // end of class declaration
365 
367 template <class CAMERA>
369  : public Testable<SmartProjectionRigFactor<CAMERA> > {};
370 
371 } // namespace gtsam
Definition: SmartFactorParams.h:42
bool equals(const NonlinearFactor &p, double tol=1e-9) const override
equals
Definition: SmartProjectionRigFactor.h:195
std::string serialize(const T &input)
serializes to a string
Definition: serialization.h:113
const ValueType at(Key j) const
Definition: Values-inl.h:204
DegeneracyMode degeneracyMode
How to linearize the factor.
Definition: SmartFactorParams.h:45
Definition: Factor.h:69
Definition: SmartProjectionFactor.h:44
Definition: Testable.h:152
const std::shared_ptr< Cameras > & cameraRig() const
return the calibration object
Definition: SmartProjectionRigFactor.h:171
std::vector< T, typename internal::FastDefaultVectorAllocator< T >::type > FastVector
Definition: FastVector.h:34
TriangulationResult result_
result from triangulateSafe
Definition: SmartProjectionFactor.h:62
Vector reprojectionError(const POINT &point, const ZVector &measured, FBlocks *Fs=nullptr, Matrix *E=nullptr) const
Calculate vector [project2(point)-z] of re-projection errors.
Definition: CameraSet.h:146
Definition: Group.h:43
Definition: NonlinearFactor.h:68
KeyVector keys_
The keys involved in this factor.
Definition: Factor.h:87
std::shared_ptr< RegularHessianFactor< DimPose > > createHessianFactor(const Values &values, const double &lambda=0.0, bool diagonalDamping=false) const
linearize and return a Hessianfactor that is an approximation of error(p)
Definition: SmartProjectionRigFactor.h:262
const KeyVector & nonUniqueKeys() const
Definition: SmartProjectionRigFactor.h:168
SharedIsotropic noiseModel_
Definition: SmartFactorBase.h:73
std::shared_ptr< typename Base::Cameras > cameraRig_
cameras in the rig (fixed poses wrt body and intrinsics, for each camera)
Definition: SmartProjectionRigFactor.h:68
A set of cameras, all with their own calibration.
Definition: CameraSet.h:36
void add(const MEASUREMENTS &measurements, const KeyVector &poseKeys, const FastVector< size_t > &cameraIds=FastVector< size_t >())
Definition: SmartProjectionRigFactor.h:146
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
Definition: SmartProjectionRigFactor.h:181
Definition: SymmetricBlockMatrix.h:53
Smart factor on cameras (pose + calibration)
void add(const MEASUREMENT &measured, const Key &poseKey, const size_t &cameraId=0)
Definition: SmartProjectionRigFactor.h:120
ZVector measured_
Definition: SmartFactorBase.h:80
KeyVector nonUniqueKeys_
vector of keys (one for each observation) with potentially repeated keys
Definition: SmartProjectionRigFactor.h:65
TriangulationResult triangulateSafe(const Cameras &cameras) const
Call gtsam::triangulateSafe iff we need to re-triangulate.
Definition: SmartProjectionFactor.h:173
Base::Cameras cameras(const Values &values) const override
Definition: SmartProjectionRigFactor.h:209
std::shared_ptr< This > shared_ptr
shorthand for a smart pointer to a factor
Definition: SmartProjectionRigFactor.h:81
LinearizationMode linearizationMode
How to linearize the factor.
Definition: SmartFactorParams.h:44
SmartProjectionRigFactor()
Default constructor, only for serialization.
Definition: SmartProjectionRigFactor.h:84
FastVector< size_t > cameraIds_
Definition: SmartProjectionRigFactor.h:72
Pose3 inverse() const
inverse transformation with derivatives
Definition: Values.h:65
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
double error(const Values &values) const override
Definition: SmartProjectionRigFactor.h:227
SmartProjectionRigFactor(const SharedNoiseModel &sharedNoiseModel, const std::shared_ptr< Cameras > &cameraRig, const SmartProjectionParams &params=SmartProjectionParams())
Definition: SmartProjectionRigFactor.h:94
const ZVector & measured() const
Return the 2D measurements (ZDim, in general).
Definition: SmartFactorBase.h:160
Definition: chartTesting.h:28
bool equals(const NonlinearFactor &p, double tol=1e-9) const override
equals
Definition: SmartProjectionFactor.h:114
FastVector< Key > KeyVector
Define collection type once and for all - also used in wrappers.
Definition: Key.h:86
virtual bool active(const Values &) const
Definition: NonlinearFactor.h:141
std::shared_ptr< GaussianFactor > linearizeDamped(const Values &values, const double &lambda=0.0) const
Definition: SmartProjectionRigFactor.h:332
CAMERA Camera
shorthand for a set of cameras
Definition: SmartProjectionFactor.h:73
Definition: SmartProjectionRigFactor.h:52
const_iterator begin() const
Definition: Factor.h:145
const FastVector< size_t > & cameraIds() const
return the calibration object
Definition: SmartProjectionRigFactor.h:174
bool equal(const T &obj1, const T &obj2, double tol)
Definition: Testable.h:85
Definition: Pose3.h:37
std::uint64_t Key
Integer nonlinear key type.
Definition: types.h:102
void print(const std::string &s="", const KeyFormatter &keyFormatter=DefaultKeyFormatter) const override
Definition: SmartProjectionFactor.h:102
void computeJacobiansWithTriangulatedPoint(typename Base::FBlocks &Fs, Matrix &E, Vector &b, const Cameras &cameras) const
Definition: SmartProjectionRigFactor.h:244
std::shared_ptr< GaussianFactor > linearize(const Values &values) const override
linearize
Definition: SmartProjectionRigFactor.h:346
noiseModel::Base::shared_ptr SharedNoiseModel
Definition: NoiseModel.h:741
double totalReprojectionError(const Cameras &cameras, std::optional< Point3 > externalPoint={}) const
Definition: SmartProjectionFactor.h:411
bool equals(const This &other, double tol=1e-9) const
check equality