github.com/kaydxh/golang@v0.0.131/pkg/gocv/cgo/third_path/opencv4/include/opencv2/flann/kdtree_index.h (about) 1 /*********************************************************************** 2 * Software License Agreement (BSD License) 3 * 4 * Copyright 2008-2009 Marius Muja (mariusm@cs.ubc.ca). All rights reserved. 5 * Copyright 2008-2009 David G. Lowe (lowe@cs.ubc.ca). All rights reserved. 6 * 7 * THE BSD LICENSE 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 *************************************************************************/ 30 31 #ifndef OPENCV_FLANN_KDTREE_INDEX_H_ 32 #define OPENCV_FLANN_KDTREE_INDEX_H_ 33 34 //! @cond IGNORED 35 36 #include <algorithm> 37 #include <map> 38 #include <cstring> 39 40 #include "nn_index.h" 41 #include "dynamic_bitset.h" 42 #include "matrix.h" 43 #include "result_set.h" 44 #include "heap.h" 45 #include "allocator.h" 46 #include "random.h" 47 #include "saving.h" 48 49 50 namespace cvflann 51 { 52 53 struct KDTreeIndexParams : public IndexParams 54 { 55 KDTreeIndexParams(int trees = 4) 56 { 57 (*this)["algorithm"] = FLANN_INDEX_KDTREE; 58 (*this)["trees"] = trees; 59 } 60 }; 61 62 63 /** 64 * Randomized kd-tree index 65 * 66 * Contains the k-d trees and other information for indexing a set of points 67 * for nearest-neighbor matching. 68 */ 69 template <typename Distance> 70 class KDTreeIndex : public NNIndex<Distance> 71 { 72 public: 73 typedef typename Distance::ElementType ElementType; 74 typedef typename Distance::ResultType DistanceType; 75 76 77 /** 78 * KDTree constructor 79 * 80 * Params: 81 * inputData = dataset with the input features 82 * params = parameters passed to the kdtree algorithm 83 */ 84 KDTreeIndex(const Matrix<ElementType>& inputData, const IndexParams& params = KDTreeIndexParams(), 85 Distance d = Distance() ) : 86 dataset_(inputData), index_params_(params), distance_(d) 87 { 88 size_ = dataset_.rows; 89 veclen_ = dataset_.cols; 90 91 trees_ = get_param(index_params_,"trees",4); 92 tree_roots_ = new NodePtr[trees_]; 93 94 // Create a permutable array of indices to the input vectors. 95 vind_.resize(size_); 96 for (size_t i = 0; i < size_; ++i) { 97 vind_[i] = int(i); 98 } 99 100 mean_ = new DistanceType[veclen_]; 101 var_ = new DistanceType[veclen_]; 102 } 103 104 105 KDTreeIndex(const KDTreeIndex&); 106 KDTreeIndex& operator=(const KDTreeIndex&); 107 108 /** 109 * Standard destructor 110 */ 111 ~KDTreeIndex() 112 { 113 if (tree_roots_!=NULL) { 114 delete[] tree_roots_; 115 } 116 delete[] mean_; 117 delete[] var_; 118 } 119 120 /** 121 * Builds the index 122 */ 123 void buildIndex() CV_OVERRIDE 124 { 125 /* Construct the randomized trees. */ 126 for (int i = 0; i < trees_; i++) { 127 /* Randomize the order of vectors to allow for unbiased sampling. */ 128 #ifndef OPENCV_FLANN_USE_STD_RAND 129 cv::randShuffle(vind_); 130 #else 131 std::random_shuffle(vind_.begin(), vind_.end()); 132 #endif 133 134 tree_roots_[i] = divideTree(&vind_[0], int(size_) ); 135 } 136 } 137 138 139 flann_algorithm_t getType() const CV_OVERRIDE 140 { 141 return FLANN_INDEX_KDTREE; 142 } 143 144 145 void saveIndex(FILE* stream) CV_OVERRIDE 146 { 147 save_value(stream, trees_); 148 for (int i=0; i<trees_; ++i) { 149 save_tree(stream, tree_roots_[i]); 150 } 151 } 152 153 154 155 void loadIndex(FILE* stream) CV_OVERRIDE 156 { 157 load_value(stream, trees_); 158 if (tree_roots_!=NULL) { 159 delete[] tree_roots_; 160 } 161 tree_roots_ = new NodePtr[trees_]; 162 for (int i=0; i<trees_; ++i) { 163 load_tree(stream,tree_roots_[i]); 164 } 165 166 index_params_["algorithm"] = getType(); 167 index_params_["trees"] = tree_roots_; 168 } 169 170 /** 171 * Returns size of index. 172 */ 173 size_t size() const CV_OVERRIDE 174 { 175 return size_; 176 } 177 178 /** 179 * Returns the length of an index feature. 180 */ 181 size_t veclen() const CV_OVERRIDE 182 { 183 return veclen_; 184 } 185 186 /** 187 * Computes the inde memory usage 188 * Returns: memory used by the index 189 */ 190 int usedMemory() const CV_OVERRIDE 191 { 192 return int(pool_.usedMemory+pool_.wastedMemory+dataset_.rows*sizeof(int)); // pool memory and vind array memory 193 } 194 195 /** 196 * Find set of nearest neighbors to vec. Their indices are stored inside 197 * the result object. 198 * 199 * Params: 200 * result = the result object in which the indices of the nearest-neighbors are stored 201 * vec = the vector for which to search the nearest neighbors 202 * maxCheck = the maximum number of restarts (in a best-bin-first manner) 203 */ 204 void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE 205 { 206 const int maxChecks = get_param(searchParams,"checks", 32); 207 const float epsError = 1+get_param(searchParams,"eps",0.0f); 208 const bool explore_all_trees = get_param(searchParams,"explore_all_trees",false); 209 210 if (maxChecks==FLANN_CHECKS_UNLIMITED) { 211 getExactNeighbors(result, vec, epsError); 212 } 213 else { 214 getNeighbors(result, vec, maxChecks, epsError, explore_all_trees); 215 } 216 } 217 218 IndexParams getParameters() const CV_OVERRIDE 219 { 220 return index_params_; 221 } 222 223 private: 224 225 226 /*--------------------- Internal Data Structures --------------------------*/ 227 struct Node 228 { 229 /** 230 * Dimension used for subdivision. 231 */ 232 int divfeat; 233 /** 234 * The values used for subdivision. 235 */ 236 DistanceType divval; 237 /** 238 * The child nodes. 239 */ 240 Node* child1, * child2; 241 }; 242 typedef Node* NodePtr; 243 typedef BranchStruct<NodePtr, DistanceType> BranchSt; 244 typedef BranchSt* Branch; 245 246 247 248 void save_tree(FILE* stream, NodePtr tree) 249 { 250 save_value(stream, *tree); 251 if (tree->child1!=NULL) { 252 save_tree(stream, tree->child1); 253 } 254 if (tree->child2!=NULL) { 255 save_tree(stream, tree->child2); 256 } 257 } 258 259 260 void load_tree(FILE* stream, NodePtr& tree) 261 { 262 tree = pool_.allocate<Node>(); 263 load_value(stream, *tree); 264 if (tree->child1!=NULL) { 265 load_tree(stream, tree->child1); 266 } 267 if (tree->child2!=NULL) { 268 load_tree(stream, tree->child2); 269 } 270 } 271 272 273 /** 274 * Create a tree node that subdivides the list of vecs from vind[first] 275 * to vind[last]. The routine is called recursively on each sublist. 276 * Place a pointer to this new tree node in the location pTree. 277 * 278 * Params: pTree = the new node to create 279 * first = index of the first vector 280 * last = index of the last vector 281 */ 282 NodePtr divideTree(int* ind, int count) 283 { 284 NodePtr node = pool_.allocate<Node>(); // allocate memory 285 286 /* If too few exemplars remain, then make this a leaf node. */ 287 if ( count == 1) { 288 node->child1 = node->child2 = NULL; /* Mark as leaf node. */ 289 node->divfeat = *ind; /* Store index of this vec. */ 290 } 291 else { 292 int idx; 293 int cutfeat; 294 DistanceType cutval; 295 meanSplit(ind, count, idx, cutfeat, cutval); 296 297 node->divfeat = cutfeat; 298 node->divval = cutval; 299 node->child1 = divideTree(ind, idx); 300 node->child2 = divideTree(ind+idx, count-idx); 301 } 302 303 return node; 304 } 305 306 307 /** 308 * Choose which feature to use in order to subdivide this set of vectors. 309 * Make a random choice among those with the highest variance, and use 310 * its variance as the threshold value. 311 */ 312 void meanSplit(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval) 313 { 314 memset(mean_,0,veclen_*sizeof(DistanceType)); 315 memset(var_,0,veclen_*sizeof(DistanceType)); 316 317 /* Compute mean values. Only the first SAMPLE_MEAN values need to be 318 sampled to get a good estimate. 319 */ 320 int cnt = std::min((int)SAMPLE_MEAN+1, count); 321 for (int j = 0; j < cnt; ++j) { 322 ElementType* v = dataset_[ind[j]]; 323 for (size_t k=0; k<veclen_; ++k) { 324 mean_[k] += v[k]; 325 } 326 } 327 for (size_t k=0; k<veclen_; ++k) { 328 mean_[k] /= cnt; 329 } 330 331 /* Compute variances (no need to divide by count). */ 332 for (int j = 0; j < cnt; ++j) { 333 ElementType* v = dataset_[ind[j]]; 334 for (size_t k=0; k<veclen_; ++k) { 335 DistanceType dist = v[k] - mean_[k]; 336 var_[k] += dist * dist; 337 } 338 } 339 /* Select one of the highest variance indices at random. */ 340 cutfeat = selectDivision(var_); 341 cutval = mean_[cutfeat]; 342 343 int lim1, lim2; 344 planeSplit(ind, count, cutfeat, cutval, lim1, lim2); 345 346 if (lim1>count/2) index = lim1; 347 else if (lim2<count/2) index = lim2; 348 else index = count/2; 349 350 /* If either list is empty, it means that all remaining features 351 * are identical. Split in the middle to maintain a balanced tree. 352 */ 353 if ((lim1==count)||(lim2==0)) index = count/2; 354 } 355 356 357 /** 358 * Select the top RAND_DIM largest values from v and return the index of 359 * one of these selected at random. 360 */ 361 int selectDivision(DistanceType* v) 362 { 363 int num = 0; 364 size_t topind[RAND_DIM]; 365 366 /* Create a list of the indices of the top RAND_DIM values. */ 367 for (size_t i = 0; i < veclen_; ++i) { 368 if ((num < RAND_DIM)||(v[i] > v[topind[num-1]])) { 369 /* Put this element at end of topind. */ 370 if (num < RAND_DIM) { 371 topind[num++] = i; /* Add to list. */ 372 } 373 else { 374 topind[num-1] = i; /* Replace last element. */ 375 } 376 /* Bubble end value down to right location by repeated swapping. */ 377 int j = num - 1; 378 while (j > 0 && v[topind[j]] > v[topind[j-1]]) { 379 std::swap(topind[j], topind[j-1]); 380 --j; 381 } 382 } 383 } 384 /* Select a random integer in range [0,num-1], and return that index. */ 385 int rnd = rand_int(num); 386 return (int)topind[rnd]; 387 } 388 389 390 /** 391 * Subdivide the list of points by a plane perpendicular on axe corresponding 392 * to the 'cutfeat' dimension at 'cutval' position. 393 * 394 * On return: 395 * dataset[ind[0..lim1-1]][cutfeat]<cutval 396 * dataset[ind[lim1..lim2-1]][cutfeat]==cutval 397 * dataset[ind[lim2..count]][cutfeat]>cutval 398 */ 399 void planeSplit(int* ind, int count, int cutfeat, DistanceType cutval, int& lim1, int& lim2) 400 { 401 /* Move vector indices for left subtree to front of list. */ 402 int left = 0; 403 int right = count-1; 404 for (;; ) { 405 while (left<=right && dataset_[ind[left]][cutfeat]<cutval) ++left; 406 while (left<=right && dataset_[ind[right]][cutfeat]>=cutval) --right; 407 if (left>right) break; 408 std::swap(ind[left], ind[right]); ++left; --right; 409 } 410 lim1 = left; 411 right = count-1; 412 for (;; ) { 413 while (left<=right && dataset_[ind[left]][cutfeat]<=cutval) ++left; 414 while (left<=right && dataset_[ind[right]][cutfeat]>cutval) --right; 415 if (left>right) break; 416 std::swap(ind[left], ind[right]); ++left; --right; 417 } 418 lim2 = left; 419 } 420 421 /** 422 * Performs an exact nearest neighbor search. The exact search performs a full 423 * traversal of the tree. 424 */ 425 void getExactNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, float epsError) 426 { 427 // checkID -= 1; /* Set a different unique ID for each search. */ 428 429 if (trees_ > 1) { 430 fprintf(stderr,"It doesn't make any sense to use more than one tree for exact search"); 431 } 432 if (trees_>0) { 433 searchLevelExact(result, vec, tree_roots_[0], 0.0, epsError); 434 } 435 CV_Assert(result.full()); 436 } 437 438 /** 439 * Performs the approximate nearest-neighbor search. The search is approximate 440 * because the tree traversal is abandoned after a given number of descends in 441 * the tree. 442 */ 443 void getNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, 444 int maxCheck, float epsError, bool explore_all_trees = false) 445 { 446 int i; 447 BranchSt branch; 448 449 int checkCount = 0; 450 Heap<BranchSt>* heap = new Heap<BranchSt>((int)size_); 451 DynamicBitset checked(size_); 452 453 /* Search once through each tree down to root. */ 454 for (i = 0; i < trees_; ++i) { 455 searchLevel(result, vec, tree_roots_[i], 0, checkCount, maxCheck, 456 epsError, heap, checked, explore_all_trees); 457 if (!explore_all_trees && (checkCount >= maxCheck) && result.full()) 458 break; 459 } 460 461 /* Keep searching other branches from heap until finished. */ 462 while ( heap->popMin(branch) && (checkCount < maxCheck || !result.full() )) { 463 searchLevel(result, vec, branch.node, branch.mindist, checkCount, maxCheck, 464 epsError, heap, checked, false); 465 } 466 467 delete heap; 468 469 CV_Assert(result.full()); 470 } 471 472 473 /** 474 * Search starting from a given node of the tree. Based on any mismatches at 475 * higher levels, all exemplars below this level must have a distance of 476 * at least "mindistsq". 477 */ 478 void searchLevel(ResultSet<DistanceType>& result_set, const ElementType* vec, NodePtr node, DistanceType mindist, int& checkCount, int maxCheck, 479 float epsError, Heap<BranchSt>* heap, DynamicBitset& checked, bool explore_all_trees = false) 480 { 481 if (result_set.worstDist()<mindist) { 482 // printf("Ignoring branch, too far\n"); 483 return; 484 } 485 486 /* If this is a leaf node, then do check and return. */ 487 if ((node->child1 == NULL)&&(node->child2 == NULL)) { 488 /* Do not check same node more than once when searching multiple trees. 489 Once a vector is checked, we set its location in vind to the 490 current checkID. 491 */ 492 int index = node->divfeat; 493 if ( checked.test(index) || 494 (!explore_all_trees && (checkCount>=maxCheck) && result_set.full()) ) { 495 return; 496 } 497 checked.set(index); 498 checkCount++; 499 500 DistanceType dist = distance_(dataset_[index], vec, veclen_); 501 result_set.addPoint(dist,index); 502 503 return; 504 } 505 506 /* Which child branch should be taken first? */ 507 ElementType val = vec[node->divfeat]; 508 DistanceType diff = val - node->divval; 509 NodePtr bestChild = (diff < 0) ? node->child1 : node->child2; 510 NodePtr otherChild = (diff < 0) ? node->child2 : node->child1; 511 512 /* Create a branch record for the branch not taken. Add distance 513 of this feature boundary (we don't attempt to correct for any 514 use of this feature in a parent node, which is unlikely to 515 happen and would have only a small effect). Don't bother 516 adding more branches to heap after halfway point, as cost of 517 adding exceeds their value. 518 */ 519 520 DistanceType new_distsq = mindist + distance_.accum_dist(val, node->divval, node->divfeat); 521 // if (2 * checkCount < maxCheck || !result.full()) { 522 if ((new_distsq*epsError < result_set.worstDist())|| !result_set.full()) { 523 heap->insert( BranchSt(otherChild, new_distsq) ); 524 } 525 526 /* Call recursively to search next level down. */ 527 searchLevel(result_set, vec, bestChild, mindist, checkCount, maxCheck, epsError, heap, checked); 528 } 529 530 /** 531 * Performs an exact search in the tree starting from a node. 532 */ 533 void searchLevelExact(ResultSet<DistanceType>& result_set, const ElementType* vec, const NodePtr node, DistanceType mindist, const float epsError) 534 { 535 /* If this is a leaf node, then do check and return. */ 536 if ((node->child1 == NULL)&&(node->child2 == NULL)) { 537 int index = node->divfeat; 538 DistanceType dist = distance_(dataset_[index], vec, veclen_); 539 result_set.addPoint(dist,index); 540 return; 541 } 542 543 /* Which child branch should be taken first? */ 544 ElementType val = vec[node->divfeat]; 545 DistanceType diff = val - node->divval; 546 NodePtr bestChild = (diff < 0) ? node->child1 : node->child2; 547 NodePtr otherChild = (diff < 0) ? node->child2 : node->child1; 548 549 /* Create a branch record for the branch not taken. Add distance 550 of this feature boundary (we don't attempt to correct for any 551 use of this feature in a parent node, which is unlikely to 552 happen and would have only a small effect). Don't bother 553 adding more branches to heap after halfway point, as cost of 554 adding exceeds their value. 555 */ 556 557 DistanceType new_distsq = mindist + distance_.accum_dist(val, node->divval, node->divfeat); 558 559 /* Call recursively to search next level down. */ 560 searchLevelExact(result_set, vec, bestChild, mindist, epsError); 561 562 if (new_distsq*epsError<=result_set.worstDist()) { 563 searchLevelExact(result_set, vec, otherChild, new_distsq, epsError); 564 } 565 } 566 567 568 private: 569 570 enum 571 { 572 /** 573 * To improve efficiency, only SAMPLE_MEAN random values are used to 574 * compute the mean and variance at each level when building a tree. 575 * A value of 100 seems to perform as well as using all values. 576 */ 577 SAMPLE_MEAN = 100, 578 /** 579 * Top random dimensions to consider 580 * 581 * When creating random trees, the dimension on which to subdivide is 582 * selected at random from among the top RAND_DIM dimensions with the 583 * highest variance. A value of 5 works well. 584 */ 585 RAND_DIM=5 586 }; 587 588 589 /** 590 * Number of randomized trees that are used 591 */ 592 int trees_; 593 594 /** 595 * Array of indices to vectors in the dataset. 596 */ 597 std::vector<int> vind_; 598 599 /** 600 * The dataset used by this index 601 */ 602 const Matrix<ElementType> dataset_; 603 604 IndexParams index_params_; 605 606 size_t size_; 607 size_t veclen_; 608 609 610 DistanceType* mean_; 611 DistanceType* var_; 612 613 614 /** 615 * Array of k-d trees used to find neighbours. 616 */ 617 NodePtr* tree_roots_; 618 619 /** 620 * Pooled memory allocator. 621 * 622 * Using a pooled memory allocator is more efficient 623 * than allocating memory directly when there is a large 624 * number small of memory allocations. 625 */ 626 PooledAllocator pool_; 627 628 Distance distance_; 629 630 631 }; // class KDTreeForest 632 633 } 634 635 //! @endcond 636 637 #endif //OPENCV_FLANN_KDTREE_INDEX_H_