SRBA: Sparser Relative Bundle Adjustment
/home/travis/build/MRPT/srba/examples/cpp/tutorial-srba-stereo-se3.cpp
00001 /* +---------------------------------------------------------------------------+
00002    |                     Mobile Robot Programming Toolkit (MRPT)               |
00003    |                          http://www.mrpt.org/                             |
00004    |                                                                           |
00005    | Copyright (c) 2005-2015, Individual contributors, see AUTHORS file        |
00006    | See: http://www.mrpt.org/Authors - All rights reserved.                   |
00007    | Released under BSD License. See details in http://www.mrpt.org/License    |
00008    +---------------------------------------------------------------------------+ */
00009 
00010 #include <srba.h>
00011 #include <mrpt/gui.h>  // For rendering results as a 3D scene
00012 
00013 using namespace srba;
00014 using namespace std;
00015 using mrpt::utils::DEG2RAD;
00016 
00017 struct RBA_OPTIONS : public RBA_OPTIONS_DEFAULT
00018 {
00019 //  typedef ecps::local_areas_fixed_size            edge_creation_policy_t;  //!< One of the most important choices: how to construct the relative coordinates graph problem
00020     typedef options::sensor_pose_on_robot_se3        sensor_pose_on_robot_t;
00021     typedef options::observation_noise_identity      obs_noise_matrix_t;      // The sensor noise matrix is the same for all observations and equal to \sigma * I(identity)
00022 //  typedef options::solver_LM_schur_dense_cholesky solver_t;                //!< Solver algorithm (Default: Lev-Marq, with Schur, with dense Cholesky)
00023 };
00024 
00025 typedef RbaEngine<
00026     kf2kf_poses::SE3,              // Parameterization  of KF-to-KF poses
00027     landmarks::Euclidean3D,        // Parameterization of landmark positions
00028     observations::StereoCamera, // Type of observations
00029     RBA_OPTIONS
00030     >  my_srba_t;
00031 
00032 // --------------------------------------------------------------------------------
00033 // A test dataset (generated with https://github.com/jlblancoc/recursive-world-toolkit )
00034 // --------------------------------------------------------------------------------
00035 struct basic_stereo_dataset_entry_t
00036 {
00037     unsigned int landmark_id;
00038     double l_px_x, l_px_y, r_px_x, r_px_y;
00039 };
00040 // Observations for KF#0: 0.000000 0.000000 0.000000 0.564787 -0.517532 0.434261 -0.473913
00041 const mrpt::poses::CPose3DQuat GT_pose0(0,0,0, mrpt::math::CQuaternionDouble(0.564787, -0.517532, 0.434261, -0.473913));
00042 basic_stereo_dataset_entry_t  dataset0[] = {
00043  {   146,  509.16046143,  437.46981812,  487.56234741,  437.46981812},
00044  {   144,  437.15927124,  483.60800171,  415.72924805,  483.60800171},
00045  {   119,  717.74304199,   10.41780090,  671.35614014,   10.41780090},
00046  {   118,  303.95758057,  452.25698853,  279.69769287,  452.25698853},
00047  {    55,  668.79144287,  462.95404053,  647.50024414,  462.95404053},
00048  {    64,  942.45770264,  482.42794800,  905.10852051,  482.42794800},
00049  {    39,  539.63507080,  412.02212524,  524.38378906,  412.02212524},
00050  {    35,  515.34265137,  418.47946167,  501.14129639,  418.47946167},
00051  {   114,  251.08596802,  143.94938660,  219.89593506,  143.94938660},
00052  {    20,  131.02098083,  441.55328369,  101.34998322,  441.55328369},
00053  {    63,  130.22460938,   40.40441895,   88.11344147,   40.40441895},
00054  {    28,  549.69879150,  422.24081421,  536.64208984,  422.24081421},
00055  {    52,  285.58596802,  311.38674927,  266.17193604,  311.38674927},
00056  {   141,  602.49987793,  447.69750977,  588.13580322,  447.69750977},
00057  {    84,  397.96939087,  377.29605103,  384.32940674,  377.29605103},
00058  {    76,  560.31323242,  382.84091187,  548.23840332,  382.84091187},
00059  {    71,  511.07693481,  305.64028931,  498.33679199,  305.64028931},
00060  {    95,  489.02133179,  574.60296631,  471.31988525,  574.60296631},
00061  {    37,  597.42114258,  345.28842163,  585.29571533,  345.28842163},
00062  {    18,  872.09954834,  508.56875610,  848.17993164,  508.56875610},
00063  {   100,  274.51089478,  287.06481934,  257.16955566,  287.06481934},
00064  {   127,  405.27337646,  466.33535767,  392.28976440,  466.33535767},
00065  {   115,  298.95901489,  357.22961426,  283.78897095,  357.22961426},
00066  {    59,  604.91369629,  384.71456909,  593.73840332,  384.71456909},
00067  {     6,  604.14477539,  436.54782104,  593.01409912,  436.54782104},
00068  {   113,  410.54818726,  411.51428223,  399.81372070,  411.51428223},
00069  {    99,  321.10958862,  432.39556885,  307.92941284,  432.39556885},
00070  {   128,  452.99237061,  360.34350586,  443.32141113,  360.34350586},
00071  {    86,  482.48013306,  347.64862061,  473.00042725,  347.64862061},
00072  {    30,  995.84106445,  405.77438354,  973.26440430,  405.77438354},
00073  {    13,  485.14672852,  439.37075806,  475.89678955,  439.37075806},
00074  {   148,  880.86297607,  206.19326782,  860.58264160,  206.19326782},
00075 };
00076 // Observations for KF#10. 1.226071 0.293637 0.110099 0.521317 -0.478835 0.477946 -0.520108
00077 const mrpt::poses::CPose3DQuat GT_pose10(1.226071, 0.293637, 0.110099, mrpt::math::CQuaternionDouble(0.521317, -0.478835, 0.477946, -0.520108));
00078 basic_stereo_dataset_entry_t  dataset1[] = {
00079  {   146,  491.26168823,  551.57379150,  423.40914917,  551.57379150},
00080  {    39,  539.21508789,  436.04541016,  510.94876099,  436.04541016},
00081  {   144,  212.05824280,  760.23156738,  130.36854553,  760.23156738},
00082  {    35,  492.21871948,  446.14865112,  466.45300293,  446.14865112},
00083  {    55,  834.35400391,  557.37854004,  788.51184082,  557.37854004},
00084  {    28,  546.43200684,  446.28805542,  525.22998047,  446.28805542},
00085  {    76,  559.35211182,  382.55627441,  540.91125488,  382.55627441},
00086  {    84,  241.46690369,  366.48257446,  212.30659485,  366.48257446},
00087  {   141,  632.18359375,  487.72677612,  609.05029297,  487.72677612},
00088  {    71,  486.61346436,  251.04017639,  465.07601929,  251.04017639},
00089  {    37,  611.87152100,  328.35580444,  594.16027832,  328.35580444},
00090  {    59,  614.13189697,  385.92330933,  598.62408447,  385.92330933},
00091  {   127,  265.42541504,  547.43658447,  239.19529724,  547.43658447},
00092  {   113,  302.50097656,  429.91296387,  283.61132813,  429.91296387},
00093  {   128,  389.86721802,  345.30511475,  374.68167114,  345.30511475},
00094  {     6,  611.41735840,  457.71142578,  595.99652100,  457.71142578},
00095  {    86,  438.98941040,  328.56036377,  424.79483032,  328.56036377},
00096  {    13,  440.80871582,  464.69479370,  427.16564941,  464.69479370},
00097  {    26,  546.39410400,  371.82641602,  535.95281982,  371.82641602},
00098  {    77,  487.84552002,  382.68484497,  477.85519409,  382.68484497},
00099  {    66,  200.29261780,  398.92413330,  182.15275574,  398.92413330},
00100  {    97,  390.99511719,  399.05416870,  379.56640625,  399.05416870},
00101  {    32,  558.65643311,  375.37698364,  548.65789795,  375.37698364},
00102  {     3,  568.27807617,  334.56246948,  557.75860596,  334.56246948},
00103  {    94,  216.95486450,  207.21980286,  196.44139099,  207.21980286},
00104  {   105,  422.90161133,  424.59942627,  412.17526245,  424.59942627},
00105  {    24,  375.15139771,  291.60083008,  362.73464966,  291.60083008},
00106  {     1,  705.76177979,  346.89096069,  692.97778320,  346.89096069},
00107  {    12,  422.85137939,  393.76672363,  413.06048584,  393.76672363},
00108  {   132,  407.56420898,  505.53576660,  395.41671753,  505.53576660},
00109  {    74,  195.35592651,  543.41839600,  176.65670776,  543.41839600},
00110  {   106,  735.83538818,  419.90661621,  723.00628662,  419.90661621},
00111  {    81,  627.14727783,  411.86691284,  617.46148682,  411.86691284},
00112  {     2,  425.69473267,  355.24987793,  416.55752563,  355.24987793},
00113  {    85,  368.50869751,  435.69857788,  358.13888550,  435.69857788},
00114  {   121,  690.39721680,  402.24075317,  679.54412842,  402.24075317},
00115 };
00116 
00117 int main(int argc, char**argv)
00118 {
00119     my_srba_t rba;     //  Create an empty RBA problem
00120 
00121     // --------------------------------------------------------------------------------
00122     // Set parameters
00123     // --------------------------------------------------------------------------------
00124     rba.setVerbosityLevel( 1 );   // 0: None; 1:Important only; 2:Verbose
00125 
00126     rba.parameters.srba.use_robust_kernel = true;
00127     rba.parameters.obs_noise.std_noise_observations = 0.5; // pixels
00128 
00129     // =========== Topology parameters ===========
00130     rba.parameters.srba.max_tree_depth       = 3;
00131     rba.parameters.srba.max_optimize_depth   = 3;
00132     // ===========================================
00133 
00134     // Set camera calib:
00135     mrpt::utils::TCamera & lc = rba.parameters.sensor.camera_calib.leftCamera;
00136     lc.ncols = 1024;
00137     lc.nrows = 768;
00138     lc.cx(512);
00139     lc.cy(384);
00140     lc.fx(200);
00141     lc.fy(150);
00142     lc.dist.setZero();
00143     rba.parameters.sensor.camera_calib.rightCamera = lc;
00144     rba.parameters.sensor.camera_calib.rightCameraPose.fromString("[0.2 0 0  1 0 0 0]");  // [X Y Z qr qx qy qz]
00145 
00146     // Sensor pose on the robot parameters:
00147     rba.parameters.sensor_pose.relative_pose = mrpt::poses::CPose3D(0,0,0,DEG2RAD(-90),DEG2RAD(0),DEG2RAD(-90) ); // Set camera pointing forwards (camera's +Z is robot +X)
00148 
00149     // Alternatively, parameters can be loaded from an .ini-like config file
00150     // -----------------------------------------------------------------------
00151     // rba.parameters.loadFromConfigFileName("config_file.cfg", "srba");
00152     //rba.sensor_params.camera_calib.loadFromConfigFile("CAMERA","config_file.cfg");
00153 
00154     // --------------------------------------------------------------------------------
00155     // Dump parameters to console (for checking/debugging only)
00156     // --------------------------------------------------------------------------------
00157     //cout << "RBA parameters:\n-----------------\n";
00158     //rba.parameters.dumpToConsole();
00159 
00160     // --------------------------------------------------------------------------------
00161     // Define observations of KF #0:
00162     // --------------------------------------------------------------------------------
00163     my_srba_t::new_kf_observations_t  list_obs;
00164     my_srba_t::new_kf_observation_t   obs_field;
00165 
00166     obs_field.is_fixed = false;   // Landmarks have unknown relative positions (i.e. treat them as unknowns to be estimated)
00167 #if 1
00168     obs_field.is_unknown_with_init_val = false; // We don't have any guess on the initial LM position (will invoke the inverse sensor model)
00169 #else
00170     obs_field.is_unknown_with_init_val = true;      // Set default relative position of unknown new landmarks...
00171     obs_field.setRelPos( mrpt::math::TPoint3D(0.,0.,1.) ); // ...to (x,y,z)=(0,0,1), in front of the camera.
00172 #endif
00173 
00174     for (size_t i=0;i<sizeof(dataset0)/sizeof(dataset0[0]);i++)
00175     {
00176         obs_field.obs.feat_id = dataset0[i].landmark_id;
00177         obs_field.obs.obs_data.left_px.x = dataset0[i].l_px_x;
00178         obs_field.obs.obs_data.left_px.y = dataset0[i].l_px_y;
00179         obs_field.obs.obs_data.right_px.x = dataset0[i].r_px_x;
00180         obs_field.obs.obs_data.right_px.y = dataset0[i].r_px_y;
00181         list_obs.push_back( obs_field );
00182     }
00183 
00184 
00185     //  Here happens the main stuff: create Key-frames, build structures, run optimization, etc.
00186     //  ============================================================================================
00187     my_srba_t::TNewKeyFrameInfo new_kf_info;
00188     rba.define_new_keyframe(
00189         list_obs,      // Input observations for the new KF
00190         new_kf_info,   // Output info
00191         true           // Also run local optimization?
00192         );
00193 
00194     cout << "Created KF #" << new_kf_info.kf_id
00195         << " | # kf-to-kf edges created:" <<  new_kf_info.created_edge_ids.size()  << endl
00196         << "Optimization error: " << new_kf_info.optimize_results.total_sqr_error_init << " -> " << new_kf_info.optimize_results.total_sqr_error_final << endl
00197         << "-------------------------------------------------------" << endl;
00198 
00199 
00200     // --------------------------------------------------------------------------------
00201     // Define observations of KF #1:
00202     // --------------------------------------------------------------------------------
00203     list_obs.clear();
00204 
00205     for (size_t i=0;i<sizeof(dataset1)/sizeof(dataset1[0]);i++)
00206     {
00207         obs_field.obs.feat_id = dataset1[i].landmark_id;
00208         obs_field.obs.obs_data.left_px.x = dataset1[i].l_px_x;
00209         obs_field.obs.obs_data.left_px.y = dataset1[i].l_px_y;
00210         obs_field.obs.obs_data.right_px.x = dataset1[i].r_px_x;
00211         obs_field.obs.obs_data.right_px.y = dataset1[i].r_px_y;
00212         list_obs.push_back( obs_field );
00213     }
00214 
00215     //  Here happens the main stuff: create Key-frames, build structures, run optimization, etc.
00216     //  ============================================================================================
00217     rba.define_new_keyframe(
00218         list_obs,      // Input observations for the new KF
00219         new_kf_info,   // Output info
00220         true           // Also run local optimization?
00221         );
00222 
00223     cout << "Created KF #" << new_kf_info.kf_id
00224         << " | # kf-to-kf edges created:" <<  new_kf_info.created_edge_ids.size() << endl
00225         << "Optimization error: " << new_kf_info.optimize_results.total_sqr_error_init << " -> " << new_kf_info.optimize_results.total_sqr_error_final << endl
00226         << "-------------------------------------------------------" << endl;
00227 
00228 
00229     // Dump the relative pose of KF#0 wrt KF#1:
00230     cout << "inv_pose of KF-to-KF edge #0 (relative pose of KF#0 wrt KF#1):\n" << rba.get_k2k_edges()[0].inv_pose << endl;
00231     cout << "Relative pose of KF#1 wrt KF#0:\n" << (-rba.get_k2k_edges()[0].inv_pose) << endl;
00232 
00233     // Compare to ground truth:
00234     cout << "Ground truth: relative pose of KF#1 wrt KF#0: \n" << mrpt::poses::CPose3D(GT_pose10-GT_pose0) << endl;
00235 
00236     // --------------------------------------------------------------------------------
00237     // Saving RBA graph as a DOT file:
00238     // --------------------------------------------------------------------------------
00239     const string sFil = "graph.dot";
00240     cout << "Saving final graph of KFs and LMs to: " << sFil << endl;
00241     rba.save_graph_as_dot(sFil, true /* LMs=save */);
00242     cout << "Done.\n";
00243 
00244     // --------------------------------------------------------------------------------
00245     // Show 3D view of the resulting map:
00246     // --------------------------------------------------------------------------------
00247     my_srba_t::TOpenGLRepresentationOptions  opengl_options;
00248     mrpt::opengl::CSetOfObjectsPtr rba_3d = mrpt::opengl::CSetOfObjects::Create();
00249 
00250     rba.build_opengl_representation(
00251         0,  // Root KF,
00252         opengl_options, // Rendering options
00253         rba_3d  // Output scene
00254         );
00255 
00256     // Display:
00257 #if MRPT_HAS_WXWIDGETS
00258     mrpt::gui::CDisplayWindow3D win("RBA results",640,480);
00259     {
00260         mrpt::opengl::COpenGLScenePtr &scene = win.get3DSceneAndLock();
00261         scene->insert(rba_3d);
00262         win.unlockAccess3DScene();
00263     }
00264     win.setCameraZoom( 4 );
00265     win.repaint();
00266 
00267     cout << "Press any key or close window to exit.\n";
00268     win.waitForKey();
00269 #endif
00270 
00271     return 0; // All ok
00272 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends