sba_demo.cpp
Go to the documentation of this file.
00001 // g2o - General Graph Optimization
00002 // Copyright (C) 2011 H. Strasdat
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 #include <Eigen/StdVector>
00018 #include <tr1/random>
00019 #include <iostream>
00020 #include <stdint.h>
00021 #include <tr1/unordered_set>
00022 
00023 #include "g2o/core/graph_optimizer_sparse.h"
00024 #include "g2o/core/block_solver.h"
00025 #include "g2o/core/solver.h"
00026 #include "g2o/solvers/cholmod/linear_solver_cholmod.h"
00027 #include "g2o/solvers/cholmod/linear_solver_cholmod.h"
00028 #include "g2o/solvers/dense/linear_solver_dense.h"
00029 #include "g2o/types/icp/types_icp.h"
00030 #include "g2o/core/structure_only_solver.h"
00031 
00032 using namespace Eigen;
00033 using namespace std;
00034 
00035 
00036 class Sample
00037 {
00038 
00039   static tr1::ranlux_base_01 gen_real;
00040   static tr1::mt19937 gen_int;
00041 public:
00042   static int uniform(int from, int to);
00043 
00044   static double uniform();
00045 
00046   static double gaussian(double sigma);
00047 };
00048 
00049 
00050 tr1::ranlux_base_01 Sample::gen_real;
00051 tr1::mt19937 Sample::gen_int;
00052 
00053 int Sample::uniform(int from, int to)
00054 {
00055   tr1::uniform_int<int> unif(from, to);
00056   int sam = unif(gen_int);
00057   return  sam;
00058 }
00059 
00060 double Sample::uniform()
00061 {
00062   std::tr1::uniform_real<double> unif(0.0, 1.0);
00063   double sam = unif(gen_real);
00064   return  sam;
00065 }
00066 
00067 double Sample::gaussian(double sigma)
00068 {
00069   std::tr1::normal_distribution<double> gauss(0.0, sigma);
00070   double sam = gauss(gen_real);
00071   return  sam;
00072 }
00073 
00074 int main(int argc, const char* argv[])
00075 {
00076   if (argc<2)
00077   {
00078     cout << endl;
00079     cout << "Please type: " << endl;
00080     cout << "ba_demo [PIXEL_NOISE] [OUTLIER RATIO] [ROBUST_KERNEL] [STRUCTURE_ONLY] [DENSE]" << endl;
00081     cout << endl;
00082     cout << "PIXEL_NOISE: noise in image space (E.g.: 1)" << endl;
00083     cout << "OUTLIER_RATIO: probability of spuroius observation  (default: 0.0)" << endl;
00084     cout << "ROBUST_KERNEL: use robust kernel (0 or 1; default: 0==false)" << endl;
00085     cout << "STRUCTURE_ONLY: performe structure-only BA to get better point initializations (0 or 1; default: 0==false)" << endl;
00086     cout << "DENSE: Use dense solver (0 or 1; default: 0==false)" << endl;
00087     cout << endl;
00088     cout << "Note, if OUTLIER_RATIO is above 0, ROBUST_KERNEL should be set to 1==true." << endl;
00089     cout << endl;
00090     exit(0);
00091   }
00092 
00093   double PIXEL_NOISE = atof(argv[1]);
00094 
00095   double OUTLIER_RATIO = 0.0;
00096 
00097   if (argc>2)
00098   {
00099     OUTLIER_RATIO = atof(argv[2]);
00100   }
00101 
00102   bool ROBUST_KERNEL = false;
00103   if (argc>3)
00104   {
00105     ROBUST_KERNEL = atof(argv[3]);
00106   }
00107   bool STRUCTURE_ONLY = false;
00108   if (argc>4)
00109   {
00110     STRUCTURE_ONLY = atof(argv[4]);
00111   }
00112 
00113   bool DENSE = false;
00114   if (argc>5)
00115   {
00116     DENSE = atof(argv[5]);
00117   }
00118 
00119   cout << "PIXEL_NOISE: " <<  PIXEL_NOISE << endl;
00120   cout << "OUTLIER_RATIO: " << OUTLIER_RATIO<<  endl;
00121   cout << "ROBUST_KERNEL: " << ROBUST_KERNEL << endl;
00122   cout << "STRUCTURE_ONLY: " << STRUCTURE_ONLY<< endl;
00123   cout << "DENSE: "<<  DENSE << endl;
00124 
00125 
00126 
00127   g2o::SparseOptimizer optimizer;
00128   optimizer.setMethod(g2o::SparseOptimizer::LevenbergMarquardt);
00129   optimizer.setVerbose(false);
00130   g2o::BlockSolver_6_3::LinearSolverType * linearSolver;
00131   if (DENSE)
00132   {
00133         linearSolver= new g2o::LinearSolverDense<g2o
00134         ::BlockSolver_6_3::PoseMatrixType>();
00135   }
00136   else
00137   {
00138     linearSolver
00139         = new g2o::LinearSolverCholmod<g2o
00140         ::BlockSolver_6_3::PoseMatrixType>();
00141   }
00142 
00143 
00144   g2o::BlockSolver_6_3 * solver_ptr
00145       = new g2o::BlockSolver_6_3(&optimizer,linearSolver);
00146 
00147 
00148   optimizer.setSolver(solver_ptr);
00149 
00150 
00151   // set up 500 points
00152   vector<Vector3d> true_points;
00153   for (size_t i=0;i<500; ++i)
00154   {
00155     true_points.push_back(Vector3d((Sample::uniform()-0.5)*3,
00156                                    Sample::uniform()-0.5,
00157                                    Sample::uniform()+10));
00158   }
00159 
00160 
00161   Vector2d focal_length(500,500); // pixels
00162   Vector2d principal_point(320,240); // 640x480 image
00163   double baseline = 0.075;      // 7.5 cm baseline
00164 
00165 
00166   vector<g2o::SE3Quat,
00167       aligned_allocator<g2o::SE3Quat> > true_poses;
00168 
00169   // set up camera params
00170   g2o::VertexSCam::setKcam(focal_length[0],focal_length[1],
00171                            principal_point[0],principal_point[1],
00172                            baseline);
00173   
00174   // set up 5 vertices, first 2 fixed
00175   int vertex_id = 0;
00176   for (size_t i=0; i<5; ++i)
00177   {
00178 
00179 
00180     Vector3d trans(i*0.04-1.,0,0);
00181 
00182     Eigen:: Quaterniond q;
00183     q.setIdentity();
00184     g2o::SE3Quat pose(q,trans);
00185 
00186 
00187     g2o::VertexSCam * v_se3
00188         = new g2o::VertexSCam();
00189 
00190     v_se3->setId(vertex_id);
00191     v_se3->estimate() = pose;
00192     v_se3->setAll();            // set aux transforms
00193 
00194     if (i<2)
00195       v_se3->setFixed(true);
00196     
00197     optimizer.addVertex(v_se3);
00198     true_poses.push_back(pose);
00199     vertex_id++;
00200   }
00201 
00202   int point_id=vertex_id;
00203   int point_num = 0;
00204   double sum_diff2 = 0;
00205 
00206   cout << endl;
00207   tr1::unordered_map<int,int> pointid_2_trueid;
00208   tr1::unordered_set<int> inliers;
00209 
00210   // add point projections to this vertex
00211   for (size_t i=0; i<true_points.size(); ++i)
00212   {
00213     g2o::VertexPointXYZ * v_p
00214         = new g2o::VertexPointXYZ();
00215 
00216 
00217     v_p->setId(point_id);
00218     v_p->setMarginalized(true);
00219     v_p->estimate() = true_points.at(i)
00220         + Vector3d(Sample::gaussian(1),
00221                    Sample::gaussian(1),
00222                    Sample::gaussian(1));
00223 
00224 
00225 
00226     int num_obs = 0;
00227 
00228     for (size_t j=0; j<true_poses.size(); ++j)
00229     {
00230       Vector3d z;
00231       dynamic_cast<g2o::VertexSCam*>
00232         (optimizer.vertices().find(j)->second)
00233         ->mapPoint(z,true_points.at(i));
00234 
00235       if (z[0]>=0 && z[1]>=0 && z[0]<640 && z[1]<480)
00236       {
00237         ++num_obs;
00238       }
00239     }
00240 
00241     if (num_obs>=2)
00242     {
00243 
00244       bool inlier = true;
00245       for (size_t j=0; j<true_poses.size(); ++j)
00246       {
00247         Vector3d z;
00248         dynamic_cast<g2o::VertexSCam*>
00249           (optimizer.vertices().find(j)->second)
00250           ->mapPoint(z,true_points.at(i));
00251 
00252         if (z[0]>=0 && z[1]>=0 && z[0]<640 && z[1]<480)
00253         {
00254           double sam = Sample::uniform();
00255           if (sam<OUTLIER_RATIO)
00256           {
00257             z = Vector3d(Sample::uniform(64,640),
00258                          Sample::uniform(0,480),
00259                          Sample::uniform(0,64)); // disparity
00260             z(2) = z(0) - z(2); // px' now
00261 
00262             inlier= false;
00263           }
00264 
00265           z += Vector3d(Sample::gaussian(PIXEL_NOISE),
00266                         Sample::gaussian(PIXEL_NOISE),
00267                         Sample::gaussian(PIXEL_NOISE/16.0));
00268 
00269           g2o::Edge_XYZ_VSC * e
00270               = new g2o::Edge_XYZ_VSC();
00271 
00272 
00273           e->vertices()[0]
00274               = dynamic_cast<g2o::OptimizableGraph::Vertex*>(v_p);
00275 
00276           e->vertices()[1]
00277               = dynamic_cast<g2o::OptimizableGraph::Vertex*>
00278               (optimizer.vertices().find(j)->second);
00279 
00280           e->measurement() = z;
00281           e->inverseMeasurement() = -z;
00282           e->information() = Matrix3d::Identity();
00283 
00284           e->setRobustKernel(ROBUST_KERNEL);
00285           e->setHuberWidth(1);
00286 
00287           optimizer.addEdge(e);
00288 
00289 
00290         }
00291 
00292       }
00293 
00294       if (inlier)
00295       {
00296         inliers.insert(point_id);
00297         Vector3d diff = v_p->estimate() - true_points[i];
00298 
00299         sum_diff2 += diff.dot(diff);
00300       }
00301      // else
00302      //   cout << "Point: " << point_id <<  "has at least one spurious observation" <<endl;
00303 
00304 
00305       optimizer.addVertex(v_p);
00306 
00307       pointid_2_trueid.insert(make_pair(point_id,i));
00308 
00309       ++point_id;
00310       ++point_num;
00311 
00312 
00313     }
00314 
00315   }
00316 
00317 
00318   cout << endl;
00319   optimizer.initializeOptimization();
00320 
00321   optimizer.setVerbose(true);
00322 
00323 
00324   g2o::StructureOnlySolver<3> structure_only_ba;
00325 
00326   if (STRUCTURE_ONLY)
00327   {
00328     cout << "Performing structure-only BA:"   << endl;
00329     structure_only_ba.setVerbose(true);
00330     structure_only_ba.calc(optimizer.vertices(),
00331                            10);
00332 
00333 
00334   }
00335 
00336     cout << endl;
00337   cout << "Performing full BA:" << endl;
00338   optimizer.optimize(10);
00339 
00340   cout << endl;
00341   cout << "Point error before optimisation (inliers only): " << sqrt(sum_diff2/point_num) << endl;
00342 
00343 
00344   point_num = 0;
00345   sum_diff2 = 0;
00346 
00347 
00348   for (tr1::unordered_map<int,int>::iterator it=pointid_2_trueid.begin();
00349        it!=pointid_2_trueid.end(); ++it)
00350   {
00351 
00352     g2o::HyperGraph::VertexIDMap::iterator v_it
00353         = optimizer.vertices().find(it->first);
00354 
00355     if (v_it==optimizer.vertices().end())
00356     {
00357       cerr << "Vertex " << it->first << " not in graph!" << endl;
00358       exit(-1);
00359     }
00360 
00361     g2o::VertexPointXYZ * v_p
00362         = dynamic_cast< g2o::VertexPointXYZ * > (v_it->second);
00363 
00364     if (v_p==0)
00365     {
00366       cerr << "Vertex " << it->first << "is not a PointXYZ!" << endl;
00367       exit(-1);
00368     }
00369 
00370     Vector3d diff = v_p->estimate()-true_points[it->second];
00371 
00372     if (inliers.find(it->first)==inliers.end())
00373       continue;
00374 
00375     sum_diff2 += diff.dot(diff);
00376 
00377     ++point_num;
00378   }
00379 
00380   cout << "Point error after optimisation (inliers only): " << sqrt(sum_diff2/point_num) << endl;
00381   cout << endl;
00382 
00383 }


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