KdTree.cpp
Go to the documentation of this file.
1 // ****************************************************************************
2 // This file is part of the Integrating Vision Toolkit (IVT).
3 //
4 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
5 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
6 //
7 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
8 // All rights reserved.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions 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 //
16 // 2. Redistributions in binary form must reproduce the above copyright
17 // notice, this list of conditions and the following disclaimer in the
18 // documentation and/or other materials provided with the distribution.
19 //
20 // 3. Neither the name of the KIT nor the names of its contributors may be
21 // used to endorse or promote products derived from this software
22 // without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
25 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
28 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 // ****************************************************************************
35 // ****************************************************************************
36 // Filename: KdTree.cpp
37 // Author: Kai Welke
38 // Date: 14.04.2005
39 // ****************************************************************************
40 
41 
42 // ****************************************************************************
43 // Includes
44 // ****************************************************************************
45 
46 #include <new> // for explicitly using correct new/delete operators on VC DSPs
47 
48 #include "KdTree.h"
49 #include "KdUtils.h"
50 #include "KdPriorityQueue.h"
51 
52 #include "Helpers/Quicksort.h"
53 #include "Helpers/BasicFileIO.h"
54 
55 #include <stdio.h>
56 #include <float.h>
57 #include <string.h>
58 
59 
60 
61 static inline float SquaredEuclideanDistance(const float *pVector1, const float *pVector2, int nDimension)
62 {
63  register float sum = 0.0f;
64 
65  for (register int x = 0; x < nDimension; x++)
66  {
67  const float v = pVector1[x] - pVector2[x];
68  sum += v * v;
69  }
70 
71  return sum;
72 }
73 
74 static inline float CrossCorrelation(const float *pVector1, const float *pVector2, int nDimension)
75 {
76  register float sum = 0.0f;
77 
78  for (register int x = 0; x < nDimension; x++)
79  sum += pVector1[x] * pVector2[x];
80 
81  return sum;
82 }
83 
84 
85 
86 // ****************************************************************************
87 // Constructor / Destructor
88 // ****************************************************************************
89 
90 CKdTree::CKdTree(int nMaximumNumberOfNodes)
91 {
92  // init pointers
93  m_pRoot = 0;
96 
97  // create priority list for BFF search
98  m_pNodeListBBF = new CKdPriorityQueue(nMaximumNumberOfNodes);
99 
100  // create priority list for second closest element
101  m_pNearestNeighborList_ = new CKdPriorityQueue(nMaximumNumberOfNodes);
103 
104  m_nLeaves = 0;
106 }
107 
109 {
110  Dispose();
111 
112  // delete priotiry queues
113  delete m_pNodeListBBF;
115 }
116 
117 
118 // ****************************************************************************
119 // Methods
120 // ****************************************************************************
121 
122 void CKdTree::Build(float **ppfValues, int nLow, int nHigh, int nBucketSize, int nDimensions, int nUserDataSize)
123 {
124  // set members
125  m_nBucketSize = nBucketSize;
126  m_nDimensions = nDimensions;
127  m_nUserDataSize = nUserDataSize;
129  m_nLeaves = nHigh - nLow + 1;
130 
131  // find enclosing bounding box
133 
134  // init members for recursion
135  m_pRoot = BuildRecursive(ppfValues, nLow, nHigh, &m_EnclosingBox, 0);
136 }
137 
138 CKdTreeNode* CKdTree::BuildRecursive(float **ppfValues,int nLow, int nHigh, KdBoundingBox* pCurrentBoundingBox, int nCurrentDepth)
139 {
140  // **************************************
141  // case1: create a leaf
142  // **************************************
143  if ((nHigh-nLow) <= (m_nBucketSize - 1))
144  {
145  // create leaf
146  CKdTreeNode* pNewNode = new CKdTreeNode();
147 
148  pNewNode->m_bIsLeaf = 1;
149 
150  // create and fill bucket
151  const int nSize = nHigh - nLow + 1;
152 
153  pNewNode->m_pValues = new float[nSize * m_nTotalVectorSize];
154  pNewNode->m_nSize = nSize;
155 
156  float *pValues = pNewNode->m_pValues;
157 
158  for (int n = 0 ; n < nSize; n++)
159  {
160  for (int d = 0; d < m_nTotalVectorSize; d++)
161  pValues[d] = ppfValues[nLow + n][d];
162 
163  pValues += m_nTotalVectorSize;
164  }
165 
166  pNewNode->m_nCutDimension = nCurrentDepth % m_nDimensions;
167  pNewNode->m_Bounding.fLow = pCurrentBoundingBox->pfLow[pNewNode->m_nCutDimension];
168  pNewNode->m_Bounding.fHigh = pCurrentBoundingBox->pfHigh[pNewNode->m_nCutDimension];
169 
170  return pNewNode;
171  }
172 
173 
174  // *********************************************
175  // case2: partition the set and start recursion
176  // *********************************************
177 
178  const int nDimension = nCurrentDepth % m_nDimensions;
179 
180  // Quicksort array to find median and patition sets
181  Quicksort::QuicksortByElementOfVector(ppfValues, nLow, nHigh, nDimension);
182 
183  // retrieve median value
184  const int nMedianIndex = (nHigh - nLow) / 2 + nLow;
185  const float fMedianValue = ppfValues[nMedianIndex][nDimension];
186 
187  // remember original boundings in dimension
188  const float fHigh = pCurrentBoundingBox->pfHigh[nDimension];
189  const float fLow = pCurrentBoundingBox->pfLow[nDimension];
190 
191  // *********************************************
192  // start next recursion
193  // *********************************************
194  // note that median is element of left branch
195  // adjust bounding box to mirror lower part of interval
196  pCurrentBoundingBox->pfHigh[nDimension] = fMedianValue;
197 
198  // create left node
199  CKdTreeNode* pNodeLeft = BuildRecursive(ppfValues, nLow, nMedianIndex, pCurrentBoundingBox, nCurrentDepth + 1);
200 
201  // adjust bounding box to mirror higher part of interval
202  pCurrentBoundingBox->pfHigh[nDimension] = fHigh;
203  pCurrentBoundingBox->pfLow[nDimension] = fMedianValue;
204 
205  // create right node
206  CKdTreeNode* pNodeRight = BuildRecursive(ppfValues, nMedianIndex+1, nHigh, pCurrentBoundingBox, nCurrentDepth + 1);
207 
208  // readjust bounding box
209  pCurrentBoundingBox->pfLow[nDimension] = fLow;
210 
211  // *********************************************
212  // create inner nodes
213  // *********************************************
214  CKdTreeNode* pNewNode = new CKdTreeNode();
215  // set cut dimension
216  pNewNode->m_nCutDimension = nCurrentDepth % m_nDimensions;
217  // set value of median
218  pNewNode->m_fMedianValue = fMedianValue;
219  // set children
220  pNewNode->m_pLeftChild = pNodeLeft;
221  pNewNode->m_pRightChild = pNodeRight;
222  // set boundings in dimension
223  pNewNode->m_Bounding.fLow = pCurrentBoundingBox->pfLow[pNewNode->m_nCutDimension];
224  pNewNode->m_Bounding.fHigh = pCurrentBoundingBox->pfHigh[pNewNode->m_nCutDimension];
225  // this is no leaf!
226  pNewNode->m_bIsLeaf = 0;
227 
228  return pNewNode;
229 }
230 
232 {
233  if (m_pRoot)
235 
236  if (m_EnclosingBox.pfLow)
237  delete [] m_EnclosingBox.pfLow;
238 
240  delete [] m_EnclosingBox.pfHigh;
241 }
242 
244 {
245  if (pNode->m_bIsLeaf)
246  {
247  delete pNode;
248  return;
249  }
250 
251  // recursion
252  if (pNode->m_pLeftChild) DisposeRecursive(pNode->m_pLeftChild);
253  if (pNode->m_pRightChild) DisposeRecursive(pNode->m_pRightChild);
254 
255  delete pNode;
256 }
257 
258 
259 
260 void CKdTree::NearestNeighbor(const float *pQuery, float &fError, float *&pfNN, int nMaximumLeavesToVisit)
261 {
262  // not used in this call
264 
265  m_nMaximumLeavesToVisit = nMaximumLeavesToVisit <= 0 ? m_nLeaves : nMaximumLeavesToVisit;
266  m_fCurrentMinDistance = FLT_MAX;
267 
268  // start recursion
270 
271  // set return values
272  fError = m_fCurrentMinDistance;
273  pfNN = m_pNearestNeighbor;
274 }
275 
276 void CKdTree::NearestNeighborBBF(const float *pQuery, float &fError, float *&pfNN, int nMaximumLeavesToVisit)
277 {
278  // not used in this call
280 
281  // set recursive parameter
282  m_nMaximumLeavesToVisit = nMaximumLeavesToVisit <= 0 ? m_nLeaves : nMaximumLeavesToVisit;
283  m_fCurrentMinDistance = FLT_MAX;
284 
285  // empty bbf node list for this run
287 
288  // start recursion
289  const float fDistanceBB = GetDistanceFromBox(m_EnclosingBox, pQuery, m_nDimensions);
290  NearestNeighborRecursiveBBF(m_pRoot, pQuery, fDistanceBB);
291 
292  // return result
293  fError = m_fCurrentMinDistance;
294  pfNN = m_pNearestNeighbor;
295 }
296 
297 void CKdTree::NearestNeighbor(const float *pQuery, float &fError, CKdPriorityQueue *&pNNList, int nMaximumLeavesToVisit)
298 {
299  // empty neighbor list
302 
303  // member recursive params for this search
304  m_nMaximumLeavesToVisit = nMaximumLeavesToVisit <= 0 ? m_nLeaves : nMaximumLeavesToVisit;
305  m_fCurrentMinDistance = FLT_MAX;
306 
307  // start recursion
309 
310  // set return values
311  fError = m_fCurrentMinDistance;
312  pNNList = m_pNearestNeighborList;
313 }
314 
315 void CKdTree::NearestNeighborBBF(const float *pQuery, float &fError, CKdPriorityQueue *&pNNList, int nMaximumLeavesToVisit)
316 {
317  // empty neighbor list
320 
321  // set recursive parameter
322  m_nMaximumLeavesToVisit = nMaximumLeavesToVisit <= 0 ? m_nLeaves : nMaximumLeavesToVisit;
323  m_fCurrentMinDistance = FLT_MAX;
324 
325  // empty bbf node list for this run
327 
328  // start recursion
329  const float fDistanceBB = GetDistanceFromBox(m_EnclosingBox, pQuery, m_nDimensions);
330  NearestNeighborRecursiveBBF(m_pRoot, pQuery, fDistanceBB);
331 
332  // return result
333  fError = m_fCurrentMinDistance;
334  pNNList = m_pNearestNeighborList;
335 }
336 
337 
338 void CKdTree::NearestNeighborRecursive(CKdTreeNode *pNode, const float *pQuery)
339 {
340  // maximum number of leaves searched
341  if (m_nMaximumLeavesToVisit == 0)
342  return;
343 
344  if (pNode->m_bIsLeaf)
345  {
346  // go through bucket and find nearest neighbor with linear search
347  float *pValues = pNode->m_pValues;
348  const int nSize = pNode->m_nSize;
349 
350  for (int i = 0 ; i < nSize; i++)
351  {
352  // check distance
353  const float fDistance = SquaredEuclideanDistance(pValues, pQuery, m_nDimensions);
354 
355  if (fDistance < m_fCurrentMinDistance)
356  {
357  m_pNearestNeighbor = pValues;
358  m_fCurrentMinDistance = fDistance;
359 
360  // list for second closest element
363  }
364  }
365 
367 
368  // go up one level
369  return;
370  }
371 
372  // step down
373  const float fCutDifference = pQuery[pNode->m_nCutDimension] - pNode->m_fMedianValue;
374  const bool bFromLeft = fCutDifference < 0.0f;
375 
376  NearestNeighborRecursive(bFromLeft ? pNode->m_pLeftChild : pNode->m_pRightChild, pQuery);
377 
378  // worst-case estimation
379  if (m_fCurrentMinDistance >= fCutDifference * fCutDifference)
380  {
381  // search other sub-tree
382  NearestNeighborRecursive(bFromLeft ? pNode->m_pRightChild : pNode->m_pLeftChild, pQuery);
383  }
384 }
385 
386 void CKdTree::NearestNeighborRecursiveBBF(CKdTreeNode* pNode, const float *pQuery, float fDistanceBB)
387 {
388  // maximum number of leaves searched
389  if (m_nMaximumLeavesToVisit == 0)
390  return;
391 
392  if (pNode->m_bIsLeaf)
393  {
394  // go through bucket and find nearest neighbor with linear search
395  float *pValues = pNode->m_pValues;
396  const int nSize = pNode->m_nSize;
397 
398  for (int i = 0; i < nSize; i++)
399  {
400  const float fDistance = SquaredEuclideanDistance(pValues, pQuery, m_nDimensions);
401 
402  if (fDistance < m_fCurrentMinDistance)
403  {
404  m_pNearestNeighbor = pValues;
405  m_fCurrentMinDistance = fDistance;
406 
407  // list for second closest element
410  }
411 
412  pValues += m_nTotalVectorSize;
413  }
414 
416 
417  return;
418  }
419 
420 
421  // step down
422  const int nDimension = pNode->m_nCutDimension;
423 
424  // difference from query to cut plane
425  const float fCutDifference = pQuery[nDimension] - pNode->m_fMedianValue;
426 
427  if (fCutDifference < 0.0f)
428  {
429  // difference from box to point (was the old distance for this node)
430  float fBoxDifference = pNode->m_Bounding.fLow - pQuery[nDimension];
431 
432  // point inside? -> no difference
433  if (fBoxDifference < 0.0f)
434  fBoxDifference = 0.0f;
435 
436  // adjust distance:
437  // subtract old distance (fBoxDifference)
438  // add new distance (fCutDifference = new lower bound of right child)
439  const float fChildDistanceBB = fDistanceBB - fBoxDifference * fBoxDifference + fCutDifference * fCutDifference;
440 
441  // store node in BBF node list
442  m_pNodeListBBF->Push(fChildDistanceBB, pNode->m_pRightChild);
443 
444  // step down left
445  NearestNeighborRecursiveBBF(pNode->m_pLeftChild, pQuery, fDistanceBB);
446  }
447  else
448  {
449  // difference from box to point (was the old distance for this node)
450  float fBoxDifference = pQuery[nDimension] - pNode->m_Bounding.fHigh;
451 
452  // point inside? -> no difference
453  if (fBoxDifference < 0.0f)
454  fBoxDifference = 0.0f;
455 
456  // adjust distance:
457  // subtract old distance (fBoxDifference)
458  // add new distance (fCutDifference = new lower bound of right child)
459  const float fChildDistanceBB = fDistanceBB - fBoxDifference * fBoxDifference + fCutDifference * fCutDifference;
460 
461  // store node in BBF node list
462  m_pNodeListBBF->Push(fChildDistanceBB, pNode->m_pLeftChild);
463 
464  // step down right
465  NearestNeighborRecursiveBBF(pNode->m_pRightChild, pQuery, fDistanceBB);
466  }
467 
468  // step up (using best node - BBF)
469  // take best node from priority queue as next possible node
470  float fChildDistanceBB;
471  m_pNodeListBBF->Pop(fChildDistanceBB, (void *&) pNode);
472 
473  // pruefe ob Distanz zwischen Median und Anfrage in der Dimension
474  // des Knotens groesser ist, als die minimale distanz bisher
475  if (m_fCurrentMinDistance >= fChildDistanceBB)
476  NearestNeighborRecursiveBBF(pNode, pQuery, fChildDistanceBB);
477 }
CKdTree(int nMaximumNumberOfNodes=10000)
Definition: KdTree.cpp:90
int m_nMaximumLeavesToVisit
Definition: KdTree.h:163
float fHigh
Definition: KdStructs.h:53
int m_nDimensions
Definition: KdTree.h:149
void NearestNeighborRecursiveBBF(CKdTreeNode *pNode, const float *pQuery, float fDistanceBB)
Definition: KdTree.cpp:386
CKdTreeNode * m_pRightChild
Definition: KdTree.h:87
CKdPriorityQueue * m_pNodeListBBF
Definition: KdTree.h:168
float m_fMedianValue
Definition: KdTree.h:89
KdBoundingBox CalculateEnclosingBoundingBox(float **ppValues, int nDimension, int nSize)
Definition: KdUtils.h:62
GLenum GLsizei n
Definition: glext.h:4209
void Pop(float &fValue, void *&pMeta)
int m_nUserDataSize
Definition: KdTree.h:151
float GetDistanceFromBox(KdBoundingBox BoundingBox, const float *pValues, int nDimension)
Definition: KdUtils.h:100
CKdPriorityQueue * m_pNearestNeighborList_
Definition: KdTree.h:166
float * m_pValues
Definition: KdTree.h:97
float * pfHigh
Definition: KdStructs.h:66
float * pfLow
Definition: KdStructs.h:64
static float SquaredEuclideanDistance(const float *pVector1, const float *pVector2, int nDimension)
Definition: KdTree.cpp:61
int m_nTotalVectorSize
Definition: KdTree.h:153
GLenum GLint x
Definition: glext.h:3125
void QuicksortByElementOfVector(float **ppValues, int nLow, int nHigh, int nSortByDimension)
Definition: Quicksort.cpp:179
CKdPriorityQueue * m_pNearestNeighborList
Definition: KdTree.h:165
~CKdTree()
Definition: KdTree.cpp:108
CKdTreeNode * m_pRoot
Definition: KdTree.h:145
int m_nLeaves
Definition: KdTree.h:155
int m_bIsLeaf
Definition: KdTree.h:93
void NearestNeighborBBF(const float *pfQuery, float &fError, float *&pfNN, int nMaximumLeavesToVisit=-1)
Definition: KdTree.cpp:276
KdBounding m_Bounding
Definition: KdTree.h:91
CKdTreeNode * BuildRecursive(float **ppfValues, int nLow, int nHigh, KdBoundingBox *pCurrentBoundingBox, int nCurrentDepth)
Definition: KdTree.cpp:138
CKdTreeNode * m_pLeftChild
Definition: KdTree.h:87
int m_nBucketSize
Definition: KdTree.h:147
void Build(float **ppfValues, int nLow, int nHigh, int nBucketSize, int nDimensions, int nUserDataSize)
Definition: KdTree.cpp:122
void Dispose()
Definition: KdTree.cpp:231
void NearestNeighborRecursive(CKdTreeNode *pNode, const float *pQuery)
Definition: KdTree.cpp:338
const GLdouble * v
Definition: glext.h:3212
float * m_pNearestNeighbor
Definition: KdTree.h:161
static float CrossCorrelation(const float *pVector1, const float *pVector2, int nDimension)
Definition: KdTree.cpp:74
void DisposeRecursive(CKdTreeNode *pNode)
Definition: KdTree.cpp:243
KdBoundingBox m_EnclosingBox
Definition: KdTree.h:157
void NearestNeighbor(const float *pQuery, float &fError, float *&pfNN, int nMaximumLeavesToVisit=-1)
Definition: KdTree.cpp:260
void Push(float fValue, void *pMeta)
int m_nCutDimension
Definition: KdTree.h:94
float m_fCurrentMinDistance
Definition: KdTree.h:160
int m_nSize
Definition: KdTree.h:96
float fLow
Definition: KdStructs.h:51


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Mon Dec 2 2019 03:47:28