lc.cpp
Go to the documentation of this file.
00001 #include "libhaloc/lc.h"
00002 #include "libhaloc/utils.h"
00003 #include <iostream>
00004 #include <numeric>
00005 #include <stdlib.h>
00006 #include <fstream>
00007 #include <sstream>
00008 #include <string>
00009 #include <boost/filesystem.hpp>
00010 #include <boost/algorithm/string.hpp>
00011 #include <boost/lexical_cast.hpp>
00012 #include <boost/math/distributions.hpp>
00013 #include <cv.h>
00014 #include <highgui.h>
00015 
00016 #include "opencv2/core/core.hpp"
00017 #include "opencv2/highgui/highgui.hpp"
00018 #include "opencv2/features2d/features2d.hpp"
00019 
00020 using namespace boost;
00021 namespace fs=filesystem;
00022 
00025 haloc::LoopClosure::Params::Params() :
00026   work_dir(""),
00027   image_dir(""),
00028   num_proj(DEFAULT_NUM_PROJ),
00029   desc_type("SIFT"),
00030   desc_matching_type("CROSSCHECK"),
00031   desc_thresh_ratio(DEFAULT_DESC_THRESH_RATIO),
00032   epipolar_thresh(DEFAULT_EPIPOLAR_THRESH),
00033   min_neighbor(DEFAULT_MIN_NEIGHBOR),
00034   n_candidates(DEFAULT_N_CANDIDATES),
00035   group_range(DEFAULT_GROUP_RANGE),
00036   min_matches(DEFAULT_MIN_MATCHES),
00037   min_inliers(DEFAULT_MIN_INLIERS),
00038   max_reproj_err(DEFAULT_MAX_REPROJ_ERR),
00039   verbose(DEFAULT_VERBOSE),
00040   save_images(DEFAULT_SAVE_IMAGES)
00041 {}
00042 
00045 haloc::LoopClosure::LoopClosure(){}
00046 
00050 void haloc::LoopClosure::setParams(const Params& params)
00051 {
00052   params_ = params;
00053 
00054   // Will be the same
00055   params_.image_dir = params_.work_dir;
00056 
00057   // Log
00058   cout << "  work_dir           = " << params_.work_dir << endl;
00059   cout << "  image_dir          = " << params_.image_dir << endl;
00060   cout << "  num_proj           = " << params_.num_proj << endl;
00061   cout << "  desc_type          = " << params_.desc_type << endl;
00062   cout << "  desc_matching_type = " << params_.desc_matching_type << endl;
00063   cout << "  desc_thresh_ratio  = " << params_.desc_thresh_ratio << endl;
00064   cout << "  epipolar_thresh    = " << params_.epipolar_thresh << endl;
00065   cout << "  min_neighbor       = " << params_.min_neighbor << endl;
00066   cout << "  n_candidates       = " << params_.n_candidates << endl;
00067   cout << "  group_range        = " << params_.group_range << endl;
00068   cout << "  min_matches        = " << params_.min_matches << endl;
00069   cout << "  min_inliers        = " << params_.min_inliers << endl;
00070   cout << "  max_reproj_err     = " << params_.max_reproj_err << endl;
00071   cout << "  verbose            = " << params_.verbose << endl;
00072   cout << "  save_images        = " << params_.save_images << endl;
00073 
00074 }
00075 
00079 void haloc::LoopClosure::setCameraModel(image_geometry::StereoCameraModel stereo_camera_model,
00080                                         Mat camera_matrix)
00081 {
00082   query_.setCameraModel(stereo_camera_model);
00083   camera_matrix_ = camera_matrix;
00084 }
00085 
00088 void haloc::LoopClosure::init()
00089 {
00090   // Working directory sanity check
00091   if (params_.work_dir[params_.work_dir.length()-1] != '/')
00092     params_.work_dir += "/haloc_" + lexical_cast<string>(time(0));
00093   else
00094     params_.work_dir += "haloc_" + lexical_cast<string>(time(0));
00095 
00096   // Create the directory to store the keypoints and descriptors
00097   if (fs::is_directory(params_.work_dir))
00098     fs::remove_all(params_.work_dir);
00099   fs::path dir(params_.work_dir);
00100   if (!fs::create_directory(dir))
00101     ROS_ERROR("[Haloc:] ERROR -> Impossible to create the execution directory.");
00102 
00103   // Image directory sanity check
00104   if (params_.save_images)
00105   {
00106     if (params_.image_dir[params_.image_dir.length()-1] != '/')
00107       params_.image_dir += "/images/";
00108     else
00109       params_.image_dir += "images/";
00110 
00111     // Create the directory to store the keypoints and descriptors
00112     if (fs::is_directory(params_.image_dir))
00113       fs::remove_all(params_.image_dir);
00114     fs::path dir(params_.image_dir);
00115     if (!fs::create_directory(dir))
00116       ROS_ERROR("[Haloc:] ERROR -> Impossible to create the image directory.");
00117   }
00118 
00119   // Initialize image properties
00120   haloc::Image::Params img_params;
00121   img_params.desc_type = params_.desc_type;
00122   img_params.desc_matching_type = params_.desc_matching_type;
00123   img_params.desc_thresh_ratio = params_.desc_thresh_ratio;
00124   img_params.min_matches = params_.min_matches;
00125   img_params.epipolar_thresh = params_.epipolar_thresh;
00126   query_.setParams(img_params);
00127 
00128   // Init main variables
00129   hash_table_.clear();
00130   img_id_ = 0;
00131 }
00132 
00135 void haloc::LoopClosure::finalize()
00136 {
00137   // Log information
00138   if (params_.verbose && lc_candidate_positions_.size() > 0)
00139   {
00140     double sum = std::accumulate(lc_candidate_positions_.begin(), lc_candidate_positions_.end(), 0.0);
00141     double mean = sum / lc_candidate_positions_.size();
00142     ROS_INFO_STREAM("[libhaloc:] Mean loop closure candidate position: " << mean << "/" << params_.n_candidates << ".");
00143   }
00144 
00145   // Remove the temporal directory
00146   if (fs::is_directory(params_.work_dir))
00147     fs::remove_all(params_.work_dir);
00148 }
00149 
00150 
00155 int haloc::LoopClosure::setNode(Mat img)
00156 {
00157   // Set the image
00158   if (!query_.setMono(img_id_, img))
00159     return -1;
00160 
00161   if (params_.save_images)
00162   {
00163     string path = params_.image_dir + lexical_cast<string>(img_id_) + ".png";
00164     imwrite(path, img);
00165   }
00166 
00167   // Initialize hash
00168   if (!hash_.isInitialized())
00169     hash_.init(query_.getDesc());
00170 
00171   // Save hash to table
00172   hash_table_.push_back(make_pair(query_.getId(), hash_.getHash(query_.getDesc())));
00173 
00174   // Save kp and descriptors
00175   vector<Point3f> empty;
00176   FileStorage fs(params_.work_dir+"/"+lexical_cast<string>(img_id_)+".yml", FileStorage::WRITE);
00177   write(fs, "id", query_.getId());
00178   write(fs, "kp", query_.getKp());
00179   write(fs, "desc", query_.getDesc());
00180   write(fs, "threed", empty);
00181   fs.release();
00182   img_id_++;
00183 
00184   return query_.getId();
00185 }
00186 
00187 
00193 int haloc::LoopClosure::setNode(Mat img_l, Mat img_r)
00194 {
00195   // Set the images
00196   if (!query_.setStereo(img_id_, img_l, img_r))
00197     return -1;
00198 
00199   if (params_.save_images)
00200   {
00201     string path = params_.image_dir + lexical_cast<string>(img_id_) + "_l.png";
00202     imwrite(path, img_l);
00203     path = params_.image_dir + lexical_cast<string>(img_id_) + "_r.png";
00204     imwrite(path, img_r);
00205   }
00206 
00207   // Initialize hash
00208   if (!hash_.isInitialized())
00209     hash_.init(query_.getDesc());
00210 
00211   // Save hash to table
00212   hash_table_.push_back(make_pair(query_.getId(), hash_.getHash(query_.getDesc())));
00213 
00214   // Save kp and descriptors
00215   FileStorage fs(params_.work_dir+"/"+lexical_cast<string>(img_id_)+".yml", FileStorage::WRITE);
00216   write(fs, "id", query_.getId());
00217   write(fs, "kp", query_.getKp());
00218   write(fs, "desc", query_.getDesc());
00219   write(fs, "threed", query_.get3D());
00220   fs.release();
00221   img_id_++;
00222 
00223   return query_.getId();
00224 }
00225 
00231 bool haloc::LoopClosure::getHash(int img_id, vector<float>& hash)
00232 {
00233   hash.clear();
00234   for (uint i=0; i<hash_table_.size(); i++)
00235   {
00236     if (hash_table_[i].first == img_id)
00237     {
00238       hash = hash_table_[i].second;
00239       return true;
00240     }
00241   }
00242   return false;
00243 }
00244 
00251 bool haloc::LoopClosure::hashMatching(int img_id_a, int img_id_b, float& matching)
00252 {
00253   matching = -1.0;
00254   vector<float> hash_a, hash_b;
00255   if(!getHash(img_id_a, hash_a)) return false;
00256   if(!getHash(img_id_b, hash_b)) return false;
00257   matching = hash_.match(hash_a, hash_b);
00258   return true;
00259 }
00260 
00264 void haloc::LoopClosure::getCandidates(vector< pair<int,float> >& candidates)
00265 {
00266   getCandidates(img_id_-1, candidates);
00267 }
00268 
00273 void haloc::LoopClosure::getCandidates(int image_id,
00274                                        vector< pair<int,float> >& candidates)
00275 {
00276   // Init
00277   candidates.clear();
00278 
00279   // Check if enough neighbors
00280   if ((int)hash_table_.size() <= params_.min_neighbor) return;
00281 
00282   // Query matching versus all the hash table
00283   vector< pair<int,float> > best_matchings;
00284   getBestMatchings(image_id, params_.n_candidates, best_matchings);
00285 
00286   // Build the likelihood vector
00287   vector< pair<int,float> > cur_likelihood;
00288   buildLikelihoodVector(best_matchings, cur_likelihood);
00289 
00290   // Merge current likelihood with the previous
00291   vector<float> matchings_likelihood;
00292   getMatchingsLikelihood(best_matchings, matchings_likelihood, cur_likelihood, prev_likelihood_);
00293 
00294   // Save for the next execution
00295   prev_likelihood_ = cur_likelihood;
00296 
00297   // Sanity check
00298   if (best_matchings.size() < 2) return;
00299 
00300   // Group similar images
00301   vector< vector<int> > groups;
00302   groupSimilarImages(best_matchings, groups);
00303 
00304   // Order matchings by likelihood
00305   vector< pair<int, float> > sorted_matchings;
00306   for (uint i=0; i<best_matchings.size(); i++)
00307     sorted_matchings.push_back(make_pair(best_matchings[i].first, matchings_likelihood[i]));
00308   sort(sorted_matchings.begin(), sorted_matchings.end(), haloc::Utils::sortByLikelihood);
00309 
00310   // Build the output
00311   for (uint i=0; i<groups.size(); i++)
00312   {
00313     int group_id = -1;
00314     float group_likelihood = 0.0;
00315     for (uint j=0; j<groups[i].size(); j++)
00316     {
00317       // Search this index into the matchings vector
00318       for (uint k=0; k<sorted_matchings.size(); k++)
00319       {
00320         if (groups[i][j] == sorted_matchings[k].first)
00321         {
00322           if (group_id < 0) group_id = groups[i][j];
00323           group_likelihood += sorted_matchings[k].second;
00324           break;
00325         }
00326       }
00327     }
00328     candidates.push_back(make_pair(group_id, group_likelihood));
00329   }
00330 
00331   // Sort candidates by likelihood
00332   sort(candidates.begin(), candidates.end(), haloc::Utils::sortByLikelihood);
00333 
00334 }
00335 
00340 bool haloc::LoopClosure::getLoopClosure(int& lc_img_id)
00341 {
00342   tf::Transform trans;
00343   return getLoopClosure(lc_img_id, trans);
00344 }
00345 
00351 bool haloc::LoopClosure::getLoopClosure(int& lc_img_id,
00352                                         tf::Transform& trans)
00353 {
00354   // Get the candidates to close loop
00355   vector< pair<int,float> > hash_matching;
00356   getCandidates(hash_matching);
00357   if (hash_matching.size() == 0) return false;
00358 
00359   // Check for loop closure
00360   trans.setIdentity();
00361   lc_img_id = -1;
00362   int matches = 0;
00363   int max_matches = 0;
00364   int inliers = 0;
00365   int max_inliers = 0;
00366   bool valid = false;
00367   int final_img_idx = -1;
00368   string best_lc_found = "";
00369   for (uint i=0; i<hash_matching.size(); i++)
00370   {
00371     // Loop-closure?
00372     final_img_idx = i;
00373     string candidate_id = lexical_cast<string>(hash_matching[i].first);
00374     Image candidate = getImage(params_.work_dir+"/"+candidate_id+".yml");
00375     valid = compute(query_, candidate, matches, inliers, trans);
00376 
00377     // Log
00378     if (params_.verbose)
00379     {
00380       if (matches > max_matches)
00381       {
00382         max_matches = matches;
00383         max_inliers = inliers;
00384         best_lc_found = candidate_id;
00385       }
00386     }
00387     if (valid) break;
00388   }
00389 
00390   // Get the image of the loop closure
00391   if (valid)
00392   {
00393     // Store the loop closing information
00394     lc_img_id = hash_matching[final_img_idx].first;
00395     lc_candidate_positions_.push_back(final_img_idx+1);
00396     lc_found_.push_back(make_pair(lc_img_id, (img_id_ - 1) ));
00397 
00398     // Log
00399     if(params_.verbose)
00400       ROS_INFO_STREAM("[libhaloc:] LC by hash between nodes " <<
00401                       query_.getId() << " and " << lc_img_id <<
00402                       " (matches: " << matches << "; inliers: " <<
00403                       inliers << "; Position: " << final_img_idx+1 << "/" <<
00404                       params_.n_candidates << ").");
00405   }
00406   else
00407   {
00408     // Log
00409     if(params_.verbose && best_lc_found != "")
00410     {
00411       ROS_INFO_STREAM("[libhaloc:] No LC by hash, best candidate is " <<
00412                       best_lc_found << " (matches: " << max_matches <<
00413                       "; inliers: " << max_inliers << ").");
00414     }
00415   }
00416 
00417   // Return true if any valid loop closure has been found.
00418   return valid;
00419 }
00420 
00430 bool haloc::LoopClosure::getLoopClosure(int img_id_a,
00431                                         int img_id_b,
00432                                         tf::Transform& trans,
00433                                         int& matches,
00434                                         int& inliers,
00435                                         bool logging)
00436 {
00437   // Image a
00438   string file_a = params_.work_dir+"/"+lexical_cast<string>(img_id_a)+".yml";
00439   Image img_a = getImage(file_a);
00440 
00441   // Image b
00442   string file_b = params_.work_dir+"/"+lexical_cast<string>(img_id_b)+".yml";
00443   Image img_b = getImage(file_b);
00444 
00445   // Get the loop closing (if any)
00446   bool valid = compute(img_a, img_b, matches, inliers, trans);
00447 
00448   // If valid loop closure, save it
00449   if (valid)
00450   {
00451     lc_found_.push_back(make_pair(img_id_a, img_id_b));
00452   }
00453 
00454   if(params_.verbose && logging)
00455   {
00456     if (valid)
00457     {
00458       ROS_INFO_STREAM("[libhaloc:] LC by ID between " <<
00459                       img_id_a << " and " << img_id_b <<
00460                       " (matches: " << matches << "; inliers: " <<
00461                       inliers << ").");
00462     }
00463     else
00464     {
00465       ROS_INFO_STREAM("[libhaloc:] No LC by ID between " <<
00466                       img_id_a << " and " << img_id_b <<
00467                       " (matches: " << matches << "; inliers: " <<
00468                       inliers << ").");
00469     }
00470   }
00471   return valid;
00472 }
00473 
00481 bool haloc::LoopClosure::getLoopClosure(int img_id_a,
00482                                         int img_id_b,
00483                                         tf::Transform& trans,
00484                                         bool logging)
00485 {
00486   int matches, inliers;
00487   return getLoopClosure(img_id_a, img_id_b, trans, matches, inliers, logging);
00488 }
00489 
00498 bool haloc::LoopClosure::compute(Image query,
00499                                  Image candidate,
00500                                  int &matches,
00501                                  int &inliers,
00502                                  tf::Transform& trans)
00503 {
00504   // Initialize outputs
00505   matches = 0;
00506   inliers = 0;
00507 
00508   // Descriptors matching
00509   Mat match_mask;
00510   vector<DMatch> desc_matches;
00511   if(params_.desc_matching_type == "CROSSCHECK")
00512   {
00513     haloc::Utils::crossCheckThresholdMatching(candidate.getDesc(),
00514         query.getDesc(), params_.desc_thresh_ratio, match_mask, desc_matches);
00515   }
00516   else if (params_.desc_matching_type == "RATIO")
00517   {
00518     haloc::Utils::ratioMatching(candidate.getDesc(),
00519         query.getDesc(), params_.desc_thresh_ratio, match_mask, desc_matches);
00520   }
00521   else
00522   {
00523     ROS_ERROR("[Haloc:] ERROR -> desc_matching_type must be 'CROSSCHECK' or 'RATIO'");
00524   }
00525 
00526   matches = (int)desc_matches.size();
00527 
00528   // Matches threshold
00529   if (matches < params_.min_matches)
00530     return false;
00531 
00532   // Get the matched keypoints
00533   vector<KeyPoint> query_kp = query.getKp();
00534   vector<KeyPoint> candidate_kp = candidate.getKp();
00535   vector<Point3f> candidate_3d = candidate.get3D();
00536   vector<Point2f> query_matched_kp;
00537   vector<Point2f> candidate_matched_kp;
00538   vector<Point3f> candidate_matched_3d_points;
00539   for(int i=0; i<matches; i++)
00540   {
00541     query_matched_kp.push_back(query_kp[desc_matches[i].trainIdx].pt);
00542     candidate_matched_kp.push_back(candidate_kp[desc_matches[i].queryIdx].pt);
00543 
00544     // Only stereo
00545     if (candidate_3d.size() != 0)
00546       candidate_matched_3d_points.push_back(candidate_3d[desc_matches[i].queryIdx]);
00547   }
00548 
00549   // Proceed depending on mono or stereo
00550   if (candidate_3d.size() == 0) // Mono
00551   {
00552     // Check the epipolar geometry
00553     Mat status;
00554     Mat F = findFundamentalMat(candidate_matched_kp, query_matched_kp, FM_RANSAC, params_.epipolar_thresh, 0.999, status);
00555 
00556     // Is the fundamental matrix valid?
00557     Scalar f_sum_parts = cv::sum(F);
00558     float f_sum = (float)f_sum_parts[0] + (float)f_sum_parts[1] + (float)f_sum_parts[2];
00559     if (f_sum < 1e-3)
00560       return false;
00561 
00562     // Check inliers size
00563     inliers = (int)cv::sum(status)[0];
00564     if (inliers < params_.min_inliers)
00565       return false;
00566   }
00567   else // Stereo
00568   {
00569     Mat rvec, tvec;
00570     vector<int> solvepnp_inliers;
00571     solvePnPRansac(candidate_matched_3d_points, query_matched_kp, camera_matrix_,
00572                    cv::Mat(), rvec, tvec, false,
00573                    100, params_.max_reproj_err,
00574                    40, solvepnp_inliers);
00575 
00576     // Inliers threshold
00577     inliers = (int)solvepnp_inliers.size();
00578     if (inliers < params_.min_inliers)
00579       return false;
00580 
00581     // Save inliers matches
00582     if (params_.save_images)
00583     {
00584       vector<DMatch> final_inliers;
00585       for(int i=0; i<solvepnp_inliers.size(); i++)
00586       {
00587         int idx = solvepnp_inliers[i];
00588         final_inliers.push_back(desc_matches[idx]);
00589       }
00590       Mat img_inliers;
00591       string path_query = params_.image_dir + lexical_cast<string>(query.getId()) + "_l.png";
00592       string path_candidate = params_.image_dir + lexical_cast<string>(candidate.getId()) + "_l.png";
00593       string output = params_.image_dir + "inliers_" + lexical_cast<string>(query.getId()) + "_" + lexical_cast<string>(candidate.getId()) + ".png";
00594       Mat img_query = imread(path_query, CV_LOAD_IMAGE_COLOR);
00595       Mat img_candidate = imread(path_candidate, CV_LOAD_IMAGE_COLOR);
00596       drawMatches(img_candidate, candidate_kp, img_query, query_kp, final_inliers, img_inliers);
00597       imwrite(output, img_inliers);
00598     }
00599 
00600     trans = haloc::Utils::buildTransformation(rvec, tvec);
00601   }
00602 
00603   // If we arrive here, there is a loop closure.
00604   return true;
00605 }
00606 
00612 void haloc::LoopClosure::getBestMatchings(int image_id,
00613                                           int best_n,
00614                                           vector< pair<int,float> > &best_matchings)
00615 {
00616   // Create a list with the non-possible candidates (because they are already loop closings)
00617   vector<int> no_candidates;
00618   for (uint i=0; i<lc_found_.size(); i++)
00619   {
00620     if (lc_found_[i].first == image_id)
00621       no_candidates.push_back(lc_found_[i].second);
00622     if (lc_found_[i].second == image_id)
00623       no_candidates.push_back(lc_found_[i].first);
00624   }
00625 
00626   // Query hash
00627   vector<float> hash_q = hash_table_[image_id].second;
00628 
00629   // Loop over all the hashes stored
00630   vector< pair<int,float> > all_matchings;
00631   for (uint i=0; i<hash_table_.size()-params_.min_neighbor-1; i++)
00632   {
00633     // Do not compute the hash matching with itself
00634     if (hash_table_[i].first == image_id) continue;
00635 
00636     // Continue if candidate is in the no_candidates list
00637     if (find(no_candidates.begin(), no_candidates.end(), hash_table_[i].first) != no_candidates.end())
00638       continue;
00639 
00640     // Hash matching
00641     vector<float> hash_t = hash_table_[i].second;
00642     float m = hash_.match(hash_q, hash_t);
00643     all_matchings.push_back(make_pair(hash_table_[i].first, m));
00644   }
00645 
00646   // Sort the hash matchings
00647   sort(all_matchings.begin(), all_matchings.end(), haloc::Utils::sortByMatching);
00648 
00649   // Retrieve the best n matches
00650   best_matchings.clear();
00651   int max_size = best_n;
00652   if (max_size > all_matchings.size()) max_size = all_matchings.size();
00653   for (uint i=0; i<max_size; i++)
00654     best_matchings.push_back(all_matchings[i]);
00655 }
00656 
00661 void haloc::LoopClosure::buildLikelihoodVector(vector< pair<int,float> > hash_matchings,
00662                                                vector< pair<int,float> > &likelihood)
00663 {
00664   // Init
00665   likelihood.clear();
00666 
00667   // Get maximums and minimums of the hash matchings
00668   int min_idx = -1;
00669   int max_idx = -1;
00670   int min_hash = -1;
00671   int max_hash = -1;
00672   for (uint i=0; i<hash_matchings.size(); i++)
00673   {
00674     if (min_idx < 0 || hash_matchings[i].first < min_idx) min_idx = hash_matchings[i].first;
00675     if (max_idx < 0 || hash_matchings[i].first > max_idx) max_idx = hash_matchings[i].first;
00676     if (min_hash < 0 || hash_matchings[i].second < min_hash) min_hash = hash_matchings[i].second;
00677     if (max_hash < 0 || hash_matchings[i].second > max_hash) max_hash = hash_matchings[i].second;
00678   }
00679 
00680   // Normalize the hash values
00681   const float min_norm_val = 1.0;
00682   const float max_norm_val = 2.0;
00683   float m = (min_norm_val - max_norm_val) / (max_hash - min_hash);
00684   float n = max_norm_val - m*min_hash;
00685 
00686   // Build the probability vector
00687   int space = params_.group_range;
00688   for (int i=0; i<=(max_idx-min_idx)+2*space; i++)
00689   {
00690     int cur_idx = min_idx - space + i;
00691 
00692     // Compute the probability for every candidate
00693     float prob = 0.0;
00694     for (uint j=0; j<hash_matchings.size(); j++)
00695     {
00696       // Create the normal distribution for this matching
00697       math::normal_distribution<> nd((float)hash_matchings[j].first, 2.0);
00698 
00699       // Sanity check
00700       if (!isfinite(m))
00701         prob += min_norm_val * math::pdf(nd, (float)cur_idx);
00702       else
00703         prob += (m*hash_matchings[j].second + n) * math::pdf(nd, (float)cur_idx);
00704     }
00705     likelihood.push_back(make_pair(cur_idx,prob));
00706   }
00707 }
00708 
00716 void haloc::LoopClosure::getMatchingsLikelihood(vector< pair<int,float> > matchings,
00717                                                 vector<float> &matchings_likelihood,
00718                                                 vector< pair<int,float> > cur_likelihood,
00719                                                 vector< pair<int,float> > prev_likelihood)
00720 {
00721   // Init
00722   matchings_likelihood.clear();
00723 
00724   // Extract the vectors
00725   vector<int> cur_idx;
00726   for (uint i=0; i<cur_likelihood.size(); i++)
00727     cur_idx.push_back(cur_likelihood[i].first);
00728 
00729   vector<int> prev_idx;
00730   for (uint i=0; i<prev_likelihood.size(); i++)
00731     prev_idx.push_back(prev_likelihood[i].first);
00732 
00733   // For every matching
00734   for (uint i=0; i<matchings.size(); i++)
00735   {
00736     // Find previous value
00737     float prev_prob = 0.0;
00738     vector<int>::iterator itp = find(prev_idx.begin(), prev_idx.end(), matchings[i].first);
00739     if (itp != prev_idx.end())
00740     {
00741       int idx = distance(prev_idx.begin(), itp);
00742       prev_prob = prev_likelihood[idx].second;
00743     }
00744 
00745     // Find current value
00746     float cur_prob = 0.0;
00747     vector<int>::iterator itc = find(cur_idx.begin(), cur_idx.end(), matchings[i].first);
00748     if (itc != cur_idx.end())
00749     {
00750       int idx = distance(cur_idx.begin(), itc);
00751       cur_prob = cur_likelihood[idx].second;
00752     }
00753 
00754     // Add and save
00755     matchings_likelihood.push_back(prev_prob + cur_prob);
00756   }
00757 
00758   // Make the probability of sum = 1
00759   float x_norm = 0.0;
00760   for (uint i=0; i<matchings_likelihood.size(); i++)
00761     x_norm += fabs(matchings_likelihood[i]);
00762   for (uint i=0; i<matchings_likelihood.size(); i++)
00763     matchings_likelihood[i] = matchings_likelihood[i] / x_norm;
00764 }
00765 
00770 void haloc::LoopClosure::groupSimilarImages(vector< pair<int,float> > matchings,
00771                                             vector< vector<int> > &groups)
00772 {
00773   // Init groups vector
00774   groups.clear();
00775   vector<int> new_group;
00776   new_group.push_back(matchings[0].first);
00777   groups.push_back(new_group);
00778   matchings.erase(matchings.begin());
00779 
00780   bool finish = false;
00781   while(!finish)
00782   {
00783     // Get the last inserted group
00784     vector<int> last_group = groups.back();
00785 
00786     // Mean image index
00787     int sum = accumulate(last_group.begin(), last_group.end(), 0.0);
00788     float mean = (float)sum / (float)last_group.size();
00789 
00790     bool new_insertion = false;
00791     for (uint i=0; i<matchings.size(); i++)
00792     {
00793       if ( abs(mean - (float)matchings[i].first) < params_.group_range )
00794       {
00795         // Save id
00796         last_group.push_back(matchings[i].first);
00797 
00798         // Replace group
00799         groups.pop_back();
00800         groups.push_back(last_group);
00801 
00802         // Delete from matching list
00803         matchings.erase(matchings.begin() + i);
00804 
00805         new_insertion = true;
00806         break;
00807       }
00808     }
00809 
00810     // Finish?
00811     if (matchings.size() == 0)
00812     {
00813       finish = true;
00814       continue;
00815     }
00816 
00817     // Proceed depending on new insertion or not
00818     if (!new_insertion)
00819     {
00820       new_group.clear();
00821       new_group.push_back(matchings[0].first);
00822       groups.push_back(new_group);
00823       matchings.erase(matchings.begin());
00824     }
00825   }
00826 }
00827 
00828 
00833 haloc::Image haloc::LoopClosure::getImage(string img_file)
00834 {
00835   // Init
00836   Image img;
00837 
00838   // Sanity check
00839   if ( !fs::exists(img_file) ) return img;
00840 
00841   // Get the image keypoints and descriptors
00842   FileStorage fs;
00843   fs.open(img_file, FileStorage::READ);
00844   if (!fs.isOpened())
00845     ROS_ERROR("[Haloc:] ERROR -> Failed to open the image keypoints and descriptors.");
00846   int id;
00847   vector<KeyPoint> kp;
00848   Mat desc;
00849   vector<Point3f> p3d;
00850   fs["id"] >> id;
00851   fs["desc"] >> desc;
00852   fs["threed"] >> p3d;
00853   FileNode kp_node = fs["kp"];
00854   read(kp_node, kp);
00855   fs.release();
00856 
00857   // Set the properties of the image
00858   img.setId(id);
00859   img.setKp(kp);
00860   img.setDesc(desc);
00861   img.set3D(p3d);
00862 
00863   return img;
00864 }


libhaloc
Author(s): Pep Lluis Negre
autogenerated on Thu Jun 6 2019 21:25:00