| 334 | |
| 335 | |
| 336 | std::pair<int, float> SCManager::detectLoopClosureID ( void ) |
| 337 | { |
| 338 | int loop_id { -1 }; // init with -1, -1 means no loop (== LeGO-LOAM's variable "closestHistoryFrameID") |
| 339 | |
| 340 | auto curr_key = polarcontext_invkeys_mat_.back(); // current observation (query) |
| 341 | auto curr_desc = polarcontexts_.back(); // current observation (query) |
| 342 | |
| 343 | /* |
| 344 | * step 1: candidates from ringkey tree_ |
| 345 | */ |
| 346 | if( (int)polarcontext_invkeys_mat_.size() < NUM_EXCLUDE_RECENT + 1) |
| 347 | { |
| 348 | std::pair<int, float> result {loop_id, 0.0}; |
| 349 | return result; // Early return |
| 350 | } |
| 351 | |
| 352 | // tree_ reconstruction (not mandatory to make everytime) |
| 353 | if( tree_making_period_conter % TREE_MAKING_PERIOD_ == 0) // to save computation cost |
| 354 | { |
| 355 | TicTocV2 t_tree_construction; |
| 356 | |
| 357 | polarcontext_invkeys_to_search_.clear(); |
| 358 | polarcontext_invkeys_to_search_.assign( polarcontext_invkeys_mat_.begin(), polarcontext_invkeys_mat_.end() - NUM_EXCLUDE_RECENT ) ; |
| 359 | |
| 360 | polarcontext_tree_.reset(); |
| 361 | polarcontext_tree_ = std::make_unique<InvKeyTree>(PC_NUM_RING /* dim */, polarcontext_invkeys_to_search_, 10 /* max leaf */ ); |
| 362 | // tree_ptr_->index->buildIndex(); // inernally called in the constructor of InvKeyTree (for detail, refer the nanoflann and KDtreeVectorOfVectorsAdaptor) |
| 363 | t_tree_construction.toc("Tree construction"); |
| 364 | } |
| 365 | tree_making_period_conter = tree_making_period_conter + 1; |
| 366 | |
| 367 | double min_dist = 10000000; // init with somthing large |
| 368 | int nn_align = 0; |
| 369 | int nn_idx = 0; |
| 370 | |
| 371 | // knn search |
| 372 | std::vector<size_t> candidate_indexes( NUM_CANDIDATES_FROM_TREE ); |
| 373 | std::vector<float> out_dists_sqr( NUM_CANDIDATES_FROM_TREE ); |
| 374 | |
| 375 | TicTocV2 t_tree_search; |
| 376 | nanoflann::KNNResultSet<float> knnsearch_result( NUM_CANDIDATES_FROM_TREE ); |
| 377 | knnsearch_result.init( &candidate_indexes[0], &out_dists_sqr[0] ); |
| 378 | polarcontext_tree_->index->findNeighbors( knnsearch_result, &curr_key[0] /* query */, nanoflann::SearchParams(10) ); |
| 379 | t_tree_search.toc("Tree search"); |
| 380 | |
| 381 | /* |
| 382 | * step 2: pairwise distance (find optimal columnwise best-fit using cosine distance) |
| 383 | */ |
| 384 | TicTocV2 t_calc_dist; |
| 385 | for ( int candidate_iter_idx = 0; candidate_iter_idx < NUM_CANDIDATES_FROM_TREE; candidate_iter_idx++ ) |
| 386 | { |
| 387 | MatrixXd polarcontext_candidate = polarcontexts_[ candidate_indexes[candidate_iter_idx] ]; |
| 388 | std::pair<double, int> sc_dist_result = distanceBtnScanContext( curr_desc, polarcontext_candidate ); |
| 389 | |
| 390 | double candidate_dist = sc_dist_result.first; |
| 391 | int candidate_align = sc_dist_result.second; |
| 392 | |
| 393 | if( candidate_dist < min_dist ) |
no test coverage detected