Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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);
00162 Vector2d principal_point(320,240);
00163 double baseline = 0.075;
00164
00165
00166 vector<g2o::SE3Quat,
00167 aligned_allocator<g2o::SE3Quat> > true_poses;
00168
00169
00170 g2o::VertexSCam::setKcam(focal_length[0],focal_length[1],
00171 principal_point[0],principal_point[1],
00172 baseline);
00173
00174
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();
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
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));
00260 z(2) = z(0) - z(2);
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
00302
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 }