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
00055 params_.image_dir = params_.work_dir;
00056
00057
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
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
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
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
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
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
00129 hash_table_.clear();
00130 img_id_ = 0;
00131 }
00132
00135 void haloc::LoopClosure::finalize()
00136 {
00137
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
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
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
00168 if (!hash_.isInitialized())
00169 hash_.init(query_.getDesc());
00170
00171
00172 hash_table_.push_back(make_pair(query_.getId(), hash_.getHash(query_.getDesc())));
00173
00174
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
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
00208 if (!hash_.isInitialized())
00209 hash_.init(query_.getDesc());
00210
00211
00212 hash_table_.push_back(make_pair(query_.getId(), hash_.getHash(query_.getDesc())));
00213
00214
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
00277 candidates.clear();
00278
00279
00280 if ((int)hash_table_.size() <= params_.min_neighbor) return;
00281
00282
00283 vector< pair<int,float> > best_matchings;
00284 getBestMatchings(image_id, params_.n_candidates, best_matchings);
00285
00286
00287 vector< pair<int,float> > cur_likelihood;
00288 buildLikelihoodVector(best_matchings, cur_likelihood);
00289
00290
00291 vector<float> matchings_likelihood;
00292 getMatchingsLikelihood(best_matchings, matchings_likelihood, cur_likelihood, prev_likelihood_);
00293
00294
00295 prev_likelihood_ = cur_likelihood;
00296
00297
00298 if (best_matchings.size() < 2) return;
00299
00300
00301 vector< vector<int> > groups;
00302 groupSimilarImages(best_matchings, groups);
00303
00304
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
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
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
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
00355 vector< pair<int,float> > hash_matching;
00356 getCandidates(hash_matching);
00357 if (hash_matching.size() == 0) return false;
00358
00359
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
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
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
00391 if (valid)
00392 {
00393
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
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
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
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
00438 string file_a = params_.work_dir+"/"+lexical_cast<string>(img_id_a)+".yml";
00439 Image img_a = getImage(file_a);
00440
00441
00442 string file_b = params_.work_dir+"/"+lexical_cast<string>(img_id_b)+".yml";
00443 Image img_b = getImage(file_b);
00444
00445
00446 bool valid = compute(img_a, img_b, matches, inliers, trans);
00447
00448
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
00505 matches = 0;
00506 inliers = 0;
00507
00508
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
00529 if (matches < params_.min_matches)
00530 return false;
00531
00532
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
00545 if (candidate_3d.size() != 0)
00546 candidate_matched_3d_points.push_back(candidate_3d[desc_matches[i].queryIdx]);
00547 }
00548
00549
00550 if (candidate_3d.size() == 0)
00551 {
00552
00553 Mat status;
00554 Mat F = findFundamentalMat(candidate_matched_kp, query_matched_kp, FM_RANSAC, params_.epipolar_thresh, 0.999, status);
00555
00556
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
00563 inliers = (int)cv::sum(status)[0];
00564 if (inliers < params_.min_inliers)
00565 return false;
00566 }
00567 else
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
00577 inliers = (int)solvepnp_inliers.size();
00578 if (inliers < params_.min_inliers)
00579 return false;
00580
00581
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
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
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
00627 vector<float> hash_q = hash_table_[image_id].second;
00628
00629
00630 vector< pair<int,float> > all_matchings;
00631 for (uint i=0; i<hash_table_.size()-params_.min_neighbor-1; i++)
00632 {
00633
00634 if (hash_table_[i].first == image_id) continue;
00635
00636
00637 if (find(no_candidates.begin(), no_candidates.end(), hash_table_[i].first) != no_candidates.end())
00638 continue;
00639
00640
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
00647 sort(all_matchings.begin(), all_matchings.end(), haloc::Utils::sortByMatching);
00648
00649
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
00665 likelihood.clear();
00666
00667
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
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
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
00693 float prob = 0.0;
00694 for (uint j=0; j<hash_matchings.size(); j++)
00695 {
00696
00697 math::normal_distribution<> nd((float)hash_matchings[j].first, 2.0);
00698
00699
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
00722 matchings_likelihood.clear();
00723
00724
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
00734 for (uint i=0; i<matchings.size(); i++)
00735 {
00736
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
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
00755 matchings_likelihood.push_back(prev_prob + cur_prob);
00756 }
00757
00758
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
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
00784 vector<int> last_group = groups.back();
00785
00786
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
00796 last_group.push_back(matchings[i].first);
00797
00798
00799 groups.pop_back();
00800 groups.push_back(last_group);
00801
00802
00803 matchings.erase(matchings.begin() + i);
00804
00805 new_insertion = true;
00806 break;
00807 }
00808 }
00809
00810
00811 if (matchings.size() == 0)
00812 {
00813 finish = true;
00814 continue;
00815 }
00816
00817
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
00836 Image img;
00837
00838
00839 if ( !fs::exists(img_file) ) return img;
00840
00841
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
00858 img.setId(id);
00859 img.setKp(kp);
00860 img.setDesc(desc);
00861 img.set3D(p3d);
00862
00863 return img;
00864 }