landmark.cpp
Go to the documentation of this file.
00001 /*
00002  * landmark.cpp
00003  *
00004  *  Created on: Jun 1, 2012
00005  *      Author: Nikolas Engelhard
00006  */
00007 
00008 
00009 #include "landmark.h"
00010 #include "misc2.h"
00011 
00012 #ifdef DO_FEATURE_OPTIMIZATION
00013 
00014 #include "graph_manager.h"
00015 
00016 #include "g2o/types/slam3d/parameter_camera.h"
00017 //#include "g2o/types/slam3d/camera_parameters.h"
00018 
00019 
00020 
00021 #include <utility>
00022 using namespace std;
00023 
00024 
00025 // look for features with more than one match
00026 MatchingResult removeStrangeMatches(const MatchingResult& match_result){
00027 
00028 
00029  map<int,int>  good_inlier;
00030  for (uint i=0; i<match_result.inlier_matches.size(); ++i){
00031   cv::DMatch m = match_result.inlier_matches[i];
00032   good_inlier[m.trainIdx] = m.queryIdx;
00033  }
00034 
00035 // now each training feature has no more than one query feature
00036  map<int,int> final_inlier;
00037  for (map<int,int>::iterator it = good_inlier.begin(); it != good_inlier.end(); ++it){
00038   final_inlier[it->second] = it->first; // no query has more than one trainIdx
00039  }
00040 
00041 
00042  MatchingResult cleaned; cleaned.inlier_matches.reserve(good_inlier.size());
00043  for (map<int,int>::iterator it = final_inlier.begin(); it != final_inlier.end(); ++it){
00044   cv::DMatch m;
00045   m.trainIdx = it->second; m.queryIdx=it->first;
00046   cleaned.inlier_matches.push_back(m);
00047  }
00048 
00049  ROS_INFO("Cleaning: removed %zu matches from %zu", match_result.inlier_matches.size()-good_inlier.size(), match_result.inlier_matches.size() );
00050 
00051  return cleaned;
00052 
00053 
00054 
00055 }
00056 
00057 
00058 
00059 void GraphManager::removeFeaturesFromGraph(){
00060 
00061 // for (Vset_it it = landmark_vertices.begin(); it != landmark_vertices.end(); ++it){
00062 //  optimizer_->removeVertex(*it);
00063 // }
00064 
00065  for (uint i=0; i<landmarks.size(); ++i){
00066   if (landmarks[i].g2o_vertex){
00067    optimizer_->removeVertex(landmarks[i].g2o_vertex);
00068    landmarks[i].g2o_vertex = NULL;
00069   }
00070 
00071  }
00072 
00073  for (EdgeSet_it it = cam_lm_edges.begin(); it != cam_lm_edges.end(); ++it){
00074   optimizer_->removeEdge(*it);
00075  }
00076 
00077 }
00078 
00079 
00080 void GraphManager::printLandmarkStatistic(){
00081 
00082  float mean_obs_cnt = 0;
00083  uint lm_cnt = landmarks.size();
00084  if (lm_cnt == 0) return;
00085 
00086  for (uint i=0; i<lm_cnt; ++i){
00087   Landmark *lm = &landmarks[i];
00088   // ROS_INFO("Landmark %i has %zu obs", lm->id, lm->observations.size());
00089   mean_obs_cnt += (lm->observations.size()*1.0/lm_cnt);
00090  }
00091 
00092  ROS_WARN("%i Landmarks with mean of %.2f observations", lm_cnt, mean_obs_cnt);
00093 }
00094 
00095 
00096 // increases next_vertex_id
00097 void GraphManager::updateLandmarkInGraph(Landmark* lm){
00098 
00099  // Landmark is not in the graph, create new vertex
00100  // use first observation as initial position
00101  if (!lm->g2o_vertex){
00102   int node_id = lm->observations.begin()->first;
00103   int feature_id = lm->observations.begin()->second;
00104   Node *n = graph_[node_id];
00105   g2o::VertexSE3* v1 = dynamic_cast<g2o::VertexSE3*>(optimizer_->vertex(n->vertex_id_ ));
00106 
00107   assert(v1);
00108   assert(int(n->feature_locations_3d_.size()) > feature_id);
00109 
00110   Eigen::Vector4f pos_relative = n->feature_locations_3d_[feature_id];
00111   if(isnan(pos_relative(2))){
00112     pos_relative(2) = 1.0; //FIXME instead of using an arbitrary depth value, use the correct vertex type
00113     return;
00114   }
00115   Eigen::Vector3d pos_absolute = v1->estimate()*Eigen::Vector3d(pos_relative[0],pos_relative[1],pos_relative[2]);
00116 
00117   lm->g2o_vertex = new LM_vertex_type();
00118   lm->g2o_vertex->setId(next_vertex_id++);
00119   lm->g2o_vertex->setFixed(false);
00120   lm->g2o_vertex->setEstimate(pos_absolute);
00121 
00122   optimizer_->addVertex(lm->g2o_vertex);
00123   landmark_vertices.insert(lm->g2o_vertex);
00124  }
00125 
00126 
00127  if (lm->observations.size()>0){
00128   // adding all new observation edges
00129   for (std::map<int,int>::iterator it=lm->observations.begin(); it != lm->observations.end(); ++it){
00130    int node_id = it->first;
00131    int kpt = it->second;
00132 
00133 
00134    // ROS_INFO("adding kpt %i in image %i", kpt, node_id);
00135 
00136    if (graph_.find(node_id) == graph_.end()){
00137     ROS_INFO("Trying to create projection to node %i which is not in the graph!", node_id);
00138     continue;
00139    }
00140 
00141    Node * node = graph_[node_id];
00142    g2o::VertexSE3* v1 = dynamic_cast<g2o::VertexSE3*>(optimizer_->vertex(node->vertex_id_));
00143 
00144 
00145    assert(node->feature_locations_3d_.size() == node->feature_locations_2d_.size());
00146    assert(kpt < int(node->feature_locations_2d_.size()));
00147 
00148 
00149    Proj_edge_type* projectionEdge = new Proj_edge_type();
00150    cv::KeyPoint kp = node->feature_locations_2d_[kpt];
00151    Eigen::Vector4f pos_relative = node->feature_locations_3d_[kpt];
00152    if(!isnan(pos_relative(2))){
00153      projectionEdge->setMeasurement(Eigen::Vector3d(kp.pt.x,kp.pt.y,pos_relative[2]));
00154      Eigen::Matrix3d info_mat = point_information_matrix(pos_relative[2]);
00155      projectionEdge->setInformation(info_mat);
00156    } else {//FIXME instead of using an arbitrary depth value and high uncertainty, use the correct vertex type
00157      continue;
00158      projectionEdge->setMeasurement(Eigen::Vector3d(kp.pt.x,kp.pt.y,1.0));
00159      Eigen::Matrix3d info_mat = point_information_matrix(1e12);//as uncertain as if it was ...meter away
00160      projectionEdge->setInformation(info_mat);
00161    }
00162    projectionEdge->setParameterId(0,0);
00163    projectionEdge->vertices()[0] = v1;
00164    projectionEdge->vertices()[1] = lm->g2o_vertex;
00165 
00166 
00167 //   projectionEdge->setParameterId(0,0);
00168 //   projectionEdge->setVertex(0,v1);
00169 //   projectionEdge->setVertex(1,lm->vertex_xyz);
00170 //   projectionEdge->setId(next_vertex_id++);
00171 
00172    //projectionEdge->setRobustKernel(true);
00173    optimizer_->addEdge(projectionEdge);
00174    lm->g2o_vertex->setFixed(false);//Vertex involved in update
00175    cam_lm_edges.insert(projectionEdge);
00176    // lm->proj_edges.insert(projectionEdge);
00177 
00178   }
00179 
00180  // lm->observations_with_edges.insert(lm->new_observations.begin(), lm->new_observations.end());
00181  // lm->new_observations.clear();
00182  }
00183 }
00184 
00185 void GraphManager::updateProjectionEdges(){
00186  //ROS_INFO("Adding all edges to the graph!");
00187 
00188  for (uint i=0; i<landmarks.size(); ++i){
00189   Landmark *lm = &landmarks[i];
00190   updateLandmarkInGraph(lm);
00191   // ROS_INFO("LM %i has %zu edges", lm->id,lm->proj_edges.size());
00192  }
00193 
00194  ROS_WARN("Updated all Landmarks!");
00195 
00196 // optimizer_->save("before.g2o");
00197 //
00198 // optimizer_->initializeOptimization();
00199 // optimizer_->setVerbose(true);
00200 // optimizer_->computeActiveErrors();
00201 //
00202 // optimizer_->optimize(100);
00203 // optimizer_->computeActiveErrors();
00204 //
00205 // optimizer_->save("after.g2o");
00206 }
00207 
00208 
00209 
00210 void GraphManager::updateLandmarks(const MatchingResult& match_result, Node* old_node, Node* new_node){
00211 
00212 // ROS_ERROR("processing landmarks for nodes %i and %i (ids: %i %i) (%i inlier)", match_result.edge.id1, match_result.edge.id2, old_node->id_, new_node->id_,match_result.inlier_matches.size());
00213 
00214  assert(old_node && new_node);
00215  assert(int(old_node->id_) == match_result.edge.id1);
00216  assert(int(new_node->id_) == match_result.edge.id2);
00217 
00218  MatchingResult cleaned = removeStrangeMatches(match_result);
00219 
00220  for (uint i=0; i<cleaned.inlier_matches.size(); ++i)
00221  {
00222   cv::DMatch m = cleaned.inlier_matches[i];
00223   // ROS_INFO("Kpt %i in img %i matches with kpt %i in img %i", m.queryIdx,new_node->id_, m.trainIdx,  old_node->id_);
00224   std::map<int, int>::iterator it_old, it_new;
00225 
00226   int lm_id_old = -1;
00227   int lm_id_new = -1;
00228 
00229   //  ROS_INFO("Node %i has %zu obs", old_node->id_, old_node->kpt_to_landmark.size());
00230   //  ROS_INFO("Node %i has %zu obs", new_node->id_, new_node->kpt_to_landmark.size());
00231 
00232   // check if one or both keypoints already belong to a landmark
00233   it_old = old_node->kpt_to_landmark.find(m.trainIdx);
00234   if (it_old != old_node->kpt_to_landmark.end())
00235     lm_id_old = it_old->second;
00236 
00237   it_new = new_node->kpt_to_landmark.find(m.queryIdx);
00238   if (it_new != new_node->kpt_to_landmark.end())
00239     lm_id_new = it_new->second;
00240 
00241 
00242 //   ROS_INFO("t: %i q: %i, old_id %i, new_id %i", m.trainIdx, m.queryIdx,  lm_id_old, lm_id_new);
00243 
00244   // no point belongs to a landmark, create new
00245   if (lm_id_old == -1 && lm_id_new == -1){
00246 
00247 
00248    // create new landmark
00249 
00250 
00251    Landmark lm;
00252    lm.id = next_landmark_id++;
00253 
00254 //    ROS_INFO("Creating landmark %i",lm.id);
00255 
00256 
00257 
00258    lm.observations[old_node->id_] = m.trainIdx;
00259    lm.observations[new_node->id_] = m.queryIdx;
00260 
00261    //   ROS_INFO("old, new %i %i", it_old->second, it);
00262 
00263    assert(lm.observations.size() == 2);
00264 
00265    // ROS_INFO("node %i: kpt %i points to landmark %i", old_node->id_, m.queryIdx, lm.id);
00266    old_node->kpt_to_landmark[m.trainIdx] = lm.id;
00267    new_node->kpt_to_landmark[m.queryIdx] = lm.id;
00268 
00269 //   ROS_INFO("old: assingning feature %i to lm %i", )
00270 
00271 //   old_node->visible_landmarks.insert(lm.id);
00272 //   new_node->visible_landmarks.insert(lm.id);
00273 
00274 
00275    landmarks.push_back(lm);
00276    continue;
00277   }
00278 
00279   // one point belongs to landmark, add new observation
00280   if (lm_id_old > -1 && lm_id_new == -1){
00281 
00282    Landmark* lm = &landmarks[lm_id_old];
00283    // add new observation
00284    lm->observations[new_node->id_] = m.queryIdx;
00285    // connect keypoint with landmark
00286    new_node->kpt_to_landmark[m.queryIdx] = lm->id;
00287 
00288    continue;
00289   }
00290 
00291   // again:
00292   if (lm_id_old == -1 && lm_id_new > -1){
00293 
00294    Landmark* lm = &landmarks[lm_id_new];
00295    // add new observation
00296    lm->observations[old_node->id_] = m.trainIdx;
00297    // connect keypoint with landmark
00298    old_node->kpt_to_landmark[m.trainIdx] = lm->id;
00299 //   old_node->visible_landmarks.insert(lm.id);
00300    continue;
00301   }
00302 
00303   assert(lm_id_old > -1 && lm_id_new > -1);
00304 
00305   // both point to the same landmark
00306   // a) could be the same landmark!
00307   if (lm_id_new == lm_id_new){
00308    // Landmark *lm = &landmarks[lm_id_new];
00309 
00310    // both landmarks should already registered as observation
00311    //   assert(lm->observations.find(new_node->id_)->second = it_new->first);
00312    //   assert(lm->observations.find(it_old->second)->second = it_old->first);
00313 
00314    continue;
00315   }
00316 
00317   // last case: both landmarks belong to different landmarks -> merge landmarks
00318 
00319 
00320   // assert(1==0);
00321 
00322   Landmark *lm_1 = &landmarks[lm_id_old];
00323   Landmark *lm_2 = &landmarks[lm_id_new];
00324 
00325   // merge landmark with less observations into larger one and delete it
00326   if  (lm_1->observations.size() >= lm_2->observations.size()){
00327    mergeLandmarks(lm_1, lm_2);
00328    landmarks.erase(landmarks.begin()+lm_id_new);
00329   }else{
00330    mergeLandmarks(lm_2, lm_1);
00331    landmarks.erase(landmarks.begin()+lm_id_old);
00332   }
00333 
00334  }
00335 
00336 }
00337 
00338 
00339 
00340 // merge lm_2 into lm_1
00341 void GraphManager::mergeLandmarks( Landmark *lm_1, Landmark *lm_del){
00342 
00343  ROS_INFO("Merging lm %i (%zu pts) into lm %i (%zu pts)", lm_1->id, lm_1->observations.size(),lm_del->id, lm_del->observations.size());
00344 
00345  int new_lm_id = lm_1->id;
00346 
00347 
00348  // remove old vertex and edges from graph:
00349 // if (lm_del->g2o_vertex != NULL)
00350 //  optimizer_->removeVertex(lm_del->g2o_vertex);
00351 // for (g2o::HyperGraph::EdgeSet::iterator it = lm_del->proj_edges.begin(); it != lm_del->proj_edges.end(); ++it){
00352 //  optimizer_->removeEdge(*it);
00353 // }
00354 
00355 
00356 // lm_del->observations_with_edges.insert(lm_del->new_observations.begin(), lm_del->new_observations.end());
00357 
00358  for (std::map<int,int>::iterator it = lm_del->observations.begin(); it != lm_del->observations.end(); ++it){
00359   Node *n = graph_[it->first];
00360   int kpt = it->second;
00361 
00362   // check bookkeeping
00363   //assert(n->kpt_to_landmark[kpt] == lm_del->id);
00364 
00365   // keypoint now directs to new landmark
00366   n->kpt_to_landmark[kpt] = new_lm_id;
00367 //  n->visible_landmarks.erase(lm_del->id);
00368 
00369   // and new landmark gets new observation
00370   lm_1->observations[n->id_] = kpt;
00371 
00372  }
00373 
00374 
00375  // add new edges for the new observations
00376  // updateLandmarkInGraph(lm_1);
00377 
00378 
00379 }
00380 #endif
00381 


rgbdslam_v2
Author(s): Felix Endres, Juergen Hess, Nikolas Engelhard
autogenerated on Thu Jun 6 2019 21:49:45