types_icp.h
Go to the documentation of this file.
00001 // g2o - General Graph Optimization
00002 // Copyright (C) 2011 Kurt Konolige
00003 //
00004 // g2o is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU Lesser General Public License as published
00006 // by the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // g2o is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser General Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #ifndef TYPES_ICP
00018 #define TYPES_ICP
00019 
00020 #define GICP_ANALYTIC_JACOBIANS
00021 //#define SCAM_ANALYTIC_JACOBIANS
00022 
00023 #include "g2o/core/base_vertex.h"
00024 #include "g2o/core/base_binary_edge.h"
00025 #include "g2o/core/base_multi_edge.h"
00026 #include "g2o/math_groups/sbacam.h"
00027 #include "g2o/types/sba/types_sba.h"
00028 #include "g2o/types/slam3d/types_six_dof_quat.h"
00029 #include <Eigen/Geometry>
00030 #include <iostream>
00031 
00032 namespace g2o {
00033 
00034   using namespace Eigen;
00035   using namespace std;
00036   typedef  Matrix<double, 6, 1> Vector6d;
00037 
00038 
00039 
00040 //
00041 // GICP-type edges
00042 // Each measurement is between two rigid points on each 6DOF vertex
00043 //
00044 
00045 
00046   //
00047   // class for edges between two points rigidly attached to vertices
00048   //
00049 
00050   class EdgeGICP
00051   {
00052     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00053 
00054    public:
00055     // point positions
00056     Vector3d pos0, pos1;
00057 
00058     // unit normals
00059     Vector3d normal0, normal1;
00060 
00061     // rotation matrix for normal
00062     Matrix3d R0,R1;
00063 
00064     // initialize an object
00065     EdgeGICP()
00066       {
00067         pos0.setZero();
00068         pos1.setZero();
00069         normal0 << 0, 0, 1;
00070         normal1 << 0, 0, 1;
00071         //makeRot();
00072         R0.setIdentity();
00073         R1.setIdentity();
00074       }
00075 
00076     // set up rotation matrix for pos0
00077     void makeRot0()
00078     {
00079       Vector3d y;
00080       y << 0, 1, 0;
00081       R0.row(2) = normal0;
00082       y = y - normal0(1)*normal0;
00083       y.normalize();            // need to check if y is close to 0
00084       R0.row(1) = y;
00085       R0.row(0) = normal0.cross(R0.row(1));
00086       //      cout << normal.transpose() << endl;
00087       //      cout << R0 << endl << endl;
00088       //      cout << R0*R0.transpose() << endl << endl;
00089     }
00090 
00091     // set up rotation matrix for pos1
00092     void makeRot1()
00093     {
00094       Vector3d y;
00095       y << 0, 1, 0;
00096       R1.row(2) = normal1;
00097       y = y - normal1(1)*normal1;
00098       y.normalize();            // need to check if y is close to 0
00099       R1.row(1) = y;
00100       R1.row(0) = normal1.cross(R1.row(1));
00101     }
00102 
00103     // returns a precision matrix for point-plane
00104     Matrix3d prec0(double e)
00105     {
00106       makeRot0();
00107       Matrix3d prec;
00108       prec << e, 0, 0,
00109               0, e, 0,
00110               0, 0, 1;
00111       return R0.transpose()*prec*R0;
00112     }
00113 
00114   };
00115 
00116 
00117   // 3D rigid constraint
00118   //    3 values for position wrt frame
00119   //    3 values for normal wrt frame, not used here
00120   // first two args are the measurement type, second two the connection classes
00121   class Edge_V_V_GICP : public  BaseBinaryEdge<3, EdgeGICP, VertexSE3, VertexSE3>
00122   {
00123   public:
00124     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00125       Edge_V_V_GICP() : pl_pl(false) {};
00126       Edge_V_V_GICP(const Edge_V_V_GICP* e);
00127 
00128     // switch to go between point-plane and plane-plane
00129     bool pl_pl;
00130     Matrix3d cov0, cov1;
00131 
00132     // I/O functions
00133     virtual bool read(std::istream& is);
00134     virtual bool write(std::ostream& os) const;
00135 
00136     // return the error estimate as a 3-vector
00137     void computeError()
00138     {
00139       // from <ViewPoint> to <Point>
00140       const VertexSE3 *vp0 = static_cast<const VertexSE3*>(_vertices[0]);
00141       const VertexSE3 *vp1 = static_cast<const VertexSE3*>(_vertices[1]);
00142 
00143       // get vp1 point into vp0 frame
00144       // could be more efficient if we computed this transform just once
00145       Vector3d p1;
00146 
00147 #if 0
00148       if (_cnum >= 0 && 0)      // using global cache
00149         {
00150           if (_tainted[_cnum])  // set up transform
00151             {
00152               _transforms[_cnum] = vp0->estimate().inverse() * vp1->estimate();
00153               _tainted[_cnum] = 0;
00154               cout << _transforms[_cnum] << endl;
00155             }
00156           p1 = _transforms[_cnum].map(measurement().pos1); // do the transform
00157         }
00158       else
00159 #endif
00160         {
00161           p1 = vp1->estimate().map(measurement().pos1);
00162           p1 = vp0->estimate().inverse().map(p1);
00163         }
00164 
00165       //      cout << endl << "Error computation; points are: " << endl;
00166       //      cout << p0.transpose() << endl;
00167       //      cout << p1.transpose() << endl;
00168 
00169       // get their difference
00170       // this is simple Euclidean distance, for now
00171       _error = p1 - measurement().pos0;
00172 
00173 #if 0
00174       cout << "vp0" << endl << vp0->estimate() << endl;
00175       cout << "vp1" << endl << vp1->estimate() << endl;
00176       cout << "e Jac Xj" << endl <<  _jacobianOplusXj << endl << endl;
00177       cout << "e Jac Xi" << endl << _jacobianOplusXi << endl << endl;
00178 #endif
00179 
00180       if (!pl_pl) return;
00181 
00182       // re-define the information matrix
00183       const Matrix3d transform = ( vp0->estimate().inverse() *  vp1->estimate() ).rotation().toRotationMatrix();
00184       information() = ( cov0 + transform * cov1 * transform.transpose() ).inverse();
00185 
00186     }
00187 
00188     // try analytic jacobians
00189 #ifdef GICP_ANALYTIC_JACOBIANS
00190     virtual void linearizeOplus();
00191 #endif
00192 
00193     // global derivative matrices
00194     static Matrix3d dRidx, dRidy, dRidz; // differential quat matrices
00195   };
00196 
00197 
00198 
00207   class VertexSCam : public VertexSE3
00208     {
00209     public:
00210       EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00211 
00212         VertexSCam();
00213 
00214       // I/O
00215       virtual bool read(std::istream& is);
00216       virtual bool write(std::ostream& os) const;
00217 
00218       // capture the update function to reset aux transforms
00219       virtual void oplus(double* update)
00220       {
00221         VertexSE3::oplus(update);
00222         setAll();
00223       }
00224 
00225       // camera matrix and stereo baseline
00226       static Matrix3d Kcam;
00227       static double baseline;
00228 
00229       // transformations
00230       Matrix<double,3,4> w2n; // transform from world to node coordinates
00231       Matrix<double,3,4> w2i; // transform from world to image coordinates
00232 
00233       // Derivatives of the rotation matrix transpose wrt quaternion xyz, used for
00234       // calculating Jacobian wrt pose of a projection.
00235       Matrix3d dRdx, dRdy, dRdz;
00236 
00237       // transforms
00238       static void transformW2F(Matrix<double,3,4> &m,
00239                                const Vector3d &trans,
00240                                const Quaterniond &qrot)
00241         {
00242           m.block<3,3>(0,0) = qrot.toRotationMatrix().transpose();
00243           m.col(3).setZero();         // make sure there's no translation
00244           Vector4d tt;
00245           tt.head(3) = trans;
00246           tt[3] = 1.0;
00247           m.col(3) = -m*tt;
00248         }
00249 
00250       static void transformF2W(Matrix<double,3,4> &m,
00251                                const Vector3d &trans,
00252                                const Quaterniond &qrot)
00253         {
00254           m.block<3,3>(0,0) = qrot.toRotationMatrix();
00255           m.col(3) = trans;
00256         }
00257 
00258       // set up camera matrix
00259       static void setKcam(double fx, double fy, double cx, double cy, double tx)
00260       {
00261         Kcam.setZero();
00262         Kcam(0,0) = fx;
00263         Kcam(1,1) = fy;
00264         Kcam(0,2) = cx;
00265         Kcam(1,2) = cy;
00266         Kcam(2,2) = 1.0;
00267         baseline = tx;
00268       }
00269 
00270       // set transform from world to cam coords
00271       void setTransform()  { transformW2F(w2n,estimate().translation(),
00272                                           estimate().rotation()); }
00273 
00274       // Set up world-to-image projection matrix (w2i), assumes camera parameters
00275       // are filled.
00276       void setProjection() { w2i = Kcam * w2n; }
00277 
00278       // sets angle derivatives
00279       void setDr()
00280       {
00281         // inefficient, just for testing
00282         // use simple multiplications and additions for production code in calculating dRdx,y,z
00283         // for dS'*R', with dS the incremental change
00284         dRdx = dRidx * w2n.block<3,3>(0,0);
00285         dRdy = dRidy * w2n.block<3,3>(0,0);
00286         dRdz = dRidz * w2n.block<3,3>(0,0);
00287       }
00288 
00289       // set all aux transforms
00290       void setAll()
00291       {
00292         setTransform();
00293         setProjection();
00294         setDr();
00295       }
00296 
00297       // calculate stereo projection
00298       void mapPoint(Vector3d &res, const Vector3d &pt3)
00299       {
00300         Vector4d pt;
00301         pt.head<3>() = pt3;
00302         pt(3) = 1.0;
00303         Vector3d p1 = w2i * pt;
00304         Vector3d p2 = w2n * pt;
00305         Vector3d pb(baseline,0,0);
00306 
00307         double invp1 = 1.0/p1(2);
00308         res.head<2>() = p1.head<2>()*invp1;
00309 
00310         // right camera px
00311         p2 = Kcam*(p2-pb);
00312         res(2) = p2(0)/p2(2);
00313       }
00314 
00315       static Matrix3d dRidx, dRidy, dRidz;
00316     };
00317 
00318 
00324 // stereo projection
00325 // first two args are the measurement type, second two the connection classes
00326   class Edge_XYZ_VSC : public  BaseBinaryEdge<3, Vector3d, VertexPointXYZ, VertexSCam>
00327 {
00328   public:
00329     EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00330 
00331       Edge_XYZ_VSC();
00332 
00333     virtual bool read(std::istream& is);
00334     virtual bool write(std::ostream& os) const;
00335 
00336     // return the error estimate as a 2-vector
00337     void computeError()
00338     {
00339       // from <Point> to <Cam>
00340       const VertexPointXYZ *point = static_cast<const VertexPointXYZ*>(_vertices[0]);
00341       VertexSCam *cam = static_cast<VertexSCam*>(_vertices[1]);
00342       //cam->setAll();
00343 
00344       // calculate the projection
00345       Vector3d kp;
00346       cam->mapPoint(kp,point->estimate());
00347 
00348       // std::cout << std::endl << "CAM   " << cam->estimate() << std::endl;
00349       // std::cout << "POINT " << pt.transpose() << std::endl;
00350       // std::cout << "PROJ  " << p1.transpose() << std::endl;
00351       // std::cout << "PROJ  " << p2.transpose() << std::endl;
00352       // std::cout << "CPROJ " << kp.transpose() << std::endl;
00353       // std::cout << "MEAS  " << _measurement.transpose() << std::endl;
00354 
00355       // error, which is backwards from the normal observed - calculated
00356       // _measurement is the measured projection
00357       _error = kp - _measurement;
00358     }
00359 #ifdef SCAM_ANALYTIC_JACOBIANS
00360     // jacobian
00361     virtual void linearizeOplus();
00362 #endif
00363 };
00364 
00365 
00366 
00367 } // end namespace
00368 
00369 #endif // TYPES_ICP


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:33:29