KdTree.cpp
Go to the documentation of this file.
00001 // ****************************************************************************
00002 // This file is part of the Integrating Vision Toolkit (IVT).
00003 //
00004 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
00005 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
00006 //
00007 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
00008 // All rights reserved.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are met:
00012 //
00013 // 1. Redistributions of source code must retain the above copyright
00014 //    notice, this list of conditions and the following disclaimer.
00015 //
00016 // 2. Redistributions in binary form must reproduce the above copyright
00017 //    notice, this list of conditions and the following disclaimer in the
00018 //    documentation and/or other materials provided with the distribution.
00019 //
00020 // 3. Neither the name of the KIT nor the names of its contributors may be
00021 //    used to endorse or promote products derived from this software
00022 //    without specific prior written permission.
00023 //
00024 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
00025 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
00028 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00033 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 // ****************************************************************************
00035 // ****************************************************************************
00036 // Filename:  KdTree.cpp
00037 // Author:    Kai Welke
00038 // Date:      14.04.2005
00039 // ****************************************************************************
00040 
00041 
00042 // ****************************************************************************
00043 // Includes
00044 // ****************************************************************************
00045 
00046 #include <new> // for explicitly using correct new/delete operators on VC DSPs
00047 
00048 #include "KdTree.h"
00049 #include "KdUtils.h"
00050 #include "KdPriorityQueue.h"
00051 
00052 #include "Helpers/Quicksort.h"
00053 #include "Helpers/BasicFileIO.h"
00054 
00055 #include <stdio.h>
00056 #include <float.h>
00057 #include <string.h>
00058 
00059 
00060 
00061 static inline float SquaredEuclideanDistance(const float *pVector1, const float *pVector2, int nDimension)
00062 {
00063         register float sum = 0.0f;
00064         
00065         for (register int x = 0; x < nDimension; x++)
00066         {
00067                 const float v = pVector1[x] - pVector2[x];
00068                 sum += v * v;
00069         }
00070         
00071         return sum;
00072 }
00073 
00074 static inline float CrossCorrelation(const float *pVector1, const float *pVector2, int nDimension)
00075 {
00076         register float sum = 0.0f;
00077         
00078         for (register int x = 0; x < nDimension; x++)
00079                 sum += pVector1[x] * pVector2[x];
00080         
00081         return sum;
00082 }
00083 
00084 
00085 
00086 // ****************************************************************************
00087 // Constructor / Destructor
00088 // ****************************************************************************
00089 
00090 CKdTree::CKdTree(int nMaximumNumberOfNodes)
00091 {
00092         // init pointers
00093         m_pRoot = 0;
00094         m_EnclosingBox.pfLow = 0;
00095         m_EnclosingBox.pfHigh = 0;
00096         
00097         // create priority list for BFF search
00098         m_pNodeListBBF = new CKdPriorityQueue(nMaximumNumberOfNodes);
00099         
00100         // create priority list for second closest element
00101         m_pNearestNeighborList_ = new CKdPriorityQueue(nMaximumNumberOfNodes);
00102         m_pNearestNeighborList = 0;
00103         
00104         m_nLeaves = 0;
00105         m_nMaximumLeavesToVisit = 0;
00106 }
00107 
00108 CKdTree::~CKdTree()
00109 {
00110         Dispose();
00111         
00112         // delete priotiry queues
00113         delete m_pNodeListBBF;
00114         delete m_pNearestNeighborList_;
00115 }
00116 
00117 
00118 // ****************************************************************************
00119 // Methods
00120 // ****************************************************************************
00121 
00122 void CKdTree::Build(float **ppfValues, int nLow, int nHigh, int nBucketSize, int nDimensions, int nUserDataSize)
00123 {
00124         // set members
00125         m_nBucketSize = nBucketSize;
00126         m_nDimensions = nDimensions;
00127     m_nUserDataSize = nUserDataSize;
00128         m_nTotalVectorSize = m_nDimensions + m_nUserDataSize;
00129         m_nLeaves = nHigh - nLow + 1;
00130         
00131         // find enclosing bounding box
00132         m_EnclosingBox = CalculateEnclosingBoundingBox(ppfValues, m_nDimensions, m_nLeaves);
00133         
00134         // init members for recursion
00135         m_pRoot = BuildRecursive(ppfValues, nLow, nHigh, &m_EnclosingBox, 0);
00136 }
00137 
00138 CKdTreeNode* CKdTree::BuildRecursive(float **ppfValues,int nLow, int nHigh, KdBoundingBox* pCurrentBoundingBox, int nCurrentDepth)
00139 {
00140         // **************************************
00141         // case1: create a leaf
00142         // **************************************
00143         if ((nHigh-nLow) <= (m_nBucketSize - 1))
00144         {
00145                 // create leaf
00146                 CKdTreeNode* pNewNode = new CKdTreeNode();
00147                 
00148                 pNewNode->m_bIsLeaf = 1;
00149                 
00150                 // create and fill bucket
00151                 const int nSize = nHigh - nLow + 1;
00152                                 
00153                 pNewNode->m_pValues = new float[nSize * m_nTotalVectorSize];
00154                 pNewNode->m_nSize = nSize;
00155                 
00156                 float *pValues = pNewNode->m_pValues;
00157                 
00158                 for (int n = 0 ; n <  nSize; n++)
00159                 {
00160                         for (int d = 0; d < m_nTotalVectorSize; d++)
00161                                 pValues[d] = ppfValues[nLow + n][d];
00162                         
00163                         pValues += m_nTotalVectorSize;
00164                 }
00165                 
00166                 pNewNode->m_nCutDimension = nCurrentDepth % m_nDimensions;
00167                 pNewNode->m_Bounding.fLow = pCurrentBoundingBox->pfLow[pNewNode->m_nCutDimension];
00168                 pNewNode->m_Bounding.fHigh = pCurrentBoundingBox->pfHigh[pNewNode->m_nCutDimension];
00169                 
00170                 return pNewNode;
00171         } 
00172 
00173         
00174         // *********************************************
00175         // case2: partition the set and start recursion
00176         // *********************************************
00177         
00178         const int nDimension = nCurrentDepth % m_nDimensions;
00179         
00180         // Quicksort array to find median and patition sets
00181         Quicksort::QuicksortByElementOfVector(ppfValues, nLow, nHigh, nDimension);
00182         
00183         // retrieve median value
00184         const int nMedianIndex = (nHigh - nLow) / 2 + nLow;
00185         const float fMedianValue = ppfValues[nMedianIndex][nDimension];
00186         
00187         // remember original boundings in dimension
00188         const float fHigh = pCurrentBoundingBox->pfHigh[nDimension];
00189         const float fLow = pCurrentBoundingBox->pfLow[nDimension];
00190         
00191         // *********************************************
00192         // start next recursion
00193         // *********************************************
00194         // note that median is element of left branch
00195         // adjust bounding box to mirror lower part of interval
00196         pCurrentBoundingBox->pfHigh[nDimension] = fMedianValue;
00197         
00198         // create left node
00199         CKdTreeNode* pNodeLeft = BuildRecursive(ppfValues, nLow, nMedianIndex, pCurrentBoundingBox, nCurrentDepth + 1);
00200         
00201         // adjust bounding box to mirror higher part of interval
00202         pCurrentBoundingBox->pfHigh[nDimension] = fHigh;
00203         pCurrentBoundingBox->pfLow[nDimension] = fMedianValue;
00204         
00205         // create right node
00206         CKdTreeNode* pNodeRight = BuildRecursive(ppfValues, nMedianIndex+1, nHigh, pCurrentBoundingBox, nCurrentDepth + 1);
00207         
00208         // readjust bounding box
00209         pCurrentBoundingBox->pfLow[nDimension] = fLow;
00210         
00211         // *********************************************
00212         // create inner nodes
00213         // *********************************************
00214         CKdTreeNode* pNewNode = new CKdTreeNode();
00215         // set cut dimension
00216         pNewNode->m_nCutDimension = nCurrentDepth % m_nDimensions;
00217         // set value of median
00218         pNewNode->m_fMedianValue = fMedianValue;
00219         // set children
00220         pNewNode->m_pLeftChild = pNodeLeft;
00221         pNewNode->m_pRightChild = pNodeRight;
00222         // set boundings in dimension
00223         pNewNode->m_Bounding.fLow = pCurrentBoundingBox->pfLow[pNewNode->m_nCutDimension];
00224         pNewNode->m_Bounding.fHigh = pCurrentBoundingBox->pfHigh[pNewNode->m_nCutDimension];
00225         // this is no leaf!
00226         pNewNode->m_bIsLeaf = 0;
00227         
00228         return pNewNode;
00229 }
00230 
00231 void CKdTree::Dispose()
00232 {
00233         if (m_pRoot)
00234                 DisposeRecursive(m_pRoot);
00235                 
00236         if (m_EnclosingBox.pfLow)
00237                 delete [] m_EnclosingBox.pfLow;
00238         
00239         if (m_EnclosingBox.pfHigh)
00240                 delete [] m_EnclosingBox.pfHigh;
00241 }
00242 
00243 void CKdTree::DisposeRecursive(CKdTreeNode *pNode)
00244 {
00245         if (pNode->m_bIsLeaf)
00246         {
00247                 delete pNode;
00248                 return;
00249         }
00250         
00251         // recursion
00252         if (pNode->m_pLeftChild) DisposeRecursive(pNode->m_pLeftChild); 
00253         if (pNode->m_pRightChild) DisposeRecursive(pNode->m_pRightChild);
00254 
00255         delete pNode;
00256 }
00257 
00258 
00259 
00260 void CKdTree::NearestNeighbor(const float *pQuery, float &fError, float *&pfNN, int nMaximumLeavesToVisit)
00261 {
00262         // not used in this call
00263         m_pNearestNeighborList = 0;
00264         
00265         m_nMaximumLeavesToVisit = nMaximumLeavesToVisit <= 0 ? m_nLeaves : nMaximumLeavesToVisit;
00266         m_fCurrentMinDistance = FLT_MAX;
00267         
00268         // start recursion
00269         NearestNeighborRecursive(m_pRoot, pQuery);      
00270         
00271         // set return values
00272         fError = m_fCurrentMinDistance;
00273         pfNN = m_pNearestNeighbor;
00274 }
00275 
00276 void CKdTree::NearestNeighborBBF(const float *pQuery, float &fError, float *&pfNN, int nMaximumLeavesToVisit)
00277 {
00278         // not used in this call
00279         m_pNearestNeighborList = 0;
00280         
00281         // set recursive parameter
00282         m_nMaximumLeavesToVisit = nMaximumLeavesToVisit <= 0 ? m_nLeaves : nMaximumLeavesToVisit;
00283         m_fCurrentMinDistance = FLT_MAX;
00284         
00285         // empty bbf node list for this run
00286         m_pNodeListBBF->Empty();
00287 
00288         // start recursion
00289         const float fDistanceBB = GetDistanceFromBox(m_EnclosingBox, pQuery, m_nDimensions);
00290         NearestNeighborRecursiveBBF(m_pRoot, pQuery, fDistanceBB);      
00291         
00292         // return result
00293         fError = m_fCurrentMinDistance;
00294         pfNN = m_pNearestNeighbor;
00295 }
00296 
00297 void CKdTree::NearestNeighbor(const float *pQuery, float &fError, CKdPriorityQueue *&pNNList, int nMaximumLeavesToVisit)
00298 {
00299         // empty neighbor list
00300         m_pNearestNeighborList = m_pNearestNeighborList_;
00301         m_pNearestNeighborList->Empty();
00302         
00303         // member recursive params for this search
00304         m_nMaximumLeavesToVisit = nMaximumLeavesToVisit <= 0 ? m_nLeaves : nMaximumLeavesToVisit;
00305         m_fCurrentMinDistance = FLT_MAX;
00306         
00307         // start recursion
00308         NearestNeighborRecursive(m_pRoot, pQuery);      
00309         
00310         // set return values
00311         fError = m_fCurrentMinDistance;
00312         pNNList = m_pNearestNeighborList;
00313 }
00314 
00315 void CKdTree::NearestNeighborBBF(const float *pQuery, float &fError, CKdPriorityQueue *&pNNList, int nMaximumLeavesToVisit)
00316 {
00317         // empty neighbor list
00318         m_pNearestNeighborList = m_pNearestNeighborList_;
00319         m_pNearestNeighborList->Empty();
00320         
00321         // set recursive parameter
00322         m_nMaximumLeavesToVisit = nMaximumLeavesToVisit <= 0 ? m_nLeaves : nMaximumLeavesToVisit;
00323         m_fCurrentMinDistance = FLT_MAX;
00324         
00325         // empty bbf node list for this run
00326         m_pNodeListBBF->Empty();
00327 
00328         // start recursion      
00329         const float fDistanceBB = GetDistanceFromBox(m_EnclosingBox, pQuery, m_nDimensions);
00330         NearestNeighborRecursiveBBF(m_pRoot, pQuery, fDistanceBB);      
00331         
00332         // return result
00333         fError = m_fCurrentMinDistance;
00334         pNNList = m_pNearestNeighborList;
00335 }
00336 
00337 
00338 void CKdTree::NearestNeighborRecursive(CKdTreeNode *pNode, const float *pQuery)
00339 {
00340         // maximum number of leaves searched
00341         if (m_nMaximumLeavesToVisit == 0)
00342                 return;
00343         
00344         if (pNode->m_bIsLeaf)
00345         {
00346                 // go through bucket and find nearest neighbor with linear search
00347                 float *pValues = pNode->m_pValues;
00348                 const int nSize = pNode->m_nSize;
00349                 
00350                 for (int i = 0 ; i < nSize; i++)
00351                 {
00352                         // check distance
00353                         const float fDistance = SquaredEuclideanDistance(pValues, pQuery, m_nDimensions);
00354                         
00355                         if (fDistance < m_fCurrentMinDistance)
00356                         {
00357                                 m_pNearestNeighbor = pValues;
00358                                 m_fCurrentMinDistance = fDistance;
00359                                 
00360                                 // list for second closest element
00361                                 if (m_pNearestNeighborList)
00362                                         m_pNearestNeighborList->Push(m_fCurrentMinDistance, pValues);
00363                         }
00364                 }
00365         
00366                 m_nMaximumLeavesToVisit--;
00367                         
00368                 // go up one level
00369                 return;
00370         }
00371     
00372         // step down
00373         const float fCutDifference = pQuery[pNode->m_nCutDimension] - pNode->m_fMedianValue;
00374         const bool bFromLeft = fCutDifference < 0.0f;
00375         
00376         NearestNeighborRecursive(bFromLeft ? pNode->m_pLeftChild : pNode->m_pRightChild, pQuery);
00377 
00378         // worst-case estimation
00379         if (m_fCurrentMinDistance >= fCutDifference * fCutDifference)
00380         {
00381                 // search other sub-tree
00382                 NearestNeighborRecursive(bFromLeft ? pNode->m_pRightChild : pNode->m_pLeftChild, pQuery);
00383         }
00384 }
00385 
00386 void CKdTree::NearestNeighborRecursiveBBF(CKdTreeNode* pNode, const float *pQuery, float fDistanceBB)
00387 {
00388         // maximum number of leaves searched
00389         if (m_nMaximumLeavesToVisit == 0)
00390                 return;
00391         
00392         if (pNode->m_bIsLeaf)
00393         {
00394                 // go through bucket and find nearest neighbor with linear search
00395                 float *pValues = pNode->m_pValues;
00396                 const int nSize = pNode->m_nSize;
00397 
00398                 for (int i = 0; i < nSize; i++)
00399                 {
00400                         const float fDistance = SquaredEuclideanDistance(pValues, pQuery, m_nDimensions);
00401                         
00402                         if (fDistance < m_fCurrentMinDistance)
00403                         {
00404                                 m_pNearestNeighbor = pValues;                                   
00405                                 m_fCurrentMinDistance = fDistance;
00406                                 
00407                                 // list for second closest element
00408                                 if (m_pNearestNeighborList)
00409                                         m_pNearestNeighborList->Push(m_fCurrentMinDistance, pValues);
00410                         }
00411                         
00412                         pValues += m_nTotalVectorSize;
00413                 }
00414 
00415                 m_nMaximumLeavesToVisit--;
00416                 
00417                 return;
00418         }
00419             
00420         
00421         // step down
00422         const int nDimension = pNode->m_nCutDimension;
00423 
00424         // difference from query to cut plane
00425         const float fCutDifference = pQuery[nDimension] - pNode->m_fMedianValue;
00426         
00427         if (fCutDifference < 0.0f)
00428         {
00429                 // difference from box to point (was the old distance for this node)
00430                 float fBoxDifference = pNode->m_Bounding.fLow - pQuery[nDimension];
00431 
00432                 // point inside? -> no difference
00433                 if (fBoxDifference < 0.0f)
00434                         fBoxDifference = 0.0f;
00435                         
00436                 // adjust distance:
00437                 // subtract old distance (fBoxDifference)
00438                 // add new distance (fCutDifference = new lower bound of right child)
00439                 const float fChildDistanceBB = fDistanceBB - fBoxDifference * fBoxDifference + fCutDifference * fCutDifference;
00440                         
00441                 // store node in BBF node list
00442                 m_pNodeListBBF->Push(fChildDistanceBB, pNode->m_pRightChild);
00443                 
00444                 // step down left
00445                 NearestNeighborRecursiveBBF(pNode->m_pLeftChild, pQuery,  fDistanceBB);
00446         } 
00447         else
00448         {
00449                 // difference from box to point (was the old distance for this node)
00450                 float fBoxDifference = pQuery[nDimension] - pNode->m_Bounding.fHigh;
00451 
00452                 // point inside? -> no difference
00453                 if (fBoxDifference < 0.0f)
00454                         fBoxDifference = 0.0f;
00455                         
00456                 // adjust distance:
00457                 // subtract old distance (fBoxDifference)
00458                 // add new distance (fCutDifference = new lower bound of right child)
00459                 const float fChildDistanceBB = fDistanceBB - fBoxDifference * fBoxDifference + fCutDifference * fCutDifference;
00460                         
00461                 // store node in BBF node list
00462                 m_pNodeListBBF->Push(fChildDistanceBB, pNode->m_pLeftChild);
00463                 
00464                 // step down right
00465                 NearestNeighborRecursiveBBF(pNode->m_pRightChild, pQuery, fDistanceBB);
00466         }
00467 
00468         // step up (using best node - BBF)
00469         // take best node from priority queue as next possible node
00470         float fChildDistanceBB;
00471         m_pNodeListBBF->Pop(fChildDistanceBB, (void *&) pNode);
00472         
00473         // pruefe ob Distanz zwischen Median und Anfrage in der Dimension 
00474         // des Knotens groesser ist, als die minimale distanz bisher
00475         if (m_fCurrentMinDistance >= fChildDistanceBB)
00476                 NearestNeighborRecursiveBBF(pNode, pQuery, fChildDistanceBB);
00477 }


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Thu Jun 6 2019 21:46:57