graph_opt.h
Go to the documentation of this file.
00001 //part of the source code of master thesis, source code produced by Jiri Divis
00008 #ifndef VSLAM_GRAPH_OPT_H_INCLUDED
00009 #define VSLAM_GRAPH_OPT_H_INCLUDED
00010 #include "utils.h"
00011 #include "pose_graph.h"
00012 
00013 #include "g2o_types/vertex_pose.h"
00014 #include "g2o_types/vertex_landmark.h"
00015 #include "g2o_types/edge_pose_landmark.h"
00016 
00017 #include <g2o/core/sparse_optimizer.h>
00018 #include <g2o/core/block_solver.h>
00019 #include <g2o/core/factory.h>
00020 #include <g2o/core/optimization_algorithm_factory.h>
00021 #include <g2o/core/optimization_algorithm_gauss_newton.h>
00022 #include <g2o/core/optimization_algorithm_levenberg.h>
00023 #include <g2o/solvers/csparse/linear_solver_csparse.h>
00024 #include <g2o/solvers/pcg/linear_solver_pcg.h>
00025 #include "g2o/solvers/dense/linear_solver_dense.h"
00026 #if defined G2O_HAVE_CHOLMOD
00027 #include "g2o/solvers/cholmod/linear_solver_cholmod.h"
00028 #elif defined G2O_HAVE_CSPARSE
00029 #include "g2o/solvers/csparse/linear_solver_csparse.h"
00030 #endif
00031 
00032 
00033 #include <boost/graph/dijkstra_shortest_paths.hpp>
00034 #include <iostream>
00035 #include <cmath>
00036 #include <tr1/functional>
00037 
00038 
00039 
00040 namespace vslam{
00041 /*------------------------------------------------------------------------------------------*/
00054 /*------------------------------------------------------------------------------------------*/
00055 /*------------------------------------------------------------------------------------------*/
00062 namespace g2o_types{}
00063 /*------------------------------------------------------------------------------------------*/
00064 
00070 template<class G> class G2OGraphBuilder{
00071     public:
00072         typedef typename graph_traits<G>::vertex_descriptor VDT;
00073 
00074         const int first_landmark_id;
00075         const double max_error;
00076 
00085         G2OGraphBuilder(int _first_landmark_id, double _max_error) : 
00086                 first_landmark_id(_first_landmark_id), max_error(_max_error) {
00087             
00088         }
00089 
00096         void operator()(g2o::SparseOptimizer& optimizer, G& g, Points<G>& points, VDT startv){
00097             buildGraphImpl(optimizer, g, points, startv);
00098         }
00099 
00100     private:
00101         virtual void buildGraphImpl(
00102                 g2o::SparseOptimizer& optimizer, G& g, Points<G>& points, VDT startv) = 0;
00103 };
00104 
00105 
00106 
00107 
00108 
00117 template<class G> class G2OConstActiveDistanceBuilder: public G2OGraphBuilder<G>{
00118     protected:
00119         typedef typename graph_traits<G>::vertex_iterator VertexItT;
00120         typedef typename graph_traits<G>::vertex_descriptor VertexD;
00121 
00122         const int active_window; 
00123     public:
00125         G2OConstActiveDistanceBuilder(int _first_landmark_id, double _max_error, int _active_window) : 
00126                 G2OGraphBuilder<G>(_first_landmark_id, _max_error), active_window(_active_window) { }
00127 
00128     private:
00129 
00131         struct Instance{
00132             g2o::SparseOptimizer& optimizer;
00133             G& g;
00134             Points<G>& points;
00135             vector<bool> point_added;
00136             std::vector<VertexD> added_vertices;
00137             vector<int> distances;
00138 
00139             Instance(g2o::SparseOptimizer& _opt, G& _g, Points<G>& _points, VertexD current_pose) : 
00140                     optimizer(_opt), g(_g), points(_points), point_added(_points.size(), false) {
00141                 typedef boost::iterator_property_map< 
00142                         vector<int>::iterator, 
00143                         typename boost::property_map< 
00144                                 G, 
00145                                 boost::vertex_index_t>::type> DistancePMap;
00146                 vector<int> _distances(num_vertices(g));
00147                 DistancePMap dmap(_distances.begin(), get(boost::vertex_index, g));
00148                 boost::dijkstra_shortest_paths(g, current_pose, 
00149                         boost::weight_map(AllWeightsOneWeightMap<G>()).distance_map(dmap));
00150                 distances=_distances;
00151             }
00152         };
00153 
00155         class PoseAgeCompare {
00156             private:
00157                 const G& g;
00158             public:
00159                 PoseAgeCompare(const G& _g) : g(_g) {}
00160 
00162                 bool operator()(VertexD a, VertexD b)
00163                 {   
00164                     return get(vertex_timestamp, g, a) > get(vertex_timestamp, g, b);
00165                 }   
00166         };
00167 
00175         void addLandmarkObservations(int lm_idx, Instance& instance){
00176             using namespace g2o_types;
00177             typedef std::pair<VertexD, int> FT;
00178             const Point<G> & lm = instance.points.getPoint(lm_idx);
00179             int added_fixed=0;
00180             for(int i=0; i< static_cast<int>(lm.seen_from.size()); i++){
00181                 FT fid = lm.seen_from[i];
00182                 double dist = instance.distances[get(boost::vertex_index, instance.g, fid.first)];
00183                 bool add=false;
00184                 if(dist <= active_window){
00185                     add=true;
00186                 } else{
00187                     if(dist <= 20){
00188                         if(added_fixed%1 == 0) add=true;
00189                         added_fixed++;
00190                     }
00191                 }
00192                 if(add){
00193                     vector<cv::KeyPoint> & keypoints = get(vertex_kp, instance.g, fid.first);
00194                     EdgeSE3PointXYZ<G>* observation =  new EdgeSE3PointXYZ<G>;
00195                     addPose(fid.first, instance, false);
00196                     observation->setVertex(
00197                             0,  instance.optimizer.vertex(get(vertex_seq, instance.g, fid.first)));
00198                     observation->setVertex(
00199                             1,  instance.optimizer.vertex(this->first_landmark_id+lm_idx));
00200                     observation->setMeasurement(
00201                             Vector2d(keypoints[fid.second].pt.x, keypoints[fid.second].pt.y));
00202                     observation->setInformation(Eigen::Matrix2d::Identity());
00203                     observation->computeError();
00204                     if((observation->error()).norm() <= this->max_error){
00205                         instance.optimizer.addEdge(observation);
00206                     } else{
00207                         ROS_WARN_STREAM_NAMED("Optimization", "encountered high error constraint(" 
00208                                 << (observation->error()).norm() << ")"); 
00209                         break;
00210                     }
00211                 }
00212             }
00213         }
00214 
00220         void addVisibleLandmarks(VertexD vertex, Instance& instance){
00221             using namespace g2o_types;
00222             vector<cv::KeyPoint> & keypoints = get(vertex_kp, instance.g, vertex);
00223             vector<int> & fixed_points = get(vertex_fix_idx, instance.g, vertex);
00224             for(size_t i = 0; i<keypoints.size(); i++){
00225                 if(fixed_points[i] != BAD_INDEX && 
00226                         instance.points.getPoint(fixed_points[i]).initialized){
00227                     if(!instance.point_added[fixed_points[i]]){
00228                         VertexPointXYZ<G>* feature_landmark = 
00229                                 new VertexPointXYZ<G>(fixed_points[i], instance.points);
00230                         feature_landmark->setId(this->first_landmark_id+fixed_points[i]);
00231                         feature_landmark->setEstimate(
00232                                 instance.points.getPoint(fixed_points[i]).global);
00233                         feature_landmark->setFixed(false);
00234                         instance.optimizer.addVertex(feature_landmark);
00235                         instance.point_added[fixed_points[i]]=true;
00236                         addLandmarkObservations(fixed_points[i], instance);
00237                     }
00238                 }
00239             }
00240         }
00241 
00247         void addPose(VertexD vertex, Instance& instance, bool add_lms){
00248             using namespace g2o_types;
00249             if(!instance.optimizer.vertex(get(vertex_seq, instance.g, vertex))){
00250                 VertexSE3<G>* camera_pose=
00251                     new VertexSE3<G>(instance.g, vertex);
00252                 camera_pose->setId(get(vertex_seq, instance.g, vertex));
00253                 camera_pose->setEstimate(get(vertex_transform, instance.g, vertex));
00254                 camera_pose->setFixed(true);
00255                 instance.optimizer.addVertex(camera_pose);
00256                 if(add_lms) addVisibleLandmarks(vertex, instance);
00257                 ROS_INFO_STREAM_NAMED("Optimization", "Added vertex " << 
00258                          get(vertex_seq, instance.g, vertex) << " keyframe flag: " << 
00259                          get(vertex_keyframe_flag, instance.g, vertex));
00260                 instance.added_vertices.push_back(vertex);
00261             }
00262         }
00263 
00265         void setPoseFixed(VertexD vertex, Instance& instance, bool fixed){
00266             instance.optimizer.vertex(get(vertex_seq, instance.g, vertex))->setFixed(fixed);
00267         }
00268 
00269         virtual void buildGraphImpl(
00270                 g2o::SparseOptimizer& optimizer, G& g, Points<G>& points, VertexD startv){
00271             Instance instance(optimizer, g, points, startv);
00272 
00273             VertexItT vertex_it, vertex_it_end;
00274             tie(vertex_it, vertex_it_end) = vertices(instance.g);
00275             while(vertex_it != vertex_it_end){
00276                 int dist = instance.distances[get(boost::vertex_index, instance.g, *vertex_it)];
00277                 if(dist <= active_window){
00278                     addPose(*vertex_it, instance, true);
00279                     setPoseFixed(*vertex_it, instance, false);
00280                     instance.added_vertices.push_back(*vertex_it);
00281                     ROS_INFO_STREAM_NAMED("Optimization", "Marked vertex " << 
00282                              get(vertex_seq, instance.g, *vertex_it) << " as optimizable.");
00283                 }
00284                 ++vertex_it;
00285             }
00286             std::sort(instance.added_vertices.begin(), instance.added_vertices.end(), 
00287                     PoseAgeCompare(instance.g));
00288             int tmp = static_cast<int>(instance.added_vertices.size());
00289             for(int i=tmp-2; i< tmp ; i++){
00290                 setPoseFixed(instance.added_vertices[i], instance, true);
00291             }
00292         }
00293 };
00294 
00295 
00297 template<class G> class G2ORunner2{
00298     protected:
00299         typedef typename graph_traits<G>::vertex_descriptor VertexD;
00300         g2o::SparseOptimizer optimizer;
00301 
00302     public:
00303         G2ORunner2(){
00304             using namespace g2o;
00305             typedef BlockSolver< BlockSolverTraits<Eigen::Dynamic, Eigen::Dynamic> >  SlamBlockSolver;
00306             typedef LinearSolverCSparse<SlamBlockSolver::PoseMatrixType> SlamLinearSolver;
00307             //typedef LinearSolverPCG<SlamBlockSolver::PoseMatrixType> SlamLinearSolver;
00308             //typedef LinearSolverCholmod<SlamBlockSolver::PoseMatrixType> SlamLinearSolver;
00309             //typedef LinearSolverDense<SlamBlockSolver::PoseMatrixType> SlamLinearSolver;
00310 
00311             SlamLinearSolver* linearSolver = new SlamLinearSolver();
00312             linearSolver->setBlockOrdering(false);
00313             SlamBlockSolver* blockSolver = new SlamBlockSolver(linearSolver);
00314             blockSolver->setSchur(false);
00315             //OptimizationAlgorithmGaussNewton* solver = 
00316             //        new OptimizationAlgorithmGaussNewton(blockSolver);
00317             OptimizationAlgorithmLevenberg* solver = 
00318                     new OptimizationAlgorithmLevenberg(blockSolver);
00319 
00320             optimizer.setAlgorithm(solver);
00321             optimizer.setComputeBatchStatistics(false);
00322         }
00323 
00324     public:
00325 
00333         virtual void doOptimalization(
00334                 G& _g, 
00335                 Points<G>& _points,
00336                 G2OGraphBuilder<G> & builder,
00337                 VertexD startv){
00338             using namespace g2o_types;
00339             PerformanceLogger<G> pl(_g, startv, "opt");
00340 
00341             ROS_INFO_NAMED("Optimization", "Building pose graph ... ");
00342             builder(optimizer,_g,_points,startv);
00343  
00344             optimizer.setVerbose(false);
00345             ROS_INFO_NAMED("Optimization", 
00346                     "Running 15 iterations of the optimalization algorithm ... ");
00347             optimizer.initializeOptimization();
00348             //optimizer.setSchur(true);
00349             optimizer.optimize(15);
00350 
00351             g2o::OptimizableGraph::EdgeContainer all_edges = optimizer.activeEdges();
00352             double max_error=0;
00353             BOOST_FOREACH(g2o::OptimizableGraph::Edge* edge_tmp, all_edges){
00354                 EdgeSE3PointXYZ<G>* edge = 
00355                         dynamic_cast<EdgeSE3PointXYZ<G>*>(edge_tmp);
00356                 edge->computeError();
00357                 if(edge->error().norm() > max_error) max_error=edge->error().norm();
00358                 double err_tolerance = builder.max_error;
00359                 if((edge->error()).norm() >= err_tolerance){
00360                     ROS_WARN_STREAM_NAMED("Optimization", "high error edge detecded, error norm: " 
00361                         << (edge->error()).norm() << " errror tolerance: " << err_tolerance);
00362                 }
00363             }
00364             ROS_INFO_STREAM_NAMED("Optimization", "Optimization done. Final chi2 is " <<
00365                 optimizer.chi2() << "; Maximal error is "<<max_error << "; Number of edges: " <<
00366                 optimizer.activeEdges().size());
00367             get(vertex_debug_info, _g, startv).double_propmap["opt_chi2"]= optimizer.chi2();
00368             get(vertex_debug_info, _g, startv).double_propmap["max_opt_error"]= max_error;
00369             optimizer.clear(); //clears g2o graph ands saves optimalization results
00370         }
00371 };
00372 
00373 
00374 
00376 }//namespace vslam
00377 
00378 
00379 
00380 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines


pose_estimation
Author(s): Jiri Divis/jiridivis@gmail.com
autogenerated on Wed Mar 27 2013 21:00:12