SRBA: Sparser Relative Bundle Adjustment
|
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 #include <mrpt/random.h> // For rendering results as a 3D scene 00013 00014 using namespace srba; 00015 using namespace mrpt::random; 00016 using namespace std; 00017 using mrpt::utils::DEG2RAD; 00018 00019 struct RBA_OPTIONS : public RBA_OPTIONS_DEFAULT 00020 { 00021 // typedef ecps::local_areas_fixed_size edge_creation_policy_t; //!< One of the most important choices: how to construct the relative coordinates graph problem 00022 typedef options::sensor_pose_on_robot_se3 sensor_pose_on_robot_t; 00023 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) 00024 // typedef options::solver_LM_schur_dense_cholesky solver_t; //!< Solver algorithm (Default: Lev-Marq, with Schur, with dense Cholesky) 00025 }; 00026 00027 typedef RbaEngine< 00028 kf2kf_poses::SE3, // Parameterization of KF-to-KF poses 00029 landmarks::Euclidean3D, // Parameterization of landmark positions 00030 observations::MonocularCamera, // Type of observations 00031 RBA_OPTIONS 00032 > my_srba_t; 00033 00034 // -------------------------------------------------------------------------------- 00035 // A test dataset. Generated with https://github.com/jlblancoc/recursive-world-toolkit 00036 // and the script: tutorials_dataset-monocular.cfg 00037 // -------------------------------------------------------------------------------- 00038 const double SENSOR_NOISE_STD = 1e-4; 00039 00040 struct basic_monocular_dataset_entry_t 00041 { 00042 unsigned int landmark_id; 00043 double px_x, px_y; 00044 }; 00045 // Observations for KF#0: GT_Pose= 0.000000 0.000000 0.000000 0.564787 -0.517532 0.434261 -0.473913 00046 basic_monocular_dataset_entry_t dataset0[] = { 00047 { 146, 397.16046143, 371.29309082}, 00048 { 144, 325.15927124, 432.81069946}, 00049 { 118, 191.95759583, 391.00930786}, 00050 { 55, 556.79144287, 405.27206421}, 00051 { 39, 427.63507080, 337.36282349}, 00052 { 35, 403.34268188, 345.97265625}, 00053 { 20, 19.02102661, 376.73773193}, 00054 { 28, 437.69879150, 350.98776245}, 00055 { 52, 173.58599854, 203.18234253}, 00056 { 141, 490.49987793, 384.93002319}, 00057 { 84, 285.96942139, 291.06143188}, 00058 { 76, 448.31323242, 298.45452881}, 00059 { 71, 399.07693481, 195.52038574}, 00060 { 37, 485.42114258, 248.38455200}, 00061 { 100, 162.51091003, 170.75312805}, 00062 { 127, 293.27337646, 409.78048706}, 00063 { 115, 186.95903015, 264.30618286}, 00064 { 59, 492.91369629, 300.95275879}, 00065 { 6, 492.14477539, 370.06378174}, 00066 { 113, 298.54818726, 336.68572998}, 00067 { 99, 209.10960388, 364.52743530}, 00068 { 128, 340.99240112, 268.45800781}, 00069 { 86, 370.48016357, 251.53149414}, 00070 { 13, 373.14675903, 373.82769775} 00071 }; 00072 // Observations for KF#10: GT_Pose = 1.226072 0.293638 0.110099 0.521317 -0.478835 0.477946 -0.520108 00073 basic_monocular_dataset_entry_t dataset1[] = { 00074 { 39, 427.21511841, 369.39392090}, 00075 { 35, 380.21871948, 382.86489868}, 00076 { 28, 434.43206787, 383.05078125}, 00077 { 76, 447.35217285, 298.07504272}, 00078 { 84, 129.46676636, 276.64343262}, 00079 { 141, 520.18365479, 438.30242920}, 00080 { 71, 374.61349487, 122.72018433}, 00081 { 37, 499.87155151, 225.80770874}, 00082 { 59, 502.13192749, 302.56442261}, 00083 { 113, 190.50091553, 361.21731567}, 00084 { 128, 277.86718750, 248.40679932}, 00085 { 6, 499.41741943, 398.28195190}, 00086 { 86, 326.98937988, 226.08045959}, 00087 { 13, 328.80868530, 407.59310913}, 00088 { 26, 434.39413452, 283.76858521}, 00089 { 77, 375.84552002, 298.24645996}, 00090 { 66, 88.29249573, 319.89883423}, 00091 { 97, 278.99508667, 320.07223511}, 00092 { 32, 446.65643311, 288.50265503}, 00093 { 3, 456.27807617, 234.08326721}, 00094 { 94, 104.95476532, 64.29298401}, 00095 { 105, 310.90158081, 354.13259888}, 00096 { 24, 263.15136719, 176.80107117}, 00097 { 1, 593.76177979, 250.52128601}, 00098 { 12, 310.85137939, 313.02230835}, 00099 { 132, 295.56417847, 462.04772949}, 00100 { 106, 623.83544922, 347.87551880}, 00101 { 81, 515.14727783, 337.15591431}, 00102 { 2, 313.69470215, 261.66650391}, 00103 { 85, 256.50866699, 368.93145752}, 00104 { 121, 578.39721680, 324.32101440}, 00105 }; 00106 00107 int main(int argc, char**argv) 00108 { 00109 my_srba_t rba; // Create an empty RBA problem 00110 00111 // -------------------------------------------------------------------------------- 00112 // Set parameters 00113 // -------------------------------------------------------------------------------- 00114 rba.setVerbosityLevel( 2 ); // 0: None; 1:Important only; 2:Verbose 00115 00116 rba.parameters.srba.use_robust_kernel = true; 00117 rba.parameters.obs_noise.std_noise_observations = 0.5; // pixels 00118 00119 // =========== Topology parameters =========== 00120 rba.parameters.srba.max_tree_depth = 3; 00121 rba.parameters.srba.max_optimize_depth = 3; 00122 // =========================================== 00123 00124 // Set camera calib: 00125 mrpt::utils::TCamera & c = rba.parameters.sensor.camera_calib; 00126 c.ncols = 800; 00127 c.nrows = 640; 00128 c.cx(400); 00129 c.cy(320); 00130 c.fx(200); 00131 c.fy(200); 00132 c.dist.setZero(); 00133 00134 // Sensor pose on the robot parameters: 00135 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) 00136 00137 // Alternatively, parameters can be loaded from an .ini-like config file 00138 // ----------------------------------------------------------------------- 00139 // rba.parameters.loadFromConfigFileName("config_file.cfg", "srba"); 00140 //rba.sensor_params.camera_calib.loadFromConfigFile("CAMERA","config_file.cfg"); 00141 00142 // -------------------------------------------------------------------------------- 00143 // Dump parameters to console (for checking/debugging only) 00144 // -------------------------------------------------------------------------------- 00145 //cout << "RBA parameters:\n-----------------\n"; 00146 //rba.parameters.dumpToConsole(); 00147 00148 // -------------------------------------------------------------------------------- 00149 // Define observations of KF #0: 00150 // -------------------------------------------------------------------------------- 00151 my_srba_t::new_kf_observations_t list_obs; 00152 my_srba_t::new_kf_observation_t obs_field; 00153 00154 obs_field.is_fixed = false; // Landmarks have unknown relative positions (i.e. treat them as unknowns to be estimated) 00155 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) 00156 00157 for (size_t i=0;i<sizeof(dataset0)/sizeof(dataset0[0]);i++) 00158 { 00159 obs_field.obs.feat_id = dataset0[i].landmark_id; 00160 obs_field.obs.obs_data.px.x = dataset0[i].px_x + randomGenerator.drawGaussian1D(0,SENSOR_NOISE_STD); 00161 obs_field.obs.obs_data.px.y = dataset0[i].px_y + randomGenerator.drawGaussian1D(0,SENSOR_NOISE_STD); 00162 list_obs.push_back( obs_field ); 00163 } 00164 00165 00166 // Here happens the main stuff: create Key-frames, build structures, run optimization, etc. 00167 // ============================================================================================ 00168 my_srba_t::TNewKeyFrameInfo new_kf_info; 00169 rba.define_new_keyframe( 00170 list_obs, // Input observations for the new KF 00171 new_kf_info, // Output info 00172 true // Also run local optimization? 00173 ); 00174 00175 cout << "Created KF #" << new_kf_info.kf_id 00176 << " | # kf-to-kf edges created:" << new_kf_info.created_edge_ids.size() << endl 00177 << "Optimization error: " << new_kf_info.optimize_results.total_sqr_error_init << " -> " << new_kf_info.optimize_results.total_sqr_error_final << endl 00178 << "-------------------------------------------------------" << endl; 00179 00180 00181 // -------------------------------------------------------------------------------- 00182 // Define observations of KF #1: 00183 // -------------------------------------------------------------------------------- 00184 list_obs.clear(); 00185 00186 for (size_t i=0;i<sizeof(dataset1)/sizeof(dataset1[0]);i++) 00187 { 00188 obs_field.obs.feat_id = dataset1[i].landmark_id; 00189 obs_field.obs.obs_data.px.x = dataset1[i].px_x + randomGenerator.drawGaussian1D(0,SENSOR_NOISE_STD); 00190 obs_field.obs.obs_data.px.y = dataset1[i].px_y + randomGenerator.drawGaussian1D(0,SENSOR_NOISE_STD); 00191 list_obs.push_back( obs_field ); 00192 } 00193 00194 // Here happens the main stuff: create Key-frames, build structures, run optimization, etc. 00195 // ============================================================================================ 00196 rba.define_new_keyframe( 00197 list_obs, // Input observations for the new KF 00198 new_kf_info, // Output info 00199 true // Also run local optimization? 00200 ); 00201 00202 cout << "Created KF #" << new_kf_info.kf_id 00203 << " | # kf-to-kf edges created:" << new_kf_info.created_edge_ids.size() << endl 00204 << "Optimization error: " << new_kf_info.optimize_results.total_sqr_error_init << " -> " << new_kf_info.optimize_results.total_sqr_error_final << endl 00205 << "-------------------------------------------------------" << endl; 00206 00207 00208 // Dump the relative pose of KF#0 wrt KF#1: 00209 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; 00210 00211 // -------------------------------------------------------------------------------- 00212 // Saving RBA graph as a DOT file: 00213 // -------------------------------------------------------------------------------- 00214 const string sFil = "graph.dot"; 00215 cout << "Saving final graph of KFs and LMs to: " << sFil << endl; 00216 rba.save_graph_as_dot(sFil, true /* LMs=save */); 00217 cout << "Done.\n"; 00218 00219 // -------------------------------------------------------------------------------- 00220 // Show 3D view of the resulting map: 00221 // -------------------------------------------------------------------------------- 00222 my_srba_t::TOpenGLRepresentationOptions opengl_options; 00223 mrpt::opengl::CSetOfObjectsPtr rba_3d = mrpt::opengl::CSetOfObjects::Create(); 00224 00225 rba.build_opengl_representation( 00226 0, // Root KF, 00227 opengl_options, // Rendering options 00228 rba_3d // Output scene 00229 ); 00230 00231 // Display: 00232 #if MRPT_HAS_WXWIDGETS 00233 mrpt::gui::CDisplayWindow3D win("RBA results",640,480); 00234 { 00235 mrpt::opengl::COpenGLScenePtr &scene = win.get3DSceneAndLock(); 00236 scene->insert(rba_3d); 00237 win.unlockAccess3DScene(); 00238 } 00239 win.setCameraZoom( 4 ); 00240 win.repaint(); 00241 00242 cout << "Press any key or close window to exit.\n"; 00243 win.waitForKey(); 00244 #endif 00245 00246 return 0; // All ok 00247 }