transformation_estimation.cpp
Go to the documentation of this file.
00001 #include "node.h"
00002 #include "scoped_timer.h"
00003 #include "transformation_estimation.h"
00004 //#include "g2o/core/graph_optimizer_sparse.h"
00005 #include "g2o/core/sparse_optimizer.h"
00006 #include "g2o/core/block_solver.h"
00007 #include "g2o/core/solver.h"
00008 #include "g2o/solvers/cholmod/linear_solver_cholmod.h"
00009 #include "g2o/types/icp/types_icp.h"
00010 
00011 #include "g2o/types/slam3d/se3quat.h"
00012 #include "g2o/types/slam3d/edge_se3_pointxyz_depth.h"
00013 #include "g2o/types/slam3d/vertex_pointxyz.h"
00014 #include "misc2.h" //Only for point_information_matrix. TODO: Move to misc2.h
00015 #include <Eigen/SVD>
00016 //TODO: Move these definitions and includes into a common header, g2o.h
00017 #include "g2o/core/estimate_propagator.h"
00018 //#include "g2o/core/factory.h"
00019 //#include "g2o/core/solver_factory.h"
00020 #include "g2o/core/hyper_dijkstra.h"
00021 #include "g2o/core/optimization_algorithm_gauss_newton.h"
00022 #include "g2o/core/optimization_algorithm_levenberg.h"
00023 #include "g2o/core/robust_kernel_impl.h"
00024 
00025 using namespace Eigen;
00026 using namespace std;
00027 using namespace g2o;
00028 
00029 typedef g2o::VertexPointXYZ  feature_vertex_type;
00030 typedef g2o::EdgeSE3PointXYZDepth feature_edge_type;
00031 //TODO: Make a class of this, with optimizerSetup being the constructor.
00032 //      getTransformFromMatchesG2O into a method for adding a node that 
00033 //      can be called as often as desired and one evaluation method.
00034 //      Needs to keep track of mapping (node id, feature id) -> vertex id
00035 
00037 void optimizerSetup(g2o::SparseOptimizer& optimizer){
00038   //optimizer.setMethod(g2o::SparseOptimizer::LevenbergMarquardt);
00039   //g2o::Optimizato
00040   optimizer.setVerbose(false);
00041 
00042   // variable-size block solver
00043   g2o::BlockSolverX::LinearSolverType * linearSolver
00044       = new g2o::LinearSolverCholmod<g2o ::BlockSolverX::PoseMatrixType>();
00045 
00046 
00047   g2o::BlockSolverX * solver_ptr
00048       = new g2o::BlockSolverX(linearSolver);
00049 
00050   g2o::OptimizationAlgorithmGaussNewton* solver = new g2o::OptimizationAlgorithmGaussNewton(solver_ptr);
00051   optimizer.setAlgorithm(solver);
00052   //optimizer.setSolver(solver_ptr);
00053 
00054   g2o::ParameterCamera* cameraParams = new g2o::ParameterCamera();
00055   //FIXME From Parameter server or cam calibration
00056   cameraParams->setKcam(521,521,319.5,239.5);
00057   g2o::SE3Quat offset; // identity
00058   cameraParams->setOffset(offset);
00059   cameraParams->setId(0);
00060   optimizer.addParameter(cameraParams);
00061 }
00062 
00063 //Second cam is fixed, therefore the transformation from the second to the first cam will be computed
00064 std::pair<g2o::VertexSE3*, g2o::VertexSE3*>  sensorVerticesSetup(g2o::SparseOptimizer& optimizer, Eigen::Matrix4f& tf_estimate){
00065     g2o::VertexSE3 *vc2 = new VertexSE3();
00066     {// set up rotation and translation for the newer node as identity
00067       Eigen::Quaterniond q(1,0,0,0);
00068       Eigen::Vector3d t(0,0,0);
00069       q.setIdentity();
00070       g2o::SE3Quat cam2(q,t);
00071 
00072       vc2->setEstimate(cam2);
00073       vc2->setId(1); 
00074       vc2->setFixed(true);
00075       optimizer.addVertex(vc2);
00076     }
00077 
00078     g2o::VertexSE3 *vc1 = new VertexSE3();
00079     {
00080       Eigen::Quaterniond q(tf_estimate.topLeftCorner<3,3>().cast<double>());//initialize rotation from estimate 
00081       Eigen::Vector3d t(tf_estimate.topRightCorner<3,1>().cast<double>());  //initialize translation from estimate
00082       g2o::SE3Quat cam1(q,t);
00083       vc1->setEstimate(cam1);
00084       vc1->setId(0);  
00085       optimizer.addVertex(vc1);
00086     }
00087 
00088     // add to optimizer
00089     return std::make_pair(vc1, vc2);
00090 }
00091 feature_edge_type* edgeToFeature(const Node* node, 
00092                               unsigned int feature_id,
00093                               g2o::VertexSE3* camera_vertex,
00094                               g2o::VertexPointXYZ* feature_vertex)
00095 {
00096    feature_edge_type* edge = new feature_edge_type();
00097    cv::KeyPoint kp = node->feature_locations_2d_[feature_id];
00098    Vector4f position = node->feature_locations_3d_[feature_id];
00099    float depth = position(2);
00100    if(!isnan(depth))
00101    {
00102      Eigen::Vector3d pix_d(kp.pt.x,kp.pt.y,depth);
00103      //ROS_INFO_STREAM("Edge from camera to position "<< pix_d.transpose());
00104      edge->setMeasurement(pix_d);
00105      Eigen::Matrix3d info_mat = point_information_matrix(depth);
00106      edge->setInformation(info_mat);
00107      feature_vertex->setEstimate(position.cast<double>().head<3>());
00108 
00109    } 
00110    else {//FIXME instead of using an arbitrary depth value and high uncertainty, use the correct vertex type (on the other hand Rainer suggested this proceeding too)
00111      Eigen::Vector3d pix_d(kp.pt.x,kp.pt.y,10.0);
00112      //ROS_INFO_STREAM("Edge from camera to position "<< pix_d.transpose());
00113      edge->setMeasurement(pix_d);
00114      Eigen::Matrix3d info_mat = point_information_matrix(10);//as uncertain as if it was ...meter away
00115      edge->setInformation(info_mat);
00116      feature_vertex->setEstimate(Eigen::Vector3d(position(0)*10, position(1)*10, 10.0));//Move from 1m to 10 m distance. Shouldn't matter much
00117    }
00118    edge->setParameterId(0,0);
00119    //edge->setRobustKernel(true);
00120    edge->vertices()[0] = camera_vertex;
00121    edge->vertices()[1] = feature_vertex;
00122 
00123    return edge;
00124 }
00126 void getTransformFromMatchesG2O(const Node* earlier_node,
00127                                 const Node* newer_node,
00128                                 const std::vector<cv::DMatch> & matches,
00129                                 Eigen::Matrix4f& transformation_estimate, //Input (initial guess) and Output
00130                                 int iterations)
00131 {
00132   ScopedTimer s(__FUNCTION__);
00133   //G2O Initialization
00134   g2o::SparseOptimizer* optimizer = new g2o::SparseOptimizer();//TODO: Speicherleck
00135   //Set parameters for icp optimizer
00136   optimizerSetup(*optimizer);
00137   //First camera is earlier_node, second camera is newer_node
00138   //Second cam is set to fixed, therefore the transformation from the second to the first cam will be computed
00139   std::pair<g2o::VertexSE3*, g2o::VertexSE3*> cams = sensorVerticesSetup(*optimizer, transformation_estimate);
00140 
00141   //std::vector<feature_vertex_type*> feature_vertices;
00142   int v_id = optimizer->vertices().size(); //0 and 1 are taken by sensor vertices
00143   //For each match, create a vertex and connect it to the sensor vertices with the measured position
00144   BOOST_FOREACH(const cv::DMatch& m, matches)
00145   {
00146     feature_vertex_type* v = new feature_vertex_type();//TODO: Speicherleck?
00147     v->setId(v_id++);
00148     v->setFixed(false);
00149 
00150     optimizer->addVertex(v);
00151     //feature_vertices.push_back(v);
00152 
00153     feature_edge_type* e1 = edgeToFeature(earlier_node, m.trainIdx, cams.first, v);
00154     optimizer->addEdge(e1);
00155 
00156     feature_edge_type* e2 = edgeToFeature(newer_node, m.queryIdx, cams.second, v);
00157     optimizer->addEdge(e2);
00158 
00159   }
00160   optimizer->initializeOptimization();
00161 
00162   ROS_INFO("Optimizer Size: %zu", optimizer->vertices().size());
00163   optimizer->optimize(iterations);
00164   optimizer->computeActiveErrors();
00165 
00166   //g2o::SE3Quat final_transformation =  cams.first->estimateAsSE3Quat().inverse();
00167   //transformation_estimate = final_transformation.to_homogeneous_matrix().cast<float>(); 
00168   transformation_estimate = cams.first->estimate().cast<float>().inverse().matrix();
00169   delete optimizer;
00170 }


rgbdslam_v2
Author(s): Felix Endres, Juergen Hess, Nikolas Engelhard
autogenerated on Thu Jun 6 2019 21:49:45