landmark_manager.h
Go to the documentation of this file.
00001 // Part of the source code of master thesis of Jiri Divis, source code written by Jiri Divis
00002 /*------------------------------------------------------------------------------------------------*/
00009 #ifndef VSLAM_LANDMARK_MANAGER_H_INCLUDED
00010 #define VSLAM_LANDMARK_MANAGER_H_INCLUDED
00011 #include "utils.h"
00012 #include "pose_graph.h" 
00013 #include "graph_utils.h"  
00014 #include "error_func.h"  // Used by RanSaC in feature-landmark association (Landmark Manager).
00015 
00016 #include <algorithm>
00017 #include <tr1/functional>
00018 
00019 
00020 namespace vslam{
00021 /*------------------------------------------------------------------------------------------------*/
00043 template<typename G> struct Point{
00044     typedef typename graph_traits<G>::vertex_descriptor VertexD;
00045     typedef pair<VertexD, int> Feature;
00046     typedef std::vector<Feature> FeatureCont;
00047 
00048     FeatureCont seen_from; 
00049     Vector3d global;       
00050     bool initialized;      
00051     bool usable;           
00052 };
00053 
00054 
00055 
00056 
00057 
00063 namespace lmdetails{
00064 /*------------------------------------------------------------------------------------------------*/
00074 
00075 template<typename G> class PointsLoc{
00076     protected:
00077         vector<Point<G> > pts;
00078         typedef typename graph_traits<G>::vertex_descriptor VertexD;
00079 
00080     public:
00081         EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00082         void destroy(int idx, G&g){
00083             getPoint(idx).initialized=false;
00084             getPoint(idx).global=Vector3d::Zero();
00085             typedef typename Point<G>::Feature T;
00086             BOOST_FOREACH(T pf, getPoint(idx).seen_from){
00087                 vector<int> & fixed_points = get(vertex_fix_idx, g, pf.first);
00088                 fixed_points[pf.second]=BAD_INDEX;
00089             }
00090             getPoint(idx).seen_from.clear();
00091         }
00092 
00093         int create(const G& g, const vector<FeatureID<G> >& observations, 
00094                 const Vector3d& estimate);
00095 
00096         void addObservation(const G&g, int idx, FeatureID<G>& f, const Vector3d& estimate);
00097 
00098         Point<G> & getPoint(int idx){
00099             return pts[idx];
00100         }
00101 
00102         const Point<G> & getPoint(int idx) const{
00103             return pts[idx];
00104         }
00105         
00106         int size() const { return pts.size(); }
00107 };
00108 
00109 
00110 
00116 template<class G> int PointsLoc<G>::create(const G& g, const vector<FeatureID<G> >& observations, 
00117         const Vector3d& estimate){
00118     Point<G> pt;
00119     vector<LandmarkObservation> lm_obs;
00120     BOOST_FOREACH(FeatureID<G> f, observations){
00121         pt.seen_from.push_back(make_pair(f.vd, f.vidx));
00122         lm_obs.push_back(LandmarkObservation(get(vertex_transform, g, f.vd).inverse(), 
00123                     getFeaturePixel(g, f))); 
00124     }
00125     pt.initialized=false;
00126     pt.usable=true;
00127     BOOST_FOREACH(LandmarkObservation tmp, lm_obs){
00128         if(!isEstimateInFrontOfCamera(tmp, estimate)) pt.usable=false; 
00129     }
00130     FeatureID<G> ff = FeatureID<G>(pt.seen_from.begin()->first, pt.seen_from.begin()->second);
00131     FeatureID<G> fl = FeatureID<G>(pt.seen_from.rbegin()->first, pt.seen_from.rbegin()->second);
00132     if(disparityAngle(g, ff, fl) < (M_PI/180.0)*3.0){ 
00133         pt.usable=false;
00134     }
00135     pt.global=estimate;
00136     pts.push_back(pt);
00137     return pts.size() - 1;
00138 }
00139 
00146 template<class G> void PointsLoc<G>::addObservation(
00147         const G&g, int idx, FeatureID<G>& f, const Vector3d& estimate){
00148     typename Point<G>::FeatureCont & seen_from_idx = pts[idx].seen_from;
00149     seen_from_idx.push_back(make_pair(f.vd, f.vidx));
00150 
00151     pts[idx].global=estimate;
00152     if(seen_from_idx.size()>=4){
00153         pts[idx].usable=true;
00154     } else{
00155         Point<G> pt = pts[idx];
00156         FeatureID<G> ff = FeatureID<G>(pt.seen_from.begin()->first, pt.seen_from.begin()->second);
00157         FeatureID<G> fl = FeatureID<G>(pt.seen_from.rbegin()->first, pt.seen_from.rbegin()->second);
00158         if(disparityAngle(g, ff, fl) > (M_PI/180.0)*3.0){
00159             pt.usable=true;
00160         }
00161     }
00162 }
00163 
00164 
00165 
00166 
00167 
00168 
00169 /*------------------------------------------------------------------------------------------------*/
00173 template<class G> class LandmarkQualityOrdering{
00174     protected:
00175         const G & g;
00176         const PointsLoc<G> & points;
00177 
00178     public:
00179         LandmarkQualityOrdering(const G& _g, const PointsLoc<G>& _points) : g(_g), points(_points) {}
00180 
00181         bool operator()(int lm_idx_a, int lm_idx_b){
00182             return lm_idx_a > lm_idx_b;
00183         }
00184 };
00185 
00186 
00188 template<class G> double ftrTrackEndToEndDisparity(const G&g, const Point<G>& pt){
00189     FeatureID<G> ff = FeatureID<G>(pt.seen_from.begin()->first, pt.seen_from.begin()->second);
00190     FeatureID<G> fl = FeatureID<G>(pt.seen_from.rbegin()->first, pt.seen_from.rbegin()->second);
00191     return disparityAngle(g, ff, fl);
00192 }
00193 
00195 template<class G> class DisparityLmOrdering : public LandmarkQualityOrdering<G>{
00196     public:
00197         DisparityLmOrdering(const G& _g, const PointsLoc<G>& _points) : 
00198                 LandmarkQualityOrdering<G>(_g, _points) {}
00199 
00201         bool operator()(int lm_idx_a, int lm_idx_b){
00202             if(this->points.getPoint(lm_idx_a).usable){
00203                 if(this->points.getPoint(lm_idx_b).usable){
00204                     double disparity_a = ftrTrackEndToEndDisparity(
00205                             this->g, this->points.getPoint(lm_idx_a));
00206                     double disparity_b = ftrTrackEndToEndDisparity(
00207                             this->g, this->points.getPoint(lm_idx_b));
00208                     return disparity_a > disparity_b;
00209                 } else{
00210                     return true;
00211                 }
00212             } else{
00213                 if(this->points.getPoint(lm_idx_b).usable){
00214                     return false;
00215                 } else{
00216                     return lm_idx_a > lm_idx_b;
00217                 }
00218             }
00219         }
00220 };
00221 
00222 
00223 template<class G> void pruneLandmarks(
00224         const G&g, PointsLoc<G>& points, typename graph_traits<G>::vertex_descriptor v, int keep_num){
00225     vector<int> visible_lm_idxs;  
00226     BOOST_FOREACH(int fix_idx, get(vertex_fix_idx, g, v)){
00227         if(fix_idx!=BAD_INDEX){
00228             visible_lm_idxs.push_back(fix_idx);
00229         }
00230     }
00231 
00232     std::sort(visible_lm_idxs.begin(), visible_lm_idxs.end(), DisparityLmOrdering<G>(g, points));
00233     vector<int>::const_iterator idx_it = visible_lm_idxs.begin();
00234     for(int j=0; (j< keep_num) && idx_it!=visible_lm_idxs.end(); j++){
00235         if(points.getPoint(*idx_it).usable){
00236             points.getPoint(*idx_it).initialized = true;
00237         } else{
00238             keep_num++;
00239         }
00240         ++idx_it;
00241     }
00242 }
00243  //end of group LmM__pruning
00245 /*------------------------------------------------------------------------------------------------*/
00246 /*------------------------------------------------------------------------------------------------*/
00251 
00252 #define  VSLAM_REPROJ_ERROR_TOLERANCE 5.0 //XXX
00253 
00254 
00255 
00256 typedef ALIGNED<LandmarkObservation>::vector LandmarkObservationVec;
00257 
00258 typedef Model<Vector3d, LandmarkObservation> PointFromLandmarkObservationsModel;
00259 
00276 inline bool landmarkObservationSetConsistency(
00277         const LandmarkObservationVec& observations1,
00278         const LandmarkObservationVec& observations2, 
00279         const LandmarkObservationVec& all_observations, 
00280         Vector3d& global_est){
00281     typedef LandmarkToPoseReprojectionError T0;
00282     typedef MDErrorFuncAdaptor<T0> T1;
00283     typedef RealErrorMaxErrorAccumulator<T1> T2;
00284     shared_ptr<ModelBuilder<PointFromLandmarkObservationsModel> > mbuilder;
00285     T0 error_func;
00286     T1 adapted_error_func = T1(error_func);
00287     T2 error_acum = T2(adapted_error_func, VSLAM_REPROJ_ERROR_TOLERANCE);
00288     mbuilder.reset(new Point3dModelFromLandmarkObservationPairBuilder<T2>(error_acum));
00289     shared_ptr<SingleSolutionModel<T2> > initial_test_model;
00290     ALIGNED<LandmarkObservation>::vector tmp_vec;
00291     initial_test_model.reset(new SingleSolutionModel<T2>(0, tmp_vec,global_est,error_acum));
00292     initial_test_model->compute(all_observations);
00293     if(initial_test_model->getInlierCount()==(int)all_observations.size()){
00294         return true;
00295     }
00296     shared_ptr<PointFromLandmarkObservationsModel> model, best_model;
00297     LandmarkObservationVec selected_data;
00298     BOOST_FOREACH(LandmarkObservation obs1, observations1){
00299         selected_data.push_back(obs1);
00300         BOOST_FOREACH(LandmarkObservation obs2, observations2){
00301             if(!(obs1 == obs2)){
00302                 selected_data.push_back(obs2);
00303                 model=mbuilder->operator()(selected_data);
00304                 model->compute(all_observations);
00305                 if(model->getInlierCount()==(int)all_observations.size()){
00306                     if(!best_model || model->getError() < best_model->getError()) best_model=model;
00307                 }
00308                 selected_data.pop_back();
00309             }
00310         }
00311         selected_data.pop_back();
00312     }
00313     if(best_model){
00314         global_est = best_model->getModel();
00315         return true;
00316     } else{
00317         return false;
00318     }
00319 }
00320 
00321 
00322 
00328 template<class G> bool consistencyCheck(
00329         const G& g, FeatureID<G> f1, FeatureID<G> f2, FeatureID<G> f3, Vector3d& estimate){
00330     LandmarkObservationVec obs;
00331     obs.push_back(LandmarkObservation(get(vertex_transform, g, f1.vd).inverse(), 
00332             getFeaturePixel(g, f1)));
00333     obs.push_back(LandmarkObservation(get(vertex_transform, g, f2.vd).inverse(), 
00334             getFeaturePixel(g, f2)));
00335     obs.push_back(LandmarkObservation(get(vertex_transform, g, f3.vd).inverse(), 
00336             getFeaturePixel(g, f3)));
00337     return landmarkObservationSetConsistency(obs, obs, obs, estimate);
00338 }
00339 
00340 
00352 template<class G>  bool consistencyCheck(
00353         const G& g, 
00354         const Points<G>& points, 
00355         FeatureID<G> lmfid, 
00356         FeatureID<G> nonlmfid, 
00357         Vector3d& estimate){
00358     typename property_map<G, vertex_fix_idx_t>::const_type vfixmap = get(vertex_fix_idx, g);
00359 
00360     if((vfixmap[lmfid.vd][lmfid.vidx]==BAD_INDEX) && 
00361             (vfixmap[nonlmfid.vd][nonlmfid.vidx]!=BAD_INDEX)){
00362         assert(false); 
00363         return false;
00364     } else{
00365         typedef pair<typename graph_traits<G>::vertex_descriptor, int> T1;
00366         Point<G> point=points.getPoint(vfixmap[lmfid.vd][lmfid.vidx]);
00367         LandmarkObservationVec obs;
00368         BOOST_FOREACH(T1 pt, point.seen_from){
00369             obs.push_back(LandmarkObservation(
00370                     get(vertex_transform, g, pt.first).inverse(), 
00371                     getFeaturePixel(g, FeatureID<G>(pt.first, pt.second))));
00372         }
00373         obs.push_back(LandmarkObservation(
00374                 get(vertex_transform, g, nonlmfid.vd).inverse(), 
00375                 getFeaturePixel(g, nonlmfid)));
00376         if(landmarkObservationSetConsistency(obs, obs, obs, estimate)){
00377             assert(vfixmap[nonlmfid.vd][nonlmfid.vidx]==BAD_INDEX);
00378             return true;
00379         } else{
00380             return false;
00381         }
00382     }
00383 }  //group LmM__impl__consist ends here.
00385 /*------------------------------------------------------------------------------------------------*/  //group LmM__impl ends here.
00387 /*------------------------------------------------------------------------------------------------*/
00388 }//namespace lmdetails
00389 
00390 /*------------------------------------------------------------------------------------------------*/
00401 template<class G> void Points<G>::activateLandmarks(
00402         const G&g, typename graph_traits<G>::vertex_descriptor v, int keep_num){
00403     lmdetails::pruneLandmarks(g, points, v, keep_num);
00404 }
00405 
00410 template<class G> const Point<G> & Points<G>::getPoint(int idx) const{
00411     return points.getPoint(idx);
00412 }
00413 
00414 
00416 template<class G> void Points<G>::lmEstimateUpd(int lm_id, Vector3d& new_estimate){
00417     points.getPoint(lm_id).global=new_estimate;
00418 }
00419 
00420 
00426 template<class G> void Points<G>::lmEstimateUpdChecked(int lm_id, Vector3d& new_estimate){
00427     this->lmEstimateUpd(lm_id, new_estimate);
00429 }
00430 
00431 
00437 template<class G> void Points<G>::deleteLmObs(G&g, const FeatureID<G>& obs){
00438     Point<G> pt = points.getPoint(get(vertex_fix_idx, g, obs.vd)[obs.vidx]);
00439     
00440     assert(pt.seen_from.size());
00441     vector<int> & fixed_points = get(vertex_fix_idx, g, obs.vd);
00442 
00443     int to_delete_idx=BAD_INDEX; int to_delete_kp_idx=BAD_INDEX;
00444     for(size_t i=0; i<pt.seen_from.size(); i++){
00445         if(pt.seen_from[i].first==obs.vd){
00446             to_delete_idx=i;
00447             to_delete_kp_idx=pt.seen_from[i].second;
00448         }
00449     }
00450     assert(to_delete_idx!=BAD_INDEX && to_delete_kp_idx!=BAD_INDEX);
00451 
00452     if((int)(pt.seen_from.size()-1)!=to_delete_idx){
00453         pt.seen_from[to_delete_idx]=pt.seen_from[pt.seen_from.size()-1];
00454     }
00455     fixed_points[to_delete_kp_idx]=BAD_INDEX;
00456     pt.seen_from.pop_back();
00457 
00458     if(pt.seen_from.size()==1){
00459         vector<int> & fixed_points2 = get(vertex_fix_idx, g, pt.seen_from[0].first);
00460         fixed_points2[pt.seen_from[0].second]=BAD_INDEX;
00461         pt.seen_from.clear();
00462         pt.initialized=false;
00463         pt.usable=false;
00464     }
00465 }
00466 
00467 
00469 template<class G> int Points<G>::size() const{
00470     return points.size();
00471 }
00472 
00473 
00474 
00483 template<typename G> bool Points<G>::fixNewLandmark(
00484         FeatureID<G> fa,
00485         FeatureID<G> fm,
00486         FeatureID<G> fb,
00487         G& g){
00488     using namespace boost;
00489     using namespace lmdetails;
00490     typename property_map<G, vertex_fix_idx_t>::type vm = get(vertex_fix_idx, g);
00491     bool c1,c2,c3;
00492     c1=vm[fa.vd][fa.vidx] == BAD_INDEX;
00493     c2=vm[fm.vd][fm.vidx] == BAD_INDEX;
00494     c3=vm[fb.vd][fb.vidx] == BAD_INDEX;
00495     if(!(c1 && c2 && c3)) return false;
00496     Vector3d estimate;
00497     if(consistencyCheck(g, fa, fm, fb, estimate)){
00498         vector<FeatureID<G> > fs;
00499         fs.push_back(fa); fs.push_back(fm); fs.push_back(fb);
00500         int tmp = points.create(g, fs, estimate); 
00501         vm[fm.vd][fm.vidx] = tmp;
00502         vm[fa.vd][fa.vidx] = tmp;
00503         vm[fb.vd][fb.vidx] = tmp;
00504         return true;
00505     } else{
00506         return false;
00507     }
00508 }
00509 
00518 template<typename G> bool Points<G>::fixNewObservation(
00519         FeatureID<G> fa, FeatureID<G> fb, G& g){
00520     using namespace boost;
00521     using namespace lmdetails;
00522     typename property_map<G, vertex_fix_idx_t>::type vm = get(vertex_fix_idx, g);
00523 
00524     if(vm[fa.vd][fa.vidx] == BAD_INDEX){
00525         if(vm[fb.vd][fb.vidx] == BAD_INDEX){
00526             assert(false);
00527         } else{
00528             return this->fixNewObservation(fb, fa, g);
00529         }
00530     } else{
00531         Vector3d estimate;
00532         if(points.getPoint(vm[fa.vd][fa.vidx]).initialized){ 
00533             estimate= points.getPoint(
00534                     vm[fa.vd][fa.vidx]).global; //set old estimate.
00535         } else{
00536             estimate = Vector3d(1.0, 1.0, 1.0); 
00537         }
00538         if(consistencyCheck<G>(g, *this, fa, fb, estimate)){
00539             points.addObservation(g, vm[fa.vd][fa.vidx], fb, estimate);
00540             vm[fb.vd][fb.vidx] = vm[fa.vd][fa.vidx];
00541             return true;
00542         } else{
00543             return false;
00544         }
00545     }
00546     assert(false);
00547     return false;
00548 }
00549 
00550 
00566 template<class G> void findNewLandmarks(
00567         typename graph_traits<G>::vertex_descriptor convd, 
00568         typename graph_traits<G>::vertex_descriptor newvd, 
00569         Points<G> & points, 
00570         G & g){
00571     using namespace boost;
00572     typename graph_traits<G>::adjacency_iterator vi, vi_end;
00573     int new_track_count=0;
00574     //find new landmarks
00575     for(tie(vi, vi_end) = adjacent_vertices(convd , g); vi!=vi_end; ++vi){
00576         if(*vi != newvd){
00577             vector<int> common_ftr_convd = common_feature_tracks<vector>(g, *vi, convd, newvd);
00578             vector<int>::const_iterator common_ftr_convd_it = common_ftr_convd.begin();
00579             while(common_ftr_convd_it!=common_ftr_convd.end()){
00580                 FeatureID<G> convdf = FeatureID<G>(convd, *common_ftr_convd_it);
00581                 FeatureID<G> newvdf = FeatureID<G>(newvd, getFeatureIdx(g, convdf, newvd));
00582                 FeatureID<G> vif = FeatureID<G>(*vi, getFeatureIdx(g, convdf, *vi));
00583 
00584                 //new landmark with 3 features
00585                 if(!isLandmakFeature(g, vif) && !isLandmakFeature(g, convdf) && 
00586                         !isLandmakFeature(g, newvdf)){
00587                     if(points.fixNewLandmark(vif, convdf, newvdf, g)){
00588                         new_track_count++;
00589                     }
00590                 }
00591                 ++common_ftr_convd_it;
00592             }
00593         }
00594     }
00595     std::string num_new_lms_key="num_new_lms";
00596     map<std::string, double> & pmap = get(vertex_debug_info, g, convd).double_propmap;
00597     if(pmap.find(num_new_lms_key) == pmap.end()){
00598         pmap[num_new_lms_key]= new_track_count;
00599     } else{
00600         get(vertex_debug_info, g, newvd).double_propmap[num_new_lms_key]=new_track_count;
00601     }
00602     ROS_INFO_STREAM_NAMED("EdgeBulder", "# of new tracks: " << new_track_count);
00603     get(vertex_debug_info, g, convd).double_propmap["tracks_new"]=new_track_count;
00604 }
00605 
00616 template<class G> void extendLandmarks(
00617         typename graph_traits<G>::vertex_descriptor convd, 
00618         typename graph_traits<G>::vertex_descriptor newvd, 
00619         Points<G> & points, 
00620         G & g){
00621     int old_track_count=0;
00622     int deleted=0;
00623     const map<int, int> & sdmap = get(edge_kp_idx_map, g, edge(convd, newvd, g).first);
00624     for(map<int, int>::const_iterator it = sdmap.begin(); it != sdmap.end(); ++it){
00625         FeatureID<G> convdf = FeatureID<G>(convd, it->first);
00626         FeatureID<G> newvdf = FeatureID<G>(newvd, it->second);
00627         
00628         // (convdf, newvdf) extends convdf landmark
00629         if(isLandmakFeature(g, convdf) && !isLandmakFeature(g, newvdf)){
00630             if(points.fixNewObservation(convdf, newvdf, g)){
00631                 old_track_count++;
00632             } else{
00633                 deleted++;
00634             }
00635         }
00636     }
00637     ROS_INFO_STREAM_NAMED("EdgeBulder", "# of tracks that ceased: " << deleted);
00638     ROS_INFO_STREAM_NAMED("EdgeBulder", "# of tracks extended: " << old_track_count);
00639     if(deleted && old_track_count){
00640         get(vertex_debug_info, g, convd).double_propmap["tracks_ceased"]=deleted;
00641         get(vertex_debug_info, g, convd).double_propmap["tracks_extended"]=old_track_count;
00642     }
00643 } //end of group LmM__interface //end of group LmM
00646 /*------------------------------------------------------------------------------------------------*/
00647 /*------------------------------------------------------------------------------------------------*/
00648 } //end of namespace vslam
00649 
00650 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines


pose_estimation
Author(s): Jiri Divis/jiridivis@gmail.com
autogenerated on Wed Mar 27 2013 21:00:12