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 #pragma once 00011 00012 #include <iostream> 00013 #include <fstream> 00014 #include <sstream> // stringstream 00015 00016 namespace srba { 00017 00018 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS> 00019 void TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::clear() 00020 { 00021 num.clear(); 00022 sym.next_edge.clear(); 00023 sym.all_edges.clear(); 00024 } 00025 00026 00027 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS> 00028 void TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::dump_as_text(std::string &s) const 00029 { 00030 using mrpt::format; 00031 00032 s.clear(); 00033 00034 s += 00035 " From | Shortest path to:=>Next node to move to [Distance] \n" 00036 "--------+-----------------------------------------------------------------\n"; 00037 for (typename next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1) 00038 { 00039 s += format(" %6u |",static_cast<unsigned int>(it1->first) ); 00040 00041 for (std::map<TKeyFrameID,TSpanTreeEntry>::const_iterator it2=it1->second.begin();it2!=it1->second.end();++it2) 00042 s += format(" %5u:=>%5u [%u] |",static_cast<unsigned int>(it2->first), static_cast<unsigned int>(it2->second.next), static_cast<unsigned int>(it2->second.distance)); 00043 00044 s += 00045 "\n" 00046 "--------+-----------------------------------------------------------------\n"; 00047 } 00048 00049 s += 00050 "\n\n" 00051 " From | To | Shortest path sequence \n" 00052 "--------+--------+--------------------------------------------------------\n"; 00053 for (typename all_edges_maps_t::const_iterator it1=sym.all_edges.begin();it1!=sym.all_edges.end();++it1) 00054 { 00055 for (typename std::map<TKeyFrameID, k2k_edge_vector_t >::const_iterator it2=it1->second.begin();it2!=it1->second.end();++it2) 00056 { 00057 s += format(" %6u | %6u |",static_cast<unsigned int>(it1->first),static_cast<unsigned int>(it2->first) ); 00058 00059 const k2k_edge_vector_t & edges = it2->second; 00060 for (typename k2k_edge_vector_t::const_iterator it3=edges.begin();it3!=edges.end();++it3) 00061 s += format(" [%4u => %4u] ",static_cast<unsigned int>((*it3)->from),static_cast<unsigned int>((*it3)->to) ); 00062 00063 s+= 00064 "\n" 00065 "--------+--------+--------------------------------------------------------\n"; 00066 } 00067 } 00068 } 00069 00070 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS> 00071 bool TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::dump_as_text_to_file(const std::string &sFileName) const 00072 { 00073 std::ofstream f; 00074 f.open(sFileName.c_str()); 00075 if (!f.is_open()) return false; 00076 00077 std::string s; 00078 this->dump_as_text(s); 00079 00080 return !(f << s).fail(); 00081 } 00082 00083 namespace internal 00084 { 00085 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS> 00086 void recursive_print_st_dot( 00087 std::set< std::pair<std::string,std::string> > & all_edges, 00088 const std::string &prefix, 00089 const TKeyFrameID came_from, 00090 const TKeyFrameID root, 00091 const std::map<TKeyFrameID,TSpanTreeEntry> &root_entries, 00092 const typename TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::next_edge_maps_t &all, 00093 std::set<TKeyFrameID> &visited, 00094 const std::map<TKeyFrameID,TSpanTreeEntry> &top_root_entries) 00095 { 00096 visited.insert(root); 00097 00098 // All nodes at depth=1 00099 for (std::map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=root_entries.begin();it!=root_entries.end();++it) 00100 { 00101 if (it->second.distance==1 && top_root_entries.find(it->first)!=top_root_entries.end()) 00102 { 00103 const TKeyFrameID child = it->first; 00104 //s << prefix << root << " -> " << prefix << child << ";\n"; 00105 const std::string s1 = prefix + mrpt::format("%06u",static_cast<unsigned int>( std::max(root,child) )); 00106 const std::string s2 = prefix + mrpt::format("%06u",static_cast<unsigned int>( std::min(root,child) )); 00107 all_edges.insert( make_pair(s1,s2) ); 00108 00109 if (!visited.count(it->first)) 00110 { 00111 typename TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::next_edge_maps_t::const_iterator it_ce = all.find(child); 00112 ASSERT_(it_ce != all.end()) 00113 internal::recursive_print_st_dot(all_edges,prefix,root,child,it_ce->second,all,visited,top_root_entries); 00114 } 00115 } 00116 } 00117 } 00118 00119 } // end NS "internal" 00120 00121 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS> 00122 bool TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::save_as_dot_file(const std::string &sFileName, const std::vector<TKeyFrameID> &kf_roots_to_save ) const 00123 { 00124 using mrpt::format; 00125 using namespace std; 00126 00127 ofstream f; 00128 f.open(sFileName.c_str()); 00129 if (!f.is_open()) return false; 00130 00131 vector<next_edge_maps_t::const_iterator> its_to_process; 00132 00133 if (kf_roots_to_save.empty()) 00134 { 00135 // All: 00136 its_to_process.reserve(sym.next_edge.size()); 00137 for (next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1) 00138 its_to_process.push_back(it1); 00139 } 00140 else 00141 { 00142 for (size_t i=0;i<kf_roots_to_save.size();i++) 00143 { 00144 next_edge_maps_t::const_iterator it=sym.next_edge.find(kf_roots_to_save[i]); 00145 if (it!=sym.next_edge.end()) // silently ignore queries for KFs without a tree 00146 its_to_process.push_back(it); 00147 } 00148 } 00149 00150 stringstream s; 00151 00152 s << "graph G {\n"; 00153 00154 map<size_t, set<string> > kfs_by_depth; 00155 map<string, size_t> depth_kf; 00156 00157 // 1st step: define nodes & their depths: 00158 for (size_t k=0;k<its_to_process.size();k++) 00159 { 00160 const next_edge_maps_t::const_iterator it1=its_to_process[k]; 00161 00162 const TKeyFrameID root = it1->first; 00163 const string sR = format("%06u",static_cast<unsigned int>(root) ); 00164 00165 const string sNodeDefR = sR + mrpt::format("%06u [label=%u]",static_cast<unsigned int>(root),static_cast<unsigned int>(root)); 00166 kfs_by_depth[0].insert( sNodeDefR ); 00167 depth_kf[mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>(root))] = 0; 00168 00169 // All nodes at depth=1 00170 for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it) 00171 { 00172 const string sNodeDef = sR + mrpt::format("%06u [label=%u]",static_cast<unsigned int>(it->first),static_cast<unsigned int>(it->first)); 00173 kfs_by_depth[it->second.distance].insert( sNodeDef ); 00174 depth_kf[mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>(it->first))] = it->second.distance; 00175 } 00176 } 00177 00178 for (map<size_t, set<string> >::const_iterator it=kfs_by_depth.begin();it!=kfs_by_depth.end();++it) 00179 { 00180 //const size_t depth = it->first; 00181 const set<string> & sNodes = it->second; 00182 00183 s << 00184 "subgraph {\n" 00185 " rank = same;\n"; 00186 for (set<string>::const_iterator itS=sNodes.begin();itS!=sNodes.end();++itS) 00187 s << *itS << "\n"; 00188 s <<"};\n"; 00189 } 00190 00191 // 2nd step: generate list of all edges in all trees: 00192 set< pair<string,string> > all_edges; 00193 00194 for (size_t k=0;k<its_to_process.size();k++) 00195 { 00196 const next_edge_maps_t::const_iterator it1=its_to_process[k]; 00197 00198 const TKeyFrameID root = it1->first; 00199 00200 // All nodes at all depths: 00201 for (map<TKeyFrameID,TSpanTreeEntry>::const_iterator it=it1->second.begin();it!=it1->second.end();++it) 00202 { 00203 const TKeyFrameID other = it->first; 00204 00205 const TKeyFrameID id1 = std::max(root,other); 00206 const TKeyFrameID id2 = std::min(root,other); 00207 00208 // Get all edges in the shortest path between them: 00209 // (we only store <max,min> since this table is symmetric) 00210 typename all_edges_maps_t::const_iterator it_eds_id1 = sym.all_edges.find(id1); 00211 ASSERT_(it_eds_id1 != sym.all_edges.end()) 00212 00213 const std::map<TKeyFrameID, k2k_edge_vector_t> &eds_id1 = it_eds_id1->second; 00214 typename std::map<TKeyFrameID, k2k_edge_vector_t>::const_iterator eds_it = eds_id1.find(id2); 00215 ASSERT_(eds_it!=eds_id1.end()) 00216 00217 const k2k_edge_vector_t &eds = eds_it->second; 00218 00219 for (size_t i=0;i<eds.size();i++) 00220 { 00221 const TKeyFrameID to = eds[i]->to; 00222 const TKeyFrameID from = eds[i]->from; 00223 00224 const string s1 = mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>( std::max(to,from) )); 00225 const string s2 = mrpt::format("%06u%06u",static_cast<unsigned int>(root),static_cast<unsigned int>( std::min(to,from) )); 00226 00227 all_edges.insert( make_pair(s1,s2) ); 00228 } 00229 } 00230 } 00231 00232 00233 // And now only draw those at a different depth level: 00234 for (set< pair<string,string> >::const_iterator it=all_edges.begin();it!=all_edges.end();++it) 00235 s << it->first << " -- " << it->second << ";\n"; 00236 00237 // And now generate invisible edges between nodes across all depths ("ranks") so graphviz really put them in different physical heights: 00238 for (map<size_t, set<string> >::const_iterator it=kfs_by_depth.begin();it!=kfs_by_depth.end();++it) 00239 { 00240 const set<string> & sNodes = it->second; 00241 if (sNodes.empty()) continue; // But shouldn't occur! 00242 00243 if (it!=kfs_by_depth.begin()) 00244 s << " -- "; 00245 00246 s << it->second.begin()->substr(0,12) << " "; 00247 } 00248 if (!kfs_by_depth.empty()) s << " [style=invis];\n"; 00249 00250 s << "}\n"; 00251 00252 return !(f << s.str()).fail(); 00253 } 00254 00255 00257 template <class KF2KF_POSE_TYPE,class LM_TYPE,class OBS_TYPE,class RBA_OPTIONS> 00258 void TRBA_Problem_state<KF2KF_POSE_TYPE,LM_TYPE,OBS_TYPE,RBA_OPTIONS>::TSpanningTree::get_stats( 00259 size_t &num_nodes_min, 00260 size_t &num_nodes_max, 00261 double &num_nodes_mean, 00262 double &num_nodes_std) const 00263 { 00264 num_nodes_min = 0; 00265 num_nodes_max = 0; 00266 num_nodes_mean = 0; 00267 num_nodes_std = 0; 00268 00269 std::vector<size_t> num_nodes; 00270 num_nodes.reserve(sym.next_edge.size()); 00271 00272 for (next_edge_maps_t::const_iterator it1=sym.next_edge.begin();it1!=sym.next_edge.end();++it1) 00273 num_nodes.push_back( it1->second.size() ); 00274 00275 mrpt::math::meanAndStd(num_nodes,num_nodes_mean,num_nodes_std); 00276 mrpt::math::minimum_maximum(num_nodes, num_nodes_min, num_nodes_max); 00277 } 00278 00279 00280 } // end NS