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 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 }