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 //                          License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
16 // Copyright (C) 2014, Itseez Inc, all rights reserved.
17 // Third party copyrights are property of their respective owners.
18 //
19 // Redistribution and use in source and binary forms, with or without modification,
20 // are permitted provided that the following conditions are met:
21 //
22 //   * Redistribution's of source code must retain the above copyright notice,
23 //     this list of conditions and the following disclaimer.
24 //
25 //   * Redistribution's in binary form must reproduce the above copyright notice,
26 //     this list of conditions and the following disclaimer in the documentation
27 //     and/or other materials provided with the distribution.
28 //
29 //   * The name of the copyright holders may not be used to endorse or promote products
30 //     derived from this software without specific prior written permission.
31 //
32 // This software is provided by the copyright holders and contributors "as is" and
33 // any express or implied warranties, including, but not limited to, the implied
34 // warranties of merchantability and fitness for a particular purpose are disclaimed.
35 // In no event shall the Intel Corporation or contributors be liable for any direct,
36 // indirect, incidental, special, exemplary, or consequential damages
37 // (including, but not limited to, procurement of substitute goods or services;
38 // loss of use, data, or profits; or business interruption) however caused
39 // and on any theory of liability, whether in contract, strict liability,
40 // or tort (including negligence or otherwise) arising in any way out of
41 // the use of this software, even if advised of the possibility of such damage.
42 //
43 //M*/
44 
45 #include "precomp.hpp"
46 #include "kdtree.hpp"
47 
48 namespace cv
49 {
50 namespace ml
51 {
52 // This is reimplementation of kd-trees from cvkdtree*.* by Xavier Delacour, cleaned-up and
53 // adopted to work with the new OpenCV data structures.
54 
55 // The algorithm is taken from:
56 // J.S. Beis and D.G. Lowe. Shape indexing using approximate nearest-neighbor search
57 // in highdimensional spaces. In Proc. IEEE Conf. Comp. Vision Patt. Recog.,
58 // pages 1000--1006, 1997. http://citeseer.ist.psu.edu/beis97shape.html
59 
60 const int MAX_TREE_DEPTH = 32;
61 
KDTree()62 KDTree::KDTree()
63 {
64     maxDepth = -1;
65     normType = NORM_L2;
66 }
67 
KDTree(InputArray _points,bool _copyData)68 KDTree::KDTree(InputArray _points, bool _copyData)
69 {
70     maxDepth = -1;
71     normType = NORM_L2;
72     build(_points, _copyData);
73 }
74 
KDTree(InputArray _points,InputArray _labels,bool _copyData)75 KDTree::KDTree(InputArray _points, InputArray _labels, bool _copyData)
76 {
77     maxDepth = -1;
78     normType = NORM_L2;
79     build(_points, _labels, _copyData);
80 }
81 
82 struct SubTree
83 {
SubTreecv::ml::SubTree84     SubTree() : first(0), last(0), nodeIdx(0), depth(0) {}
SubTreecv::ml::SubTree85     SubTree(int _first, int _last, int _nodeIdx, int _depth)
86         : first(_first), last(_last), nodeIdx(_nodeIdx), depth(_depth) {}
87     int first;
88     int last;
89     int nodeIdx;
90     int depth;
91 };
92 
93 
94 static float
medianPartition(size_t * ofs,int a,int b,const float * vals)95 medianPartition( size_t* ofs, int a, int b, const float* vals )
96 {
97     int k, a0 = a, b0 = b;
98     int middle = (a + b)/2;
99     while( b > a )
100     {
101         int i0 = a, i1 = (a+b)/2, i2 = b;
102         float v0 = vals[ofs[i0]], v1 = vals[ofs[i1]], v2 = vals[ofs[i2]];
103         int ip = v0 < v1 ? (v1 < v2 ? i1 : v0 < v2 ? i2 : i0) :
104             v0 < v2 ? i0 : (v1 < v2 ? i2 : i1);
105         float pivot = vals[ofs[ip]];
106         std::swap(ofs[ip], ofs[i2]);
107 
108         for( i1 = i0, i0--; i1 <= i2; i1++ )
109             if( vals[ofs[i1]] <= pivot )
110             {
111                 i0++;
112                 std::swap(ofs[i0], ofs[i1]);
113             }
114         if( i0 == middle )
115             break;
116         if( i0 > middle )
117             b = i0 - (b == i0);
118         else
119             a = i0;
120     }
121 
122     float pivot = vals[ofs[middle]];
123     int less = 0, more = 0;
124     for( k = a0; k < middle; k++ )
125     {
126         CV_Assert(vals[ofs[k]] <= pivot);
127         less += vals[ofs[k]] < pivot;
128     }
129     for( k = b0; k > middle; k-- )
130     {
131         CV_Assert(vals[ofs[k]] >= pivot);
132         more += vals[ofs[k]] > pivot;
133     }
134     CV_Assert(std::abs(more - less) <= 1);
135 
136     return vals[ofs[middle]];
137 }
138 
139 static void
computeSums(const Mat & points,const size_t * ofs,int a,int b,double * sums)140 computeSums( const Mat& points, const size_t* ofs, int a, int b, double* sums )
141 {
142     int i, j, dims = points.cols;
143     const float* data = points.ptr<float>(0);
144     for( j = 0; j < dims; j++ )
145         sums[j*2] = sums[j*2+1] = 0;
146     for( i = a; i <= b; i++ )
147     {
148         const float* row = data + ofs[i];
149         for( j = 0; j < dims; j++ )
150         {
151             double t = row[j], s = sums[j*2] + t, s2 = sums[j*2+1] + t*t;
152             sums[j*2] = s; sums[j*2+1] = s2;
153         }
154     }
155 }
156 
157 
build(InputArray _points,bool _copyData)158 void KDTree::build(InputArray _points, bool _copyData)
159 {
160     build(_points, noArray(), _copyData);
161 }
162 
163 
build(InputArray __points,InputArray __labels,bool _copyData)164 void KDTree::build(InputArray __points, InputArray __labels, bool _copyData)
165 {
166     Mat _points = __points.getMat(), _labels = __labels.getMat();
167     CV_Assert(_points.type() == CV_32F && !_points.empty());
168     std::vector<KDTree::Node>().swap(nodes);
169 
170     if( !_copyData )
171         points = _points;
172     else
173     {
174         points.release();
175         points.create(_points.size(), _points.type());
176     }
177 
178     int i, j, n = _points.rows, ptdims = _points.cols, top = 0;
179     const float* data = _points.ptr<float>(0);
180     float* dstdata = points.ptr<float>(0);
181     size_t step = _points.step1();
182     size_t dstep = points.step1();
183     int ptpos = 0;
184     labels.resize(n);
185     const int* _labels_data = 0;
186 
187     if( !_labels.empty() )
188     {
189         int nlabels = _labels.checkVector(1, CV_32S, true);
190         CV_Assert(nlabels == n);
191         _labels_data = _labels.ptr<int>();
192     }
193 
194     Mat sumstack(MAX_TREE_DEPTH*2, ptdims*2, CV_64F);
195     SubTree stack[MAX_TREE_DEPTH*2];
196 
197     std::vector<size_t> _ptofs(n);
198     size_t* ptofs = &_ptofs[0];
199 
200     for( i = 0; i < n; i++ )
201         ptofs[i] = i*step;
202 
203     nodes.push_back(Node());
204     computeSums(points, ptofs, 0, n-1, sumstack.ptr<double>(top));
205     stack[top++] = SubTree(0, n-1, 0, 0);
206     int _maxDepth = 0;
207 
208     while( --top >= 0 )
209     {
210         int first = stack[top].first, last = stack[top].last;
211         int depth = stack[top].depth, nidx = stack[top].nodeIdx;
212         int count = last - first + 1, dim = -1;
213         const double* sums = sumstack.ptr<double>(top);
214         double invCount = 1./count, maxVar = -1.;
215 
216         if( count == 1 )
217         {
218             int idx0 = (int)(ptofs[first]/step);
219             int idx = _copyData ? ptpos++ : idx0;
220             nodes[nidx].idx = ~idx;
221             if( _copyData )
222             {
223                 const float* src = data + ptofs[first];
224                 float* dst = dstdata + idx*dstep;
225                 for( j = 0; j < ptdims; j++ )
226                     dst[j] = src[j];
227             }
228             labels[idx] = _labels_data ? _labels_data[idx0] : idx0;
229             _maxDepth = std::max(_maxDepth, depth);
230             continue;
231         }
232 
233         // find the dimensionality with the biggest variance
234         for( j = 0; j < ptdims; j++ )
235         {
236             double m = sums[j*2]*invCount;
237             double varj = sums[j*2+1]*invCount - m*m;
238             if( maxVar < varj )
239             {
240                 maxVar = varj;
241                 dim = j;
242             }
243         }
244 
245         int left = (int)nodes.size(), right = left + 1;
246         nodes.push_back(Node());
247         nodes.push_back(Node());
248         nodes[nidx].idx = dim;
249         nodes[nidx].left = left;
250         nodes[nidx].right = right;
251         nodes[nidx].boundary = medianPartition(ptofs, first, last, data + dim);
252 
253         int middle = (first + last)/2;
254         double *lsums = (double*)sums, *rsums = lsums + ptdims*2;
255         computeSums(points, ptofs, middle+1, last, rsums);
256         for( j = 0; j < ptdims*2; j++ )
257             lsums[j] = sums[j] - rsums[j];
258         stack[top++] = SubTree(first, middle, left, depth+1);
259         stack[top++] = SubTree(middle+1, last, right, depth+1);
260     }
261     maxDepth = _maxDepth;
262 }
263 
264 
265 struct PQueueElem
266 {
PQueueElemcv::ml::PQueueElem267     PQueueElem() : dist(0), idx(0) {}
PQueueElemcv::ml::PQueueElem268     PQueueElem(float _dist, int _idx) : dist(_dist), idx(_idx) {}
269     float dist;
270     int idx;
271 };
272 
273 
findNearest(InputArray _vec,int K,int emax,OutputArray _neighborsIdx,OutputArray _neighbors,OutputArray _dist,OutputArray _labels) const274 int KDTree::findNearest(InputArray _vec, int K, int emax,
275                         OutputArray _neighborsIdx, OutputArray _neighbors,
276                         OutputArray _dist, OutputArray _labels) const
277 
278 {
279     Mat vecmat = _vec.getMat();
280     CV_Assert( vecmat.isContinuous() && vecmat.type() == CV_32F && vecmat.total() == (size_t)points.cols );
281     const float* vec = vecmat.ptr<float>();
282     K = std::min(K, points.rows);
283     int ptdims = points.cols;
284 
285     CV_Assert(K > 0 && (normType == NORM_L2 || normType == NORM_L1));
286 
287     AutoBuffer<uchar> _buf((K+1)*(sizeof(float) + sizeof(int)));
288     int* idx = (int*)(uchar*)_buf;
289     float* dist = (float*)(idx + K + 1);
290     int i, j, ncount = 0, e = 0;
291 
292     int qsize = 0, maxqsize = 1 << 10;
293     AutoBuffer<uchar> _pqueue(maxqsize*sizeof(PQueueElem));
294     PQueueElem* pqueue = (PQueueElem*)(uchar*)_pqueue;
295     emax = std::max(emax, 1);
296 
297     for( e = 0; e < emax; )
298     {
299         float d, alt_d = 0.f;
300         int nidx;
301 
302         if( e == 0 )
303             nidx = 0;
304         else
305         {
306             // take the next node from the priority queue
307             if( qsize == 0 )
308                 break;
309             nidx = pqueue[0].idx;
310             alt_d = pqueue[0].dist;
311             if( --qsize > 0 )
312             {
313                 std::swap(pqueue[0], pqueue[qsize]);
314                 d = pqueue[0].dist;
315                 for( i = 0;;)
316                 {
317                     int left = i*2 + 1, right = i*2 + 2;
318                     if( left >= qsize )
319                         break;
320                     if( right < qsize && pqueue[right].dist < pqueue[left].dist )
321                         left = right;
322                     if( pqueue[left].dist >= d )
323                         break;
324                     std::swap(pqueue[i], pqueue[left]);
325                     i = left;
326                 }
327             }
328 
329             if( ncount == K && alt_d > dist[ncount-1] )
330                 continue;
331         }
332 
333         for(;;)
334         {
335             if( nidx < 0 )
336                 break;
337             const Node& n = nodes[nidx];
338 
339             if( n.idx < 0 )
340             {
341                 i = ~n.idx;
342                 const float* row = points.ptr<float>(i);
343                 if( normType == NORM_L2 )
344                     for( j = 0, d = 0.f; j < ptdims; j++ )
345                     {
346                         float t = vec[j] - row[j];
347                         d += t*t;
348                     }
349                 else
350                     for( j = 0, d = 0.f; j < ptdims; j++ )
351                         d += std::abs(vec[j] - row[j]);
352 
353                 dist[ncount] = d;
354                 idx[ncount] = i;
355                 for( i = ncount-1; i >= 0; i-- )
356                 {
357                     if( dist[i] <= d )
358                         break;
359                     std::swap(dist[i], dist[i+1]);
360                     std::swap(idx[i], idx[i+1]);
361                 }
362                 ncount += ncount < K;
363                 e++;
364                 break;
365             }
366 
367             int alt;
368             if( vec[n.idx] <= n.boundary )
369             {
370                 nidx = n.left;
371                 alt = n.right;
372             }
373             else
374             {
375                 nidx = n.right;
376                 alt = n.left;
377             }
378 
379             d = vec[n.idx] - n.boundary;
380             if( normType == NORM_L2 )
381                 d = d*d + alt_d;
382             else
383                 d = std::abs(d) + alt_d;
384             // subtree prunning
385             if( ncount == K && d > dist[ncount-1] )
386                 continue;
387             // add alternative subtree to the priority queue
388             pqueue[qsize] = PQueueElem(d, alt);
389             for( i = qsize; i > 0; )
390             {
391                 int parent = (i-1)/2;
392                 if( parent < 0 || pqueue[parent].dist <= d )
393                     break;
394                 std::swap(pqueue[i], pqueue[parent]);
395                 i = parent;
396             }
397             qsize += qsize+1 < maxqsize;
398         }
399     }
400 
401     K = std::min(K, ncount);
402     if( _neighborsIdx.needed() )
403     {
404         _neighborsIdx.create(K, 1, CV_32S, -1, true);
405         Mat nidx = _neighborsIdx.getMat();
406         Mat(nidx.size(), CV_32S, &idx[0]).copyTo(nidx);
407     }
408     if( _dist.needed() )
409         sqrt(Mat(K, 1, CV_32F, dist), _dist);
410 
411     if( _neighbors.needed() || _labels.needed() )
412         getPoints(Mat(K, 1, CV_32S, idx), _neighbors, _labels);
413     return K;
414 }
415 
416 
findOrthoRange(InputArray _lowerBound,InputArray _upperBound,OutputArray _neighborsIdx,OutputArray _neighbors,OutputArray _labels) const417 void KDTree::findOrthoRange(InputArray _lowerBound,
418                             InputArray _upperBound,
419                             OutputArray _neighborsIdx,
420                             OutputArray _neighbors,
421                             OutputArray _labels ) const
422 {
423     int ptdims = points.cols;
424     Mat lowerBound = _lowerBound.getMat(), upperBound = _upperBound.getMat();
425     CV_Assert( lowerBound.size == upperBound.size &&
426                lowerBound.isContinuous() &&
427                upperBound.isContinuous() &&
428                lowerBound.type() == upperBound.type() &&
429                lowerBound.type() == CV_32F &&
430                lowerBound.total() == (size_t)ptdims );
431     const float* L = lowerBound.ptr<float>();
432     const float* R = upperBound.ptr<float>();
433 
434     std::vector<int> idx;
435     AutoBuffer<int> _stack(MAX_TREE_DEPTH*2 + 1);
436     int* stack = _stack;
437     int top = 0;
438 
439     stack[top++] = 0;
440 
441     while( --top >= 0 )
442     {
443         int nidx = stack[top];
444         if( nidx < 0 )
445             break;
446         const Node& n = nodes[nidx];
447         if( n.idx < 0 )
448         {
449             int j, i = ~n.idx;
450             const float* row = points.ptr<float>(i);
451             for( j = 0; j < ptdims; j++ )
452                 if( row[j] < L[j] || row[j] >= R[j] )
453                     break;
454             if( j == ptdims )
455                 idx.push_back(i);
456             continue;
457         }
458         if( L[n.idx] <= n.boundary )
459             stack[top++] = n.left;
460         if( R[n.idx] > n.boundary )
461             stack[top++] = n.right;
462     }
463 
464     if( _neighborsIdx.needed() )
465     {
466         _neighborsIdx.create((int)idx.size(), 1, CV_32S, -1, true);
467         Mat nidx = _neighborsIdx.getMat();
468         Mat(nidx.size(), CV_32S, &idx[0]).copyTo(nidx);
469     }
470     getPoints( idx, _neighbors, _labels );
471 }
472 
473 
getPoints(InputArray _idx,OutputArray _pts,OutputArray _labels) const474 void KDTree::getPoints(InputArray _idx, OutputArray _pts, OutputArray _labels) const
475 {
476     Mat idxmat = _idx.getMat(), pts, labelsmat;
477     CV_Assert( idxmat.isContinuous() && idxmat.type() == CV_32S &&
478                (idxmat.cols == 1 || idxmat.rows == 1) );
479     const int* idx = idxmat.ptr<int>();
480     int* dstlabels = 0;
481 
482     int ptdims = points.cols;
483     int i, nidx = (int)idxmat.total();
484     if( nidx == 0 )
485     {
486         _pts.release();
487         _labels.release();
488         return;
489     }
490 
491     if( _pts.needed() )
492     {
493         _pts.create( nidx, ptdims, points.type());
494         pts = _pts.getMat();
495     }
496 
497     if(_labels.needed())
498     {
499         _labels.create(nidx, 1, CV_32S, -1, true);
500         labelsmat = _labels.getMat();
501         CV_Assert( labelsmat.isContinuous() );
502         dstlabels = labelsmat.ptr<int>();
503     }
504     const int* srclabels = !labels.empty() ? &labels[0] : 0;
505 
506     for( i = 0; i < nidx; i++ )
507     {
508         int k = idx[i];
509         CV_Assert( (unsigned)k < (unsigned)points.rows );
510         const float* src = points.ptr<float>(k);
511         if( !pts.empty() )
512             std::copy(src, src + ptdims, pts.ptr<float>(i));
513         if( dstlabels )
514             dstlabels[i] = srclabels ? srclabels[k] : k;
515     }
516 }
517 
518 
getPoint(int ptidx,int * label) const519 const float* KDTree::getPoint(int ptidx, int* label) const
520 {
521     CV_Assert( (unsigned)ptidx < (unsigned)points.rows);
522     if(label)
523         *label = labels[ptidx];
524     return points.ptr<float>(ptidx);
525 }
526 
527 
dims() const528 int KDTree::dims() const
529 {
530     return !points.empty() ? points.cols : 0;
531 }
532 
533 }
534 }
535