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