• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*M///////////////////////////////////////////////////////////////////////////////////////
2  //
3  //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
4  //
5  //  By downloading, copying, installing or using the software you agree to this license.
6  //  If you do not agree to this license, do not download, install,
7  //  copy or use the software.
8  //
9  //
10  //                        Intel License Agreement
11  //                For Open Source Computer Vision Library
12  //
13  // Copyright (C) 2008, Xavier Delacour, all rights reserved.
14  // Third party copyrights are property of their respective owners.
15  //
16  // Redistribution and use in source and binary forms, with or without modification,
17  // are permitted provided that the following conditions are met:
18  //
19  //   * Redistribution's of source code must retain the above copyright notice,
20  //     this list of conditions and the following disclaimer.
21  //
22  //   * Redistribution's in binary form must reproduce the above copyright notice,
23  //     this list of conditions and the following disclaimer in the documentation
24  //     and/or other materials provided with the distribution.
25  //
26  //   * The name of Intel Corporation may not be used to endorse or promote products
27  //     derived from this software without specific prior written permission.
28  //
29  // This software is provided by the copyright holders and contributors "as is" and
30  // any express or implied warranties, including, but not limited to, the implied
31  // warranties of merchantability and fitness for a particular purpose are disclaimed.
32  // In no event shall the Intel Corporation or contributors be liable for any direct,
33  // indirect, incidental, special, exemplary, or consequential damages
34  // (including, but not limited to, procurement of substitute goods or services;
35  // loss of use, data, or profits; or business interruption) however caused
36  // and on any theory of liability, whether in contract, strict liability,
37  // or tort (including negligence or otherwise) arising in any way out of
38  // the use of this software, even if advised of the possibility of such damage.
39  //
40  //M*/
41  
42  // 2008-05-13, Xavier Delacour <xavier.delacour@gmail.com>
43  
44  #ifndef __cv_kdtree_h__
45  #define __cv_kdtree_h__
46  
47  #include "_cv.h"
48  
49  #include <vector>
50  #include <algorithm>
51  #include <limits>
52  #include <iostream>
53  #include "assert.h"
54  #include "math.h"
55  
56  // J.S. Beis and D.G. Lowe. Shape indexing using approximate nearest-neighbor search in highdimensional spaces. In Proc. IEEE Conf. Comp. Vision Patt. Recog., pages 1000--1006, 1997. http://citeseer.ist.psu.edu/beis97shape.html
57  #undef __deref
58  #undef __valuetype
59  
60  template < class __valuetype, class __deref >
61  class CvKDTree {
62  public:
63    typedef __deref deref_type;
64    typedef typename __deref::scalar_type scalar_type;
65    typedef typename __deref::accum_type accum_type;
66  
67  private:
68    struct node {
69      int dim;			// split dimension; >=0 for nodes, -1 for leaves
70      __valuetype value;		// if leaf, value of leaf
71      int left, right;		// node indices of left and right branches
72      scalar_type boundary;	// left if deref(value,dim)<=boundary, otherwise right
73    };
74    typedef std::vector < node > node_array;
75  
76    __deref deref;		// requires operator() (__valuetype lhs,int dim)
77  
78    node_array nodes;		// node storage
79    int point_dim;		// dimension of points (the k in kd-tree)
80    int root_node;		// index of root node, -1 if empty tree
81  
82    // for given set of point indices, compute dimension of highest variance
83    template < class __instype, class __valuector >
dimension_of_highest_variance(__instype * first,__instype * last,__valuector ctor)84    int dimension_of_highest_variance(__instype * first, __instype * last,
85  				    __valuector ctor) {
86      assert(last - first > 0);
87  
88      accum_type maxvar = -std::numeric_limits < accum_type >::max();
89      int maxj = -1;
90      for (int j = 0; j < point_dim; ++j) {
91        accum_type mean = 0;
92        for (__instype * k = first; k < last; ++k)
93  	mean += deref(ctor(*k), j);
94        mean /= last - first;
95        accum_type var = 0;
96        for (__instype * k = first; k < last; ++k) {
97  	accum_type diff = accum_type(deref(ctor(*k), j)) - mean;
98  	var += diff * diff;
99        }
100        var /= last - first;
101  
102        assert(maxj != -1 || var >= maxvar);
103  
104        if (var >= maxvar) {
105  	maxvar = var;
106  	maxj = j;
107        }
108      }
109  
110      return maxj;
111    }
112  
113    // given point indices and dimension, find index of median; (almost) modifies [first,last)
114    // such that points_in[first,median]<=point[median], points_in(median,last)>point[median].
115    // implemented as partial quicksort; expected linear perf.
116    template < class __instype, class __valuector >
median_partition(__instype * first,__instype * last,int dim,__valuector ctor)117    __instype * median_partition(__instype * first, __instype * last,
118  			       int dim, __valuector ctor) {
119      assert(last - first > 0);
120      __instype *k = first + (last - first) / 2;
121      median_partition(first, last, k, dim, ctor);
122      return k;
123    }
124  
125    template < class __instype, class __valuector >
126    struct median_pr {
127      const __instype & pivot;
128      int dim;
129      __deref deref;
130      __valuector ctor;
median_prCvKDTree::median_pr131      median_pr(const __instype & _pivot, int _dim, __deref _deref, __valuector _ctor)
132        : pivot(_pivot), dim(_dim), deref(_deref), ctor(_ctor) {
133      }
operator ()CvKDTree::median_pr134      bool operator() (const __instype & lhs) const {
135        return deref(ctor(lhs), dim) <= deref(ctor(pivot), dim);
136      }
137    };
138  
139    template < class __instype, class __valuector >
median_partition(__instype * first,__instype * last,__instype * k,int dim,__valuector ctor)140    void median_partition(__instype * first, __instype * last,
141  			__instype * k, int dim, __valuector ctor) {
142      int pivot = (last - first) / 2;
143  
144      std::swap(first[pivot], last[-1]);
145      __instype *middle = std::partition(first, last - 1,
146  				       median_pr < __instype, __valuector >
147  				       (last[-1], dim, deref, ctor));
148      std::swap(*middle, last[-1]);
149  
150      if (middle < k)
151        median_partition(middle + 1, last, k, dim, ctor);
152      else if (middle > k)
153        median_partition(first, middle, k, dim, ctor);
154    }
155  
156    // insert given points into the tree; return created node
157    template < class __instype, class __valuector >
insert(__instype * first,__instype * last,__valuector ctor)158    int insert(__instype * first, __instype * last, __valuector ctor) {
159      if (first == last)
160        return -1;
161      else {
162  
163        int dim = dimension_of_highest_variance(first, last, ctor);
164        __instype *median = median_partition(first, last, dim, ctor);
165  
166        __instype *split = median;
167        for (; split != last && deref(ctor(*split), dim) ==
168  	     deref(ctor(*median), dim); ++split);
169  
170        if (split == last) { // leaf
171  	int nexti = -1;
172  	for (--split; split >= first; --split) {
173  	  int i = nodes.size();
174  	  node & n = *nodes.insert(nodes.end(), node());
175  	  n.dim = -1;
176  	  n.value = ctor(*split);
177  	  n.left = -1;
178  	  n.right = nexti;
179  	  nexti = i;
180  	}
181  
182  	return nexti;
183        } else { // node
184  	int i = nodes.size();
185  	// note that recursive insert may invalidate this ref
186  	node & n = *nodes.insert(nodes.end(), node());
187  
188  	n.dim = dim;
189  	n.boundary = deref(ctor(*median), dim);
190  
191  	int left = insert(first, split, ctor);
192  	nodes[i].left = left;
193  	int right = insert(split, last, ctor);
194  	nodes[i].right = right;
195  
196  	return i;
197        }
198      }
199    }
200  
201    // run to leaf; linear search for p;
202    // if found, remove paths to empty leaves on unwind
remove(int * i,const __valuetype & p)203    bool remove(int *i, const __valuetype & p) {
204      if (*i == -1)
205        return false;
206      node & n = nodes[*i];
207      bool r;
208  
209      if (n.dim >= 0) { // node
210        if (deref(p, n.dim) <= n.boundary) // left
211  	r = remove(&n.left, p);
212        else // right
213  	r = remove(&n.right, p);
214  
215        // if terminal, remove this node
216        if (n.left == -1 && n.right == -1)
217  	*i = -1;
218  
219        return r;
220      } else { // leaf
221        if (n.value == p) {
222  	*i = n.right;
223  	return true;
224        } else
225  	return remove(&n.right, p);
226      }
227    }
228  
229  public:
230    struct identity_ctor {
operator ()CvKDTree::identity_ctor231      const __valuetype & operator() (const __valuetype & rhs) const {
232        return rhs;
233      }
234    };
235  
236    // initialize an empty tree
CvKDTree(__deref _deref=__deref ())237    CvKDTree(__deref _deref = __deref())
238      : deref(_deref), root_node(-1) {
239    }
240    // given points, initialize a balanced tree
CvKDTree(__valuetype * first,__valuetype * last,int _point_dim,__deref _deref=__deref ())241    CvKDTree(__valuetype * first, __valuetype * last, int _point_dim,
242  	   __deref _deref = __deref())
243      : deref(_deref) {
244      set_data(first, last, _point_dim, identity_ctor());
245    }
246    // given points, initialize a balanced tree
247    template < class __instype, class __valuector >
CvKDTree(__instype * first,__instype * last,int _point_dim,__valuector ctor,__deref _deref=__deref ())248    CvKDTree(__instype * first, __instype * last, int _point_dim,
249  	   __valuector ctor, __deref _deref = __deref())
250      : deref(_deref) {
251      set_data(first, last, _point_dim, ctor);
252    }
253  
set_deref(__deref _deref)254    void set_deref(__deref _deref) {
255      deref = _deref;
256    }
257  
set_data(__valuetype * first,__valuetype * last,int _point_dim)258    void set_data(__valuetype * first, __valuetype * last, int _point_dim) {
259      set_data(first, last, _point_dim, identity_ctor());
260    }
261    template < class __instype, class __valuector >
set_data(__instype * first,__instype * last,int _point_dim,__valuector ctor)262    void set_data(__instype * first, __instype * last, int _point_dim,
263  		__valuector ctor) {
264      point_dim = _point_dim;
265      nodes.clear();
266      nodes.reserve(last - first);
267      root_node = insert(first, last, ctor);
268    }
269  
dims() const270    int dims() const {
271      return point_dim;
272    }
273  
274    // remove the given point
remove(const __valuetype & p)275    bool remove(const __valuetype & p) {
276      return remove(&root_node, p);
277    }
278  
print() const279    void print() const {
280      print(root_node);
281    }
print(int i,int indent=0) const282    void print(int i, int indent = 0) const {
283      if (i == -1)
284        return;
285      for (int j = 0; j < indent; ++j)
286        std::cout << " ";
287      const node & n = nodes[i];
288      if (n.dim >= 0) {
289        std::cout << "node " << i << ", left " << nodes[i].left << ", right " <<
290  	nodes[i].right << ", dim " << nodes[i].dim << ", boundary " <<
291  	nodes[i].boundary << std::endl;
292        print(n.left, indent + 3);
293        print(n.right, indent + 3);
294      } else
295        std::cout << "leaf " << i << ", value = " << nodes[i].value << std::endl;
296    }
297  
298    ////////////////////////////////////////////////////////////////////////////////////////
299    // bbf search
300  public:
301    struct bbf_nn {		// info on found neighbors (approx k nearest)
302      const __valuetype *p;	// nearest neighbor
303      accum_type dist;		// distance from d to query point
bbf_nnCvKDTree::bbf_nn304      bbf_nn(const __valuetype & _p, accum_type _dist)
305        : p(&_p), dist(_dist) {
306      }
operator <CvKDTree::bbf_nn307      bool operator<(const bbf_nn & rhs) const {
308        return dist < rhs.dist;
309      }
310    };
311    typedef std::vector < bbf_nn > bbf_nn_pqueue;
312  private:
313    struct bbf_node {		// info on branches not taken
314      int node;			// corresponding node
315      accum_type dist;		// minimum distance from bounds to query point
bbf_nodeCvKDTree::bbf_node316      bbf_node(int _node, accum_type _dist)
317        : node(_node), dist(_dist) {
318      }
operator <CvKDTree::bbf_node319      bool operator<(const bbf_node & rhs) const {
320        return dist > rhs.dist;
321      }
322    };
323    typedef std::vector < bbf_node > bbf_pqueue;
324    mutable bbf_pqueue tmp_pq;
325  
326    // called for branches not taken, as bbf walks to leaf;
327    // construct bbf_node given minimum distance to bounds of alternate branch
pq_alternate(int alt_n,bbf_pqueue & pq,scalar_type dist) const328    void pq_alternate(int alt_n, bbf_pqueue & pq, scalar_type dist) const {
329      if (alt_n == -1)
330        return;
331  
332      // add bbf_node for alternate branch in priority queue
333      pq.push_back(bbf_node(alt_n, dist));
334      push_heap(pq.begin(), pq.end());
335    }
336  
337    // called by bbf to walk to leaf;
338    // takes one step down the tree towards query point d
339    template < class __desctype >
bbf_branch(int i,const __desctype * d,bbf_pqueue & pq) const340    int bbf_branch(int i, const __desctype * d, bbf_pqueue & pq) const {
341      const node & n = nodes[i];
342      // push bbf_node with bounds of alternate branch, then branch
343      if (d[n.dim] <= n.boundary) {	// left
344        pq_alternate(n.right, pq, n.boundary - d[n.dim]);
345        return n.left;
346      } else {			// right
347        pq_alternate(n.left, pq, d[n.dim] - n.boundary);
348        return n.right;
349      }
350    }
351  
352    // compute euclidean distance between two points
353    template < class __desctype >
distance(const __desctype * d,const __valuetype & p) const354    accum_type distance(const __desctype * d, const __valuetype & p) const {
355      accum_type dist = 0;
356      for (int j = 0; j < point_dim; ++j) {
357        accum_type diff = accum_type(d[j]) - accum_type(deref(p, j));
358        dist += diff * diff;
359      } return (accum_type) sqrt(dist);
360    }
361  
362    // called per candidate nearest neighbor; constructs new bbf_nn for
363    // candidate and adds it to priority queue of all candidates; if
364    // queue len exceeds k, drops the point furthest from query point d.
365    template < class __desctype >
bbf_new_nn(bbf_nn_pqueue & nn_pq,int k,const __desctype * d,const __valuetype & p) const366    void bbf_new_nn(bbf_nn_pqueue & nn_pq, int k,
367  		  const __desctype * d, const __valuetype & p) const {
368      bbf_nn nn(p, distance(d, p));
369      if ((int) nn_pq.size() < k) {
370        nn_pq.push_back(nn);
371        push_heap(nn_pq.begin(), nn_pq.end());
372      } else if (nn_pq[0].dist > nn.dist) {
373        pop_heap(nn_pq.begin(), nn_pq.end());
374        nn_pq.end()[-1] = nn;
375        push_heap(nn_pq.begin(), nn_pq.end());
376      }
377      assert(nn_pq.size() < 2 || nn_pq[0].dist >= nn_pq[1].dist);
378    }
379  
380  public:
381    // finds (with high probability) the k nearest neighbors of d,
382    // searching at most emax leaves/bins.
383    // ret_nn_pq is an array containing the (at most) k nearest neighbors
384    // (see bbf_nn structure def above).
385    template < class __desctype >
find_nn_bbf(const __desctype * d,int k,int emax,bbf_nn_pqueue & ret_nn_pq) const386    int find_nn_bbf(const __desctype * d,
387  		  int k, int emax,
388  		  bbf_nn_pqueue & ret_nn_pq) const {
389      assert(k > 0);
390      ret_nn_pq.clear();
391  
392      if (root_node == -1)
393        return 0;
394  
395      // add root_node to bbf_node priority queue;
396      // iterate while queue non-empty and emax>0
397      tmp_pq.clear();
398      tmp_pq.push_back(bbf_node(root_node, 0));
399      while (tmp_pq.size() && emax > 0) {
400  
401        // from node nearest query point d, run to leaf
402        pop_heap(tmp_pq.begin(), tmp_pq.end());
403        bbf_node bbf(tmp_pq.end()[-1]);
404        tmp_pq.erase(tmp_pq.end() - 1);
405  
406        int i;
407        for (i = bbf.node;
408  	   i != -1 && nodes[i].dim >= 0;
409  	   i = bbf_branch(i, d, tmp_pq));
410  
411        if (i != -1) {
412  
413  	// add points in leaf/bin to ret_nn_pq
414  	do {
415  	  bbf_new_nn(ret_nn_pq, k, d, nodes[i].value);
416  	} while (-1 != (i = nodes[i].right));
417  
418  	--emax;
419        }
420      }
421  
422      tmp_pq.clear();
423      return ret_nn_pq.size();
424    }
425  
426    ////////////////////////////////////////////////////////////////////////////////////////
427    // orthogonal range search
428  private:
find_ortho_range(int i,scalar_type * bounds_min,scalar_type * bounds_max,std::vector<__valuetype> & inbounds) const429    void find_ortho_range(int i, scalar_type * bounds_min,
430  			scalar_type * bounds_max,
431  			std::vector < __valuetype > &inbounds) const {
432      if (i == -1)
433        return;
434      const node & n = nodes[i];
435      if (n.dim >= 0) { // node
436        if (bounds_min[n.dim] <= n.boundary)
437  	find_ortho_range(n.left, bounds_min, bounds_max, inbounds);
438        if (bounds_max[n.dim] > n.boundary)
439  	find_ortho_range(n.right, bounds_min, bounds_max, inbounds);
440      } else { // leaf
441        do {
442  	inbounds.push_back(nodes[i].value);
443        } while (-1 != (i = nodes[i].right));
444      }
445    }
446  public:
447    // return all points that lie within the given bounds; inbounds is cleared
find_ortho_range(scalar_type * bounds_min,scalar_type * bounds_max,std::vector<__valuetype> & inbounds) const448    int find_ortho_range(scalar_type * bounds_min,
449  		       scalar_type * bounds_max,
450  		       std::vector < __valuetype > &inbounds) const {
451      inbounds.clear();
452      find_ortho_range(root_node, bounds_min, bounds_max, inbounds);
453      return inbounds.size();
454    }
455  };
456  
457  #endif // __cv_kdtree_h__
458  
459  // Local Variables:
460  // mode:C++
461  // End:
462