g2o
types_icp.cpp
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 #include "types_icp.h"
28 #include "g2o/core/factory.h"
29 #include "g2o/stuff/macros.h"
30 
31 #include <iostream>
32 
33 using namespace Eigen;
34 
35 namespace g2o {
36 
38  G2O_REGISTER_TYPE(EDGE_V_V_GICP, Edge_V_V_GICP);
39 
40  namespace types_icp {
41  int initialized = 0;
42 
43  void init()
44  {
46  return;
47  //cerr << "Calling " << __FILE__ << " " << __PRETTY_FUNCTION__ << endl;
48 
49  Edge_V_V_GICP::dRidx << 0.0,0.0,0.0,
50  0.0,0.0,2.0,
51  0.0,-2.0,0.0;
52  Edge_V_V_GICP::dRidy << 0.0,0.0,-2.0,
53  0.0,0.0,0.0,
54  2.0,0.0,0.0;
55  Edge_V_V_GICP::dRidz << 0.0,2.0,0.0,
56  -2.0,0.0,0.0,
57  0.0,0.0,0.0;
58 
59  VertexSCam::dRidx << 0.0,0.0,0.0,
60  0.0,0.0,2.0,
61  0.0,-2.0,0.0;
62  VertexSCam::dRidy << 0.0,0.0,-2.0,
63  0.0,0.0,0.0,
64  2.0,0.0,0.0;
65  VertexSCam::dRidz << 0.0,2.0,0.0,
66  -2.0,0.0,0.0,
67  0.0,0.0,0.0;
68 
70  }
71  }
72 
73  using namespace std;
74  using namespace Eigen;
75  typedef Matrix<double, 6, 1, Eigen::ColMajor> Vector6d;
76 
77  Matrix3D Edge_V_V_GICP::dRidx; // differential quat matrices
78  Matrix3D Edge_V_V_GICP::dRidy; // differential quat matrices
79  Matrix3D Edge_V_V_GICP::dRidz; // differential quat matrices
80  Matrix3D VertexSCam::dRidx; // differential quat matrices
81  Matrix3D VertexSCam::dRidy; // differential quat matrices
82  Matrix3D VertexSCam::dRidz; // differential quat matrices
83  Matrix3D VertexSCam::Kcam;
84  double VertexSCam::baseline;
85 
86  // global initialization
87  G2O_ATTRIBUTE_CONSTRUCTOR(init_icp_types)
88  {
90  }
91 
92  // Copy constructor
93  Edge_V_V_GICP::Edge_V_V_GICP(const Edge_V_V_GICP* e)
95  {
96 
97  // Temporary hack - TODO, sort out const-ness properly
98  _vertices[0] = const_cast<HyperGraph::Vertex*> (e->vertex(0));
99  _vertices[1] = const_cast<HyperGraph::Vertex*> (e->vertex(1));
100 
105  _measurement.R0 = e->measurement().R0;
106  _measurement.R1 = e->measurement().R1;
107 
108  pl_pl = e->pl_pl;
109  cov0 = e->cov0;
110  cov1 = e->cov1;
111 
112  // TODO the robust kernel is not correctly copied
113  //_robustKernel = e->_robustKernel;
114  }
115 
116  //
117  // Rigid 3D constraint between poses, given fixed point offsets
118  //
119 
120  // input two matched points between the frames
121  // first point belongs to the first frame, position and normal
122  // second point belongs to the second frame, position and normal
123  //
124  // the measurement variable has type EdgeGICP (see types_icp.h)
125 
126  bool Edge_V_V_GICP::read(std::istream& is)
127  {
128  // measured point and normal
129  for (int i=0; i<3; i++)
130  is >> _measurement.pos0[i];
131  for (int i=0; i<3; i++)
132  is >> _measurement.normal0[i];
133 
134  // measured point and normal
135  for (int i=0; i<3; i++)
136  is >> _measurement.pos1[i];
137  for (int i=0; i<3; i++)
138  is >> _measurement.normal1[i];
139 
140  // don't need this if we don't use it in error calculation (???)
141  // inverseMeasurement() = -measurement();
142 
143  _measurement.makeRot0(); // set up rotation matrices
144 
145  // GICP info matrices
146 
147  // point-plane only
148  Matrix3D prec;
149  double v = .01;
150  prec << v, 0, 0,
151  0, v, 0,
152  0, 0, 1;
153  const Matrix3D &R = measurement().R0; // plane of the point in vp0
154  information() = R.transpose()*prec*R;
155 
156  // information().setIdentity();
157 
158  // setRobustKernel(true);
159  //setHuberWidth(0.01); // units? m?
160 
161  return true;
162  }
163 
164 
165  // Jacobian
166  // [ -R0'*R1 | R0 * dRdx/ddx * 0p1 ]
167  // [ R0'*R1 | R0 * dR'dx/ddx * 0p1 ]
168 
169 #ifdef GICP_ANALYTIC_JACOBIANS
170 
171  // jacobian defined as:
172  // f(T0,T1) = dR0.inv() * T0.inv() * (T1 * dR1 * p1 + dt1) - dt0
173  // df/dx0 = [-I, d[dR0.inv()]/dq0 * T01 * p1]
174  // df/dx1 = [R0, T01 * d[dR1]/dq1 * p1]
176  {
177  VertexSE3* vp0 = static_cast<VertexSE3*>(_vertices[0]);
178  VertexSE3* vp1 = static_cast<VertexSE3*>(_vertices[1]);
179 
180  // topLeftCorner<3,3>() is the rotation matrix
181  Matrix3D R0T = vp0->estimate().matrix().topLeftCorner<3,3>().transpose();
182  Vector3D p1 = measurement().pos1;
183 
184  // this could be more efficient
185  if (!vp0->fixed())
186  {
187  Isometry3D T01 = vp0->estimate().inverse() * vp1->estimate();
188  Vector3D p1t = T01 * p1;
189  _jacobianOplusXi.block<3,3>(0,0) = -Matrix3D::Identity();
190  _jacobianOplusXi.block<3,1>(0,3) = dRidx*p1t;
191  _jacobianOplusXi.block<3,1>(0,4) = dRidy*p1t;
192  _jacobianOplusXi.block<3,1>(0,5) = dRidz*p1t;
193  }
194 
195  if (!vp1->fixed())
196  {
197  Matrix3D R1 = vp1->estimate().matrix().topLeftCorner<3,3>();
198  R0T = R0T*R1;
199  _jacobianOplusXj.block<3,3>(0,0) = R0T;
200  _jacobianOplusXj.block<3,1>(0,3) = R0T*dRidx.transpose()*p1;
201  _jacobianOplusXj.block<3,1>(0,4) = R0T*dRidy.transpose()*p1;
202  _jacobianOplusXj.block<3,1>(0,5) = R0T*dRidz.transpose()*p1;
203  }
204  }
205 #endif
206 
207 
208  bool Edge_V_V_GICP::write(std::ostream& os) const
209  {
210  // first point
211  for (int i=0; i<3; i++)
212  os << measurement().pos0[i] << " ";
213  for (int i=0; i<3; i++)
214  os << measurement().normal0[i] << " ";
215 
216  // second point
217  for (int i=0; i<3; i++)
218  os << measurement().pos1[i] << " ";
219  for (int i=0; i<3; i++)
220  os << measurement().normal1[i] << " ";
221 
222 
223  return os.good();
224  }
225 
226  //
227  // stereo camera functions
228  //
229 
230 
231 
233  VertexSE3()
234  {}
235 
236 
238  {}
239 
240 #ifdef SCAM_ANALYTIC_JACOBIANS
241 
245  {
246  VertexSCam *vc = static_cast<VertexSCam *>(_vertices[1]);
247 
248  VertexSBAPointXYZ *vp = static_cast<VertexSBAPointXYZ *>(_vertices[0]);
249  Vector4D pt, trans;
250  pt.head<3>() = vp->estimate();
251  pt(3) = 1.0;
252  trans.head<3>() = vc->estimate().translation();
253  trans(3) = 1.0;
254 
255  // first get the world point in camera coords
256  Eigen::Matrix<double,3,1,Eigen::ColMajor> pc = vc->w2n * pt;
257 
258  // Jacobians wrt camera parameters
259  // set d(quat-x) values [ pz*dpx/dx - px*dpz/dx ] / pz^2
260  double px = pc(0);
261  double py = pc(1);
262  double pz = pc(2);
263  double ipz2 = 1.0/(pz*pz);
264  if (isnan(ipz2) )
265  {
266  std::cout << "[SetJac] infinite jac" << std::endl;
267  *(int *)0x0 = 0;
268  }
269 
270  double ipz2fx = ipz2*vc->Kcam(0,0); // Fx
271  double ipz2fy = ipz2*vc->Kcam(1,1); // Fy
272  double b = vc->baseline; // stereo baseline
273 
274  Eigen::Matrix<double,3,1,Eigen::ColMajor> pwt;
275 
276  // check for local vars
277  pwt = (pt-trans).head<3>(); // transform translations, use differential rotation
278 
279  // dx
280  Eigen::Matrix<double,3,1,Eigen::ColMajor> dp = vc->dRdx * pwt; // dR'/dq * [pw - t]
281  _jacobianOplusXj(0,3) = (pz*dp(0) - px*dp(2))*ipz2fx;
282  _jacobianOplusXj(1,3) = (pz*dp(1) - py*dp(2))*ipz2fy;
283  _jacobianOplusXj(2,3) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
284  // dy
285  dp = vc->dRdy * pwt; // dR'/dq * [pw - t]
286  _jacobianOplusXj(0,4) = (pz*dp(0) - px*dp(2))*ipz2fx;
287  _jacobianOplusXj(1,4) = (pz*dp(1) - py*dp(2))*ipz2fy;
288  _jacobianOplusXj(2,4) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
289  // dz
290  dp = vc->dRdz * pwt; // dR'/dq * [pw - t]
291  _jacobianOplusXj(0,5) = (pz*dp(0) - px*dp(2))*ipz2fx;
292  _jacobianOplusXj(1,5) = (pz*dp(1) - py*dp(2))*ipz2fy;
293  _jacobianOplusXj(2,5) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
294 
295  // set d(t) values [ pz*dpx/dx - px*dpz/dx ] / pz^2
296  dp = -vc->w2n.col(0); // dpc / dx
297  _jacobianOplusXj(0,0) = (pz*dp(0) - px*dp(2))*ipz2fx;
298  _jacobianOplusXj(1,0) = (pz*dp(1) - py*dp(2))*ipz2fy;
299  _jacobianOplusXj(2,0) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
300  dp = -vc->w2n.col(1); // dpc / dy
301  _jacobianOplusXj(0,1) = (pz*dp(0) - px*dp(2))*ipz2fx;
302  _jacobianOplusXj(1,1) = (pz*dp(1) - py*dp(2))*ipz2fy;
303  _jacobianOplusXj(2,1) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
304  dp = -vc->w2n.col(2); // dpc / dz
305  _jacobianOplusXj(0,2) = (pz*dp(0) - px*dp(2))*ipz2fx;
306  _jacobianOplusXj(1,2) = (pz*dp(1) - py*dp(2))*ipz2fy;
307  _jacobianOplusXj(2,2) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
308 
309  // Jacobians wrt point parameters
310  // set d(t) values [ pz*dpx/dx - px*dpz/dx ] / pz^2
311  dp = vc->w2n.col(0); // dpc / dx
312  _jacobianOplusXi(0,0) = (pz*dp(0) - px*dp(2))*ipz2fx;
313  _jacobianOplusXi(1,0) = (pz*dp(1) - py*dp(2))*ipz2fy;
314  _jacobianOplusXi(2,0) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
315  dp = vc->w2n.col(1); // dpc / dy
316  _jacobianOplusXi(0,1) = (pz*dp(0) - px*dp(2))*ipz2fx;
317  _jacobianOplusXi(1,1) = (pz*dp(1) - py*dp(2))*ipz2fy;
318  _jacobianOplusXi(2,1) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
319  dp = vc->w2n.col(2); // dpc / dz
320  _jacobianOplusXi(0,2) = (pz*dp(0) - px*dp(2))*ipz2fx;
321  _jacobianOplusXi(1,2) = (pz*dp(1) - py*dp(2))*ipz2fy;
322  _jacobianOplusXi(2,2) = (pz*dp(0) - (px-b)*dp(2))*ipz2fx; // right image px
323  }
324 #endif
325  bool Edge_XYZ_VSC::read(std::istream&)
326  { return false; }
327 
328  bool Edge_XYZ_VSC::write(std::ostream&) const
329  { return false; }
330 
331  bool VertexSCam::read(std::istream&)
332  { return false; }
333 
334  bool VertexSCam::write(std::ostream&) const
335  { return false; }
336 
337 } // end namespace
virtual bool read(std::istream &is)
read the vertex from a stream, i.e., the internal state of the vertex
Definition: types_icp.cpp:126
const Vertex * vertex(size_t i) const
Definition: hyper_graph.h:186
EIGEN_MAKE_ALIGNED_OPERATOR_NEW VertexSCam()
Definition: types_icp.cpp:232
Eigen::Matrix< double, 3, 1, Eigen::ColMajor > Vector3D
Definition: eigen_types.h:46
Eigen::Matrix< double, 4, 1, Eigen::ColMajor > Vector4D
Definition: eigen_types.h:47
Matrix3D dRdy
Definition: types_icp.h:278
static Matrix3D dRidz
Definition: types_icp.h:240
Matrix3D R0
Definition: types_icp.h:72
virtual void linearizeOplus()
Definition: types_icp.cpp:175
Vector3D normal0
Definition: types_icp.h:69
virtual bool write(std::ostream &os) const
write the vertex to a stream
Definition: types_icp.cpp:208
static Matrix3D dRidy
Definition: types_icp.h:239
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Edge_XYZ_VSC()
Definition: types_icp.cpp:237
virtual bool read(std::istream &is)
read the vertex from a stream, i.e., the internal state of the vertex
Definition: types_icp.cpp:325
#define G2O_REGISTER_TYPE(name, classname)
Definition: factory.h:163
Point vertex, XYZ.
Definition: types_sba.h:137
virtual bool read(std::istream &is)
read the vertex from a stream, i.e., the internal state of the vertex
Definition: types_icp.cpp:331
#define G2O_REGISTER_TYPE_GROUP(typeGroupName)
Definition: factory.h:171
Vector3D pos1
Definition: types_icp.h:66
static Matrix3D dRidx
Definition: types_icp.h:238
Eigen::Matrix< double, D, 1, Eigen::ColMajor > & b()
return right hand side b of the constructed linear system
Definition: base_vertex.h:87
Eigen::Transform< double, 3, Eigen::Isometry, Eigen::ColMajor > Isometry3D
Definition: eigen_types.h:66
static Matrix3D Kcam
Definition: types_icp.h:269
virtual bool write(std::ostream &os) const
write the vertex to a stream
Definition: types_icp.cpp:328
Eigen::Matrix< double, 3, 3, Eigen::ColMajor > Matrix3D
Definition: eigen_types.h:61
static double baseline
Definition: types_icp.h:270
abstract Vertex, your types must derive from that one
Definition: hyper_graph.h:142
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
EIGEN_STRONG_INLINE const InformationType & information() const
information matrix of the constraint
Definition: base_edge.h:67
bool fixed() const
true => this node is fixed during the optimization
const EstimateType & estimate() const
return the current estimate of the vertex
Definition: base_vertex.h:99
Eigen::Matrix< double, 6, 1 > Vector6d
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
virtual bool write(std::ostream &os) const
write the vertex to a stream
Definition: types_icp.cpp:334
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
Matrix3D dRdx
Definition: types_icp.h:278
EIGEN_STRONG_INLINE const Measurement & measurement() const
accessor functions for the measurement represented by the edge
Definition: base_edge.h:75
Vector3D pos0
Definition: types_icp.h:66
#define G2O_ATTRIBUTE_CONSTRUCTOR(func)
Definition: macros.h:91
VertexContainer _vertices
Definition: hyper_graph.h:202