g2o
types_icp.h
Go to the documentation of this file.
1 // g2o - General Graph Optimization
2 // Copyright (C) 2011 Kurt Konolige
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright notice,
10 // this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
18 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 
27 #ifndef G2O_TYPES_ICP
28 #define G2O_TYPES_ICP
29 
30 #define GICP_ANALYTIC_JACOBIANS
31 //#define SCAM_ANALYTIC_JACOBIANS
32 
33 #include "g2o/core/base_vertex.h"
38 #include "g2o_types_icp_api.h"
39 
40 #include <Eigen/Geometry>
41 #include <iostream>
42 
43 namespace g2o {
44 
45  namespace types_icp {
46  void init();
47  }
48 
49  typedef Eigen::Matrix<double, 6, 1, Eigen::ColMajor> Vector6d;
50 
51 //
52 // GICP-type edges
53 // Each measurement is between two rigid points on each 6DOF vertex
54 //
55 
56  //
57  // class for edges between two points rigidly attached to vertices
58  //
59 
61  {
63 
64  public:
65  // point positions
66  Vector3D pos0, pos1;
67 
68  // unit normals
69  Vector3D normal0, normal1;
70 
71  // rotation matrix for normal
73 
74  // initialize an object
76  {
77  pos0.setZero();
78  pos1.setZero();
79  normal0 << 0, 0, 1;
80  normal1 << 0, 0, 1;
81  //makeRot();
82  R0.setIdentity();
83  R1.setIdentity();
84  }
85 
86  // set up rotation matrix for pos0
87  void makeRot0()
88  {
89  Vector3D y;
90  y << 0, 1, 0;
91  R0.row(2) = normal0;
92  y = y - normal0(1)*normal0;
93  y.normalize(); // need to check if y is close to 0
94  R0.row(1) = y;
95  R0.row(0) = normal0.cross(R0.row(1));
96  // cout << normal.transpose() << endl;
97  // cout << R0 << endl << endl;
98  // cout << R0*R0.transpose() << endl << endl;
99  }
100 
101  // set up rotation matrix for pos1
102  void makeRot1()
103  {
104  Vector3D y;
105  y << 0, 1, 0;
106  R1.row(2) = normal1;
107  y = y - normal1(1)*normal1;
108  y.normalize(); // need to check if y is close to 0
109  R1.row(1) = y;
110  R1.row(0) = normal1.cross(R1.row(1));
111  }
112 
113  // returns a precision matrix for point-plane
114  Matrix3D prec0(double e)
115  {
116  makeRot0();
117  Matrix3D prec;
118  prec << e, 0, 0,
119  0, e, 0,
120  0, 0, 1;
121  return R0.transpose()*prec*R0;
122  }
123 
124  // returns a precision matrix for point-plane
125  Matrix3D prec1(double e)
126  {
127  makeRot1();
128  Matrix3D prec;
129  prec << e, 0, 0,
130  0, e, 0,
131  0, 0, 1;
132  return R1.transpose()*prec*R1;
133  }
134 
135  // return a covariance matrix for plane-plane
136  Matrix3D cov0(double e)
137  {
138  makeRot0();
139  Matrix3D cov;
140  cov << 1, 0, 0,
141  0, 1, 0,
142  0, 0, e;
143  return R0.transpose()*cov*R0;
144  }
145 
146  // return a covariance matrix for plane-plane
147  Matrix3D cov1(double e)
148  {
149  makeRot1();
150  Matrix3D cov;
151  cov << 1, 0, 0,
152  0, 1, 0,
153  0, 0, e;
154  return R1.transpose()*cov*R1;
155  }
156 
157  };
158 
159 
160  // 3D rigid constraint
161  // 3 values for position wrt frame
162  // 3 values for normal wrt frame, not used here
163  // first two args are the measurement type, second two the connection classes
164  class G2O_TYPES_ICP_API Edge_V_V_GICP : public BaseBinaryEdge<3, EdgeGICP, VertexSE3, VertexSE3>
165  {
166  public:
168  Edge_V_V_GICP() : pl_pl(false) {}
169  Edge_V_V_GICP(const Edge_V_V_GICP* e);
170 
171  // switch to go between point-plane and plane-plane
172  bool pl_pl;
173  Matrix3D cov0, cov1;
174 
175  // I/O functions
176  virtual bool read(std::istream& is);
177  virtual bool write(std::ostream& os) const;
178 
179  // return the error estimate as a 3-vector
181  {
182  // from <ViewPoint> to <Point>
183  const VertexSE3 *vp0 = static_cast<const VertexSE3*>(_vertices[0]);
184  const VertexSE3 *vp1 = static_cast<const VertexSE3*>(_vertices[1]);
185 
186  // get vp1 point into vp0 frame
187  // could be more efficient if we computed this transform just once
188  Vector3D p1;
189 
190 #if 0
191  if (_cnum >= 0 && 0) // using global cache
192  {
193  if (_tainted[_cnum]) // set up transform
194  {
195  _transforms[_cnum] = vp0->estimate().inverse() * vp1->estimate();
196  _tainted[_cnum] = 0;
197  cout << _transforms[_cnum] << endl;
198  }
199  p1 = _transforms[_cnum].map(measurement().pos1); // do the transform
200  }
201  else
202 #endif
203  {
204  p1 = vp1->estimate() * measurement().pos1;
205  p1 = vp0->estimate().inverse() * p1;
206  }
207 
208  // cout << endl << "Error computation; points are: " << endl;
209  // cout << p0.transpose() << endl;
210  // cout << p1.transpose() << endl;
211 
212  // get their difference
213  // this is simple Euclidean distance, for now
214  _error = p1 - measurement().pos0;
215 
216 #if 0
217  cout << "vp0" << endl << vp0->estimate() << endl;
218  cout << "vp1" << endl << vp1->estimate() << endl;
219  cout << "e Jac Xj" << endl << _jacobianOplusXj << endl << endl;
220  cout << "e Jac Xi" << endl << _jacobianOplusXi << endl << endl;
221 #endif
222 
223  if (!pl_pl) return;
224 
225  // re-define the information matrix
226  // topLeftCorner<3,3>() is the rotation()
227  const Matrix3D transform = ( vp0->estimate().inverse() * vp1->estimate() ).matrix().topLeftCorner<3,3>();
228  information() = ( cov0 + transform * cov1 * transform.transpose() ).inverse();
229 
230  }
231 
232  // try analytic jacobians
233 #ifdef GICP_ANALYTIC_JACOBIANS
234  virtual void linearizeOplus();
235 #endif
236 
237  // global derivative matrices
238  static Matrix3D dRidx;
239  static Matrix3D dRidy;
240  static Matrix3D dRidz; // differential quat matrices
241  };
242 
243 
251  {
252  public:
253  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
254 
255  VertexSCam();
256 
257  // I/O
258  virtual bool read(std::istream& is);
259  virtual bool write(std::ostream& os) const;
260 
261  // capture the update function to reset aux transforms
262  virtual void oplusImpl(const double* update)
263  {
264  VertexSE3::oplusImpl(update);
265  setAll();
266  }
267 
268  // camera matrix and stereo baseline
269  static Matrix3D Kcam;
270  static double baseline;
271 
272  // transformations
273  Eigen::Matrix<double,3,4,Eigen::ColMajor> w2n; // transform from world to node coordinates
274  Eigen::Matrix<double,3,4,Eigen::ColMajor> w2i; // transform from world to image coordinates
275 
276  // Derivatives of the rotation matrix transpose wrt quaternion xyz, used for
277  // calculating Jacobian wrt pose of a projection.
278  Matrix3D dRdx, dRdy, dRdz;
279 
280  // transforms
281  static void transformW2F(Eigen::Matrix<double,3,4,Eigen::ColMajor> &m,
282  const Vector3D &trans,
283  const Eigen::Quaterniond &qrot)
284  {
285  m.block<3,3>(0,0) = qrot.toRotationMatrix().transpose();
286  m.col(3).setZero(); // make sure there's no translation
287  Vector4D tt;
288  tt.head(3) = trans;
289  tt[3] = 1.0;
290  m.col(3) = -m*tt;
291  }
292 
293  static void transformF2W(Eigen::Matrix<double,3,4,Eigen::ColMajor> &m,
294  const Vector3D &trans,
295  const Eigen::Quaterniond &qrot)
296  {
297  m.block<3,3>(0,0) = qrot.toRotationMatrix();
298  m.col(3) = trans;
299  }
300 
301  // set up camera matrix
302  static void setKcam(double fx, double fy, double cx, double cy, double tx)
303  {
304  Kcam.setZero();
305  Kcam(0,0) = fx;
306  Kcam(1,1) = fy;
307  Kcam(0,2) = cx;
308  Kcam(1,2) = cy;
309  Kcam(2,2) = 1.0;
310  baseline = tx;
311  }
312 
313  // set transform from world to cam coords
314  void setTransform() {
315  w2n = estimate().inverse().matrix().block<3,4>(0, 0);
316  //transformW2F(w2n,estimate().translation(), estimate().rotation());
317  }
318 
319  // Set up world-to-image projection matrix (w2i), assumes camera parameters
320  // are filled.
321  void setProjection() { w2i = Kcam * w2n; }
322 
323  // sets angle derivatives
324  void setDr()
325  {
326  // inefficient, just for testing
327  // use simple multiplications and additions for production code in calculating dRdx,y,z
328  // for dS'*R', with dS the incremental change
329  dRdx = dRidx * w2n.block<3,3>(0,0);
330  dRdy = dRidy * w2n.block<3,3>(0,0);
331  dRdz = dRidz * w2n.block<3,3>(0,0);
332  }
333 
334  // set all aux transforms
335  void setAll()
336  {
337  setTransform();
338  setProjection();
339  setDr();
340  }
341 
342  // calculate stereo projection
343  void mapPoint(Vector3D &res, const Vector3D &pt3)
344  {
345  Vector4D pt;
346  pt.head<3>() = pt3;
347  pt(3) = 1.0;
348  Vector3D p1 = w2i * pt;
349  Vector3D p2 = w2n * pt;
350  Vector3D pb(baseline,0,0);
351 
352  double invp1 = 1.0/p1(2);
353  res.head<2>() = p1.head<2>()*invp1;
354 
355  // right camera px
356  p2 = Kcam*(p2-pb);
357  res(2) = p2(0)/p2(2);
358  }
359 
360  static Matrix3D dRidx;
361  static Matrix3D dRidy;
362  static Matrix3D dRidz;
363  };
364 
365 
371 // stereo projection
372 // first two args are the measurement type, second two the connection classes
373  class G2O_TYPES_ICP_API Edge_XYZ_VSC : public BaseBinaryEdge<3, Vector3D, VertexSBAPointXYZ, VertexSCam>
374 {
375  public:
376  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
377 
378  Edge_XYZ_VSC();
379 
380  virtual bool read(std::istream& is);
381  virtual bool write(std::ostream& os) const;
382 
383  // return the error estimate as a 2-vector
385  {
386  // from <Point> to <Cam>
387  const VertexSBAPointXYZ *point = static_cast<const VertexSBAPointXYZ*>(_vertices[0]);
388  VertexSCam *cam = static_cast<VertexSCam*>(_vertices[1]);
389  //cam->setAll();
390 
391  // calculate the projection
392  Vector3D kp;
393  cam->mapPoint(kp,point->estimate());
394 
395  // std::cout << std::endl << "CAM " << cam->estimate() << std::endl;
396  // std::cout << "POINT " << pt.transpose() << std::endl;
397  // std::cout << "PROJ " << p1.transpose() << std::endl;
398  // std::cout << "PROJ " << p2.transpose() << std::endl;
399  // std::cout << "CPROJ " << kp.transpose() << std::endl;
400  // std::cout << "MEAS " << _measurement.transpose() << std::endl;
401 
402  // error, which is backwards from the normal observed - calculated
403  // _measurement is the measured projection
404  _error = kp - _measurement;
405  }
406 #ifdef SCAM_ANALYTIC_JACOBIANS
407  // jacobian
408  virtual void linearizeOplus();
409 #endif
410 };
411 
412 
413 
414 } // end namespace
415 
416 #endif // TYPES_ICP
static void transformW2F(Eigen::Matrix< double, 3, 4, Eigen::ColMajor > &m, const Vector3D &trans, const Eigen::Quaterniond &qrot)
Definition: types_icp.h:281
Eigen::Matrix< double, 3, 1, Eigen::ColMajor > Vector3D
Definition: eigen_types.h:46
virtual void oplusImpl(const double *update)
Definition: types_icp.h:262
void setTransform()
Definition: types_icp.h:314
Eigen::Matrix< double, 4, 1, Eigen::ColMajor > Vector4D
Definition: eigen_types.h:47
static Matrix3D dRidz
Definition: types_icp.h:240
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Definition: types_icp.h:62
void transform(PlaneList &l, const SE3Quat &t)
Definition: plane_test.cpp:17
static Matrix3D dRidy
Definition: types_icp.h:239
Matrix3D cov1(double e)
Definition: types_icp.h:147
Point vertex, XYZ.
Definition: types_sba.h:137
Vector3D pos1
Definition: types_icp.h:66
Eigen::Matrix< double, 3, 4, Eigen::ColMajor > w2i
Definition: types_icp.h:274
void mapPoint(Vector3D &res, const Vector3D &pt3)
Definition: types_icp.h:343
static Matrix3D dRidx
Definition: types_icp.h:360
static Matrix3D dRidx
Definition: types_icp.h:238
static Matrix3D dRidy
Definition: types_icp.h:361
Matrix3D cov0(double e)
Definition: types_icp.h:136
static Matrix3D dRidz
Definition: types_icp.h:362
static Matrix3D Kcam
Definition: types_icp.h:269
Eigen::Matrix< double, 3, 3, Eigen::ColMajor > Matrix3D
Definition: eigen_types.h:61
static double baseline
Definition: types_icp.h:270
static void transformF2W(Eigen::Matrix< double, 3, 4, Eigen::ColMajor > &m, const Vector3D &trans, const Eigen::Quaterniond &qrot)
Definition: types_icp.h:293
#define G2O_TYPES_ICP_API
Eigen::Matrix< double, 3, 4, Eigen::ColMajor > w2n
Definition: types_icp.h:273
Matrix3D dRdz
Definition: types_icp.h:278
Vector3D normal1
Definition: types_icp.h:69
Matrix3D prec1(double e)
Definition: types_icp.h:125
const EstimateType & estimate() const
return the current estimate of the vertex
Definition: base_vertex.h:99
void setProjection()
Definition: types_icp.h:321
virtual void oplusImpl(const double *update)
Definition: vertex_se3.h:105
Matrix3D prec0(double e)
Definition: types_icp.h:114
Matrix3D R1
Definition: types_icp.h:72
3D pose Vertex, represented as an Isometry3D
Definition: vertex_se3.h:50
void makeRot0()
Definition: types_icp.h:87
void makeRot1()
Definition: types_icp.h:102
static void setKcam(double fx, double fy, double cx, double cy, double tx)
Definition: types_icp.h:302
Point vertex, XYZ, is in types_sba.
Definition: types_icp.h:373
Stereo camera vertex, derived from SE3 class. Note that we use the actual pose of the vertex as its p...
Definition: types_icp.h:250
void computeError()
Definition: types_icp.h:384
Matrix< double, 6, 1, Eigen::ColMajor > Vector6d
Definition: types_icp.cpp:75