EstervQrCode 2.0.0
Library for qr code manipulation
Loading...
Searching...
No Matches
kdtree_single_index.h
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_SINGLE_INDEX_H_
32#define OPENCV_FLANN_KDTREE_SINGLE_INDEX_H_
33
35
36#include <algorithm>
37#include <map>
38#include <cstring>
39
40#include "nn_index.h"
41#include "matrix.h"
42#include "result_set.h"
43#include "heap.h"
44#include "allocator.h"
45#include "random.h"
46#include "saving.h"
47
48namespace cvflann
49{
50
51struct KDTreeSingleIndexParams : public IndexParams
52{
53 KDTreeSingleIndexParams(int leaf_max_size = 10, bool reorder = true, int dim = -1)
54 {
55 (*this)["algorithm"] = FLANN_INDEX_KDTREE_SINGLE;
56 (*this)["leaf_max_size"] = leaf_max_size;
57 (*this)["reorder"] = reorder;
58 (*this)["dim"] = dim;
59 }
60};
61
62
69template <typename Distance>
70class KDTreeSingleIndex : public NNIndex<Distance>
71{
72public:
73 typedef typename Distance::ElementType ElementType;
74 typedef typename Distance::ResultType DistanceType;
75
76
84 KDTreeSingleIndex(const Matrix<ElementType>& inputData, const IndexParams& params = KDTreeSingleIndexParams(),
85 Distance d = Distance() ) :
86 dataset_(inputData), index_params_(params), distance_(d)
87 {
88 size_ = dataset_.rows;
89 dim_ = dataset_.cols;
90 root_node_ = 0;
91 int dim_param = get_param(params,"dim",-1);
92 if (dim_param>0) dim_ = dim_param;
93 leaf_max_size_ = get_param(params,"leaf_max_size",10);
94 reorder_ = get_param(params,"reorder",true);
95
96 // Create a permutable array of indices to the input vectors.
97 vind_.resize(size_);
98 for (size_t i = 0; i < size_; i++) {
99 vind_[i] = (int)i;
100 }
101 }
102
103 KDTreeSingleIndex(const KDTreeSingleIndex&);
104 KDTreeSingleIndex& operator=(const KDTreeSingleIndex&);
105
109 ~KDTreeSingleIndex()
110 {
111 if (reorder_) delete[] data_.data;
112 }
113
117 void buildIndex() CV_OVERRIDE
118 {
119 computeBoundingBox(root_bbox_);
120 root_node_ = divideTree(0, (int)size_, root_bbox_ ); // construct the tree
121
122 if (reorder_) {
123 delete[] data_.data;
124 data_ = cvflann::Matrix<ElementType>(new ElementType[size_*dim_], size_, dim_);
125 for (size_t i=0; i<size_; ++i) {
126 for (size_t j=0; j<dim_; ++j) {
127 data_[i][j] = dataset_[vind_[i]][j];
128 }
129 }
130 }
131 else {
132 data_ = dataset_;
133 }
134 }
135
136 flann_algorithm_t getType() const CV_OVERRIDE
137 {
138 return FLANN_INDEX_KDTREE_SINGLE;
139 }
140
141
142 void saveIndex(FILE* stream) CV_OVERRIDE
143 {
144 save_value(stream, size_);
145 save_value(stream, dim_);
146 save_value(stream, root_bbox_);
147 save_value(stream, reorder_);
148 save_value(stream, leaf_max_size_);
149 save_value(stream, vind_);
150 if (reorder_) {
151 save_value(stream, data_);
152 }
153 save_tree(stream, root_node_);
154 }
155
156
157 void loadIndex(FILE* stream) CV_OVERRIDE
158 {
159 load_value(stream, size_);
160 load_value(stream, dim_);
161 load_value(stream, root_bbox_);
162 load_value(stream, reorder_);
163 load_value(stream, leaf_max_size_);
164 load_value(stream, vind_);
165 if (reorder_) {
166 load_value(stream, data_);
167 }
168 else {
169 data_ = dataset_;
170 }
171 load_tree(stream, root_node_);
172
173
174 index_params_["algorithm"] = getType();
175 index_params_["leaf_max_size"] = leaf_max_size_;
176 index_params_["reorder"] = reorder_;
177 }
178
182 size_t size() const CV_OVERRIDE
183 {
184 return size_;
185 }
186
190 size_t veclen() const CV_OVERRIDE
191 {
192 return dim_;
193 }
194
199 int usedMemory() const CV_OVERRIDE
200 {
201 return (int)(pool_.usedMemory+pool_.wastedMemory+dataset_.rows*sizeof(int)); // pool memory and vind array memory
202 }
203
204
213 void knnSearch(const Matrix<ElementType>& queries, Matrix<int>& indices, Matrix<DistanceType>& dists, int knn, const SearchParams& params) CV_OVERRIDE
214 {
215 CV_Assert(queries.cols == veclen());
216 CV_Assert(indices.rows >= queries.rows);
217 CV_Assert(dists.rows >= queries.rows);
218 CV_Assert(int(indices.cols) >= knn);
219 CV_Assert(int(dists.cols) >= knn);
220
221 KNNSimpleResultSet<DistanceType> resultSet(knn);
222 for (size_t i = 0; i < queries.rows; i++) {
223 resultSet.init(indices[i], dists[i]);
224 findNeighbors(resultSet, queries[i], params);
225 }
226 }
227
228 IndexParams getParameters() const CV_OVERRIDE
229 {
230 return index_params_;
231 }
232
242 void findNeighbors(ResultSet<DistanceType>& result, const ElementType* vec, const SearchParams& searchParams) CV_OVERRIDE
243 {
244 float epsError = 1+get_param(searchParams,"eps",0.0f);
245
246 std::vector<DistanceType> dists(dim_,0);
247 DistanceType distsq = computeInitialDistances(vec, dists);
248 searchLevel(result, vec, root_node_, distsq, dists, epsError);
249 }
250
251private:
252
253
254 /*--------------------- Internal Data Structures --------------------------*/
255 struct Node
256 {
260 int left, right;
264 int divfeat;
268 DistanceType divlow, divhigh;
272 Node* child1, * child2;
273 };
274 typedef Node* NodePtr;
275
276
277 struct Interval
278 {
279 DistanceType low, high;
280 };
281
282 typedef std::vector<Interval> BoundingBox;
283
284 typedef BranchStruct<NodePtr, DistanceType> BranchSt;
285 typedef BranchSt* Branch;
286
287
288
289
290 void save_tree(FILE* stream, NodePtr tree)
291 {
292 save_value(stream, *tree);
293 if (tree->child1!=NULL) {
294 save_tree(stream, tree->child1);
295 }
296 if (tree->child2!=NULL) {
297 save_tree(stream, tree->child2);
298 }
299 }
300
301
302 void load_tree(FILE* stream, NodePtr& tree)
303 {
304 tree = pool_.allocate<Node>();
305 load_value(stream, *tree);
306 if (tree->child1!=NULL) {
307 load_tree(stream, tree->child1);
308 }
309 if (tree->child2!=NULL) {
310 load_tree(stream, tree->child2);
311 }
312 }
313
314
315 void computeBoundingBox(BoundingBox& bbox)
316 {
317 bbox.resize(dim_);
318 for (size_t i=0; i<dim_; ++i) {
319 bbox[i].low = (DistanceType)dataset_[0][i];
320 bbox[i].high = (DistanceType)dataset_[0][i];
321 }
322 for (size_t k=1; k<dataset_.rows; ++k) {
323 for (size_t i=0; i<dim_; ++i) {
324 if (dataset_[k][i]<bbox[i].low) bbox[i].low = (DistanceType)dataset_[k][i];
325 if (dataset_[k][i]>bbox[i].high) bbox[i].high = (DistanceType)dataset_[k][i];
326 }
327 }
328 }
329
330
340 NodePtr divideTree(int left, int right, BoundingBox& bbox)
341 {
342 NodePtr node = pool_.allocate<Node>(); // allocate memory
343
344 /* If too few exemplars remain, then make this a leaf node. */
345 if ( (right-left) <= leaf_max_size_) {
346 node->child1 = node->child2 = NULL; /* Mark as leaf node. */
347 node->left = left;
348 node->right = right;
349
350 // compute bounding-box of leaf points
351 for (size_t i=0; i<dim_; ++i) {
352 bbox[i].low = (DistanceType)dataset_[vind_[left]][i];
353 bbox[i].high = (DistanceType)dataset_[vind_[left]][i];
354 }
355 for (int k=left+1; k<right; ++k) {
356 for (size_t i=0; i<dim_; ++i) {
357 if (bbox[i].low>dataset_[vind_[k]][i]) bbox[i].low=(DistanceType)dataset_[vind_[k]][i];
358 if (bbox[i].high<dataset_[vind_[k]][i]) bbox[i].high=(DistanceType)dataset_[vind_[k]][i];
359 }
360 }
361 }
362 else {
363 int idx;
364 int cutfeat;
365 DistanceType cutval;
366 middleSplit_(&vind_[0]+left, right-left, idx, cutfeat, cutval, bbox);
367
368 node->divfeat = cutfeat;
369
370 BoundingBox left_bbox(bbox);
371 left_bbox[cutfeat].high = cutval;
372 node->child1 = divideTree(left, left+idx, left_bbox);
373
374 BoundingBox right_bbox(bbox);
375 right_bbox[cutfeat].low = cutval;
376 node->child2 = divideTree(left+idx, right, right_bbox);
377
378 node->divlow = left_bbox[cutfeat].high;
379 node->divhigh = right_bbox[cutfeat].low;
380
381 for (size_t i=0; i<dim_; ++i) {
382 bbox[i].low = std::min(left_bbox[i].low, right_bbox[i].low);
383 bbox[i].high = std::max(left_bbox[i].high, right_bbox[i].high);
384 }
385 }
386
387 return node;
388 }
389
390 void computeMinMax(int* ind, int count, int dim, ElementType& min_elem, ElementType& max_elem)
391 {
392 min_elem = dataset_[ind[0]][dim];
393 max_elem = dataset_[ind[0]][dim];
394 for (int i=1; i<count; ++i) {
395 ElementType val = dataset_[ind[i]][dim];
396 if (val<min_elem) min_elem = val;
397 if (val>max_elem) max_elem = val;
398 }
399 }
400
401 void middleSplit(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox)
402 {
403 // find the largest span from the approximate bounding box
404 ElementType max_span = bbox[0].high-bbox[0].low;
405 cutfeat = 0;
406 cutval = (bbox[0].high+bbox[0].low)/2;
407 for (size_t i=1; i<dim_; ++i) {
408 ElementType span = bbox[i].high-bbox[i].low;
409 if (span>max_span) {
410 max_span = span;
411 cutfeat = i;
412 cutval = (bbox[i].high+bbox[i].low)/2;
413 }
414 }
415
416 // compute exact span on the found dimension
417 ElementType min_elem, max_elem;
418 computeMinMax(ind, count, cutfeat, min_elem, max_elem);
419 cutval = (min_elem+max_elem)/2;
420 max_span = max_elem - min_elem;
421
422 // check if a dimension of a largest span exists
423 size_t k = cutfeat;
424 for (size_t i=0; i<dim_; ++i) {
425 if (i==k) continue;
426 ElementType span = bbox[i].high-bbox[i].low;
427 if (span>max_span) {
428 computeMinMax(ind, count, i, min_elem, max_elem);
429 span = max_elem - min_elem;
430 if (span>max_span) {
431 max_span = span;
432 cutfeat = i;
433 cutval = (min_elem+max_elem)/2;
434 }
435 }
436 }
437 int lim1, lim2;
438 planeSplit(ind, count, cutfeat, cutval, lim1, lim2);
439
440 if (lim1>count/2) index = lim1;
441 else if (lim2<count/2) index = lim2;
442 else index = count/2;
443 }
444
445
446 void middleSplit_(int* ind, int count, int& index, int& cutfeat, DistanceType& cutval, const BoundingBox& bbox)
447 {
448 const float EPS=0.00001f;
449 DistanceType max_span = bbox[0].high-bbox[0].low;
450 for (size_t i=1; i<dim_; ++i) {
451 DistanceType span = bbox[i].high-bbox[i].low;
452 if (span>max_span) {
453 max_span = span;
454 }
455 }
456 DistanceType max_spread = -1;
457 cutfeat = 0;
458 for (size_t i=0; i<dim_; ++i) {
459 DistanceType span = bbox[i].high-bbox[i].low;
460 if (span>(DistanceType)((1-EPS)*max_span)) {
461 ElementType min_elem, max_elem;
462 computeMinMax(ind, count, (int)i, min_elem, max_elem);
463 DistanceType spread = (DistanceType)(max_elem-min_elem);
464 if (spread>max_spread) {
465 cutfeat = (int)i;
466 max_spread = spread;
467 }
468 }
469 }
470 // split in the middle
471 DistanceType split_val = (bbox[cutfeat].low+bbox[cutfeat].high)/2;
472 ElementType min_elem, max_elem;
473 computeMinMax(ind, count, cutfeat, min_elem, max_elem);
474
475 if (split_val<min_elem) cutval = (DistanceType)min_elem;
476 else if (split_val>max_elem) cutval = (DistanceType)max_elem;
477 else cutval = split_val;
478
479 int lim1, lim2;
480 planeSplit(ind, count, cutfeat, cutval, lim1, lim2);
481
482 if (lim1>count/2) index = lim1;
483 else if (lim2<count/2) index = lim2;
484 else index = count/2;
485 }
486
487
497 void planeSplit(int* ind, int count, int cutfeat, DistanceType cutval, int& lim1, int& lim2)
498 {
499 /* Move vector indices for left subtree to front of list. */
500 int left = 0;
501 int right = count-1;
502 for (;; ) {
503 while (left<=right && dataset_[ind[left]][cutfeat]<cutval) ++left;
504 while (left<=right && dataset_[ind[right]][cutfeat]>=cutval) --right;
505 if (left>right) break;
506 std::swap(ind[left], ind[right]); ++left; --right;
507 }
508 /* If either list is empty, it means that all remaining features
509 * are identical. Split in the middle to maintain a balanced tree.
510 */
511 lim1 = left;
512 right = count-1;
513 for (;; ) {
514 while (left<=right && dataset_[ind[left]][cutfeat]<=cutval) ++left;
515 while (left<=right && dataset_[ind[right]][cutfeat]>cutval) --right;
516 if (left>right) break;
517 std::swap(ind[left], ind[right]); ++left; --right;
518 }
519 lim2 = left;
520 }
521
522 DistanceType computeInitialDistances(const ElementType* vec, std::vector<DistanceType>& dists)
523 {
524 DistanceType distsq = 0.0;
525
526 for (size_t i = 0; i < dim_; ++i) {
527 if (vec[i] < root_bbox_[i].low) {
528 dists[i] = distance_.accum_dist(vec[i], root_bbox_[i].low, (int)i);
529 distsq += dists[i];
530 }
531 if (vec[i] > root_bbox_[i].high) {
532 dists[i] = distance_.accum_dist(vec[i], root_bbox_[i].high, (int)i);
533 distsq += dists[i];
534 }
535 }
536
537 return distsq;
538 }
539
543 void searchLevel(ResultSet<DistanceType>& result_set, const ElementType* vec, const NodePtr node, DistanceType mindistsq,
544 std::vector<DistanceType>& dists, const float epsError)
545 {
546 /* If this is a leaf node, then do check and return. */
547 if ((node->child1 == NULL)&&(node->child2 == NULL)) {
548 DistanceType worst_dist = result_set.worstDist();
549 if (reorder_) {
550 for (int i=node->left; i<node->right; ++i) {
551 DistanceType dist = distance_(vec, data_[i], dim_, worst_dist);
552 if (dist<worst_dist) {
553 result_set.addPoint(dist,vind_[i]);
554 }
555 }
556 } else {
557 for (int i=node->left; i<node->right; ++i) {
558 DistanceType dist = distance_(vec, data_[vind_[i]], dim_, worst_dist);
559 if (dist<worst_dist) {
560 result_set.addPoint(dist,vind_[i]);
561 }
562 }
563 }
564 return;
565 }
566
567 /* Which child branch should be taken first? */
568 int idx = node->divfeat;
569 ElementType val = vec[idx];
570 DistanceType diff1 = val - node->divlow;
571 DistanceType diff2 = val - node->divhigh;
572
573 NodePtr bestChild;
574 NodePtr otherChild;
575 DistanceType cut_dist;
576 if ((diff1+diff2)<0) {
577 bestChild = node->child1;
578 otherChild = node->child2;
579 cut_dist = distance_.accum_dist(val, node->divhigh, idx);
580 }
581 else {
582 bestChild = node->child2;
583 otherChild = node->child1;
584 cut_dist = distance_.accum_dist( val, node->divlow, idx);
585 }
586
587 /* Call recursively to search next level down. */
588 searchLevel(result_set, vec, bestChild, mindistsq, dists, epsError);
589
590 DistanceType dst = dists[idx];
591 mindistsq = mindistsq + cut_dist - dst;
592 dists[idx] = cut_dist;
593 if (mindistsq*epsError<=result_set.worstDist()) {
594 searchLevel(result_set, vec, otherChild, mindistsq, dists, epsError);
595 }
596 dists[idx] = dst;
597 }
598
599private:
600
604 const Matrix<ElementType> dataset_;
605
606 IndexParams index_params_;
607
608 int leaf_max_size_;
609 bool reorder_;
610
611
615 std::vector<int> vind_;
616
617 Matrix<ElementType> data_;
618
619 size_t size_;
620 size_t dim_;
621
625 NodePtr root_node_;
626
627 BoundingBox root_bbox_;
628
636 PooledAllocator pool_;
637
638 Distance distance_;
639}; // class KDTree
640
641}
642
644
645#endif //OPENCV_FLANN_KDTREE_SINGLE_INDEX_H_
int rows(int i=-1) const
CvArr * dst
Definition core_c.h:875
const int * idx
Definition core_c.h:668
int index
Definition core_c.h:634
CvSize size
Definition core_c.h:112
int count
Definition core_c.h:1413
const CvArr const CvArr CvArr * result
Definition core_c.h:1423
#define CV_OVERRIDE
Definition cvdef.h:792
#define CV_Assert(expr)
Checks a condition at runtime and throws exception if it fails.
Definition base.hpp:342
CV_EXPORTS OutputArray int double double InputArray OutputArray int int bool double k
Definition imgproc.hpp:2133
T max(T... args)
T min(T... args)
Definition flann.hpp:60
QTextStream & left(QTextStream &stream)
QTextStream & right(QTextStream &stream)
T swap(T... args)