kdtree.h
Go to the documentation of this file.
1 // Copyright 2014 Gael Guennebaud, Nicolas Mellado
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // -------------------------------------------------------------------------- //
16 //
17 // Authors: Gael Guennebaud, Nicolas Mellado
18 //
19 // Part of the implementation of the Super 4-points Congruent Sets (Super 4PCS)
20 // algorithm presented in:
21 //
22 // Super 4PCS: Fast Global Pointcloud Registration via Smart Indexing
23 // Nicolas Mellado, Dror Aiger, Niloy J. Mitra
24 // Symposium on Geometry Processing 2014.
25 //
26 // Data acquisition in large-scale scenes regularly involves accumulating
27 // information across multiple scans. A common approach is to locally align scan
28 // pairs using Iterative Closest Point (ICP) algorithm (or its variants), but
29 // requires static scenes and small motion between scan pairs. This prevents
30 // accumulating data across multiple scan sessions and/or different acquisition
31 // modalities (e.g., stereo, depth scans). Alternatively, one can use a global
32 // registration algorithm allowing scans to be in arbitrary initial poses. The
33 // state-of-the-art global registration algorithm, 4PCS, however has a quadratic
34 // time complexity in the number of data points. This vastly limits its
35 // applicability to acquisition of large environments. We present Super 4PCS for
36 // global pointcloud registration that is optimal, i.e., runs in linear time (in
37 // the number of data points) and is also output sensitive in the complexity of
38 // the alignment problem based on the (unknown) overlap across scan pairs.
39 // Technically, we map the algorithm as an ‘instance problem’ and solve it
40 // efficiently using a smart indexing data organization. The algorithm is
41 // simple, memory-efficient, and fast. We demonstrate that Super 4PCS results in
42 // significant speedup over alternative approaches and allows unstructured
43 // efficient acquisition of scenes at scales previously not possible. Complete
44 // source code and datasets are available for research use at
45 // http://geometry.cs.ucl.ac.uk/projects/2014/super4PCS/.
46 
47 #ifndef _OPENGR_ACCELERATORS_KDTREE_H
48 #define _OPENGR_ACCELERATORS_KDTREE_H
49 
50 #include "gr/utils/disablewarnings.h"
51 
52 #include <Eigen/Core>
53 #include <Eigen/Geometry>
54 
55 #include <limits>
56 #include <iostream>
57 #include <vector>
58 #include <numeric> //iota
59 
60 // max depth of the tree
61 #define KD_MAX_DEPTH 32
62 
63 // number of neighbors
64 #define KD_POINT_PER_CELL 64
65 
66 
67 namespace gr{
68 
69 /*!
70  \brief 3D Kdtree with reentrant queries
71  */
72 template<typename _Scalar, typename _Index = int >
73 class KdTree
74 {
75 public:
76  struct KdNode
77  {
78  union {
79  struct {
80  float splitValue;
81  unsigned int firstChildId:24;
82  unsigned int dim:2;
83  unsigned int leaf:1;
84  };
85  struct {
86  unsigned int start;
87  unsigned short size;
88  };
89  };
90  };
91 
92  typedef _Scalar Scalar;
93  typedef _Index Index;
94 
95  static constexpr Index invalidIndex() { return -1; }
96 
97  typedef Eigen::Matrix<Scalar,3,1> VectorType;
98  typedef Eigen::AlignedBox<_Scalar, 3> AxisAlignedBoxType;
99 
103 
104  //! element of the stack
105  struct QueryNode
106  {
107  inline QueryNode() {}
108  inline QueryNode(unsigned int id) : nodeId(id) {}
109  //! id of the next node
110  unsigned int nodeId;
111  //! squared distance to the next node
113  };
114 
115  template <int _stackSize = 64>
116  struct RangeQuery
117  {
120  QueryNode nodeStack[_stackSize];
121  };
122 
123  inline const NodeList& _getNodes (void) { return mNodes; }
124  inline const PointList& _getPoints (void) { return mPoints; }
125  inline const PointList& _getIndices (void) { return mIndices; }
126 
127 
128 public:
129  //! Create the Kd-Tree using memory copy.
130  KdTree(const PointList& points,
131  unsigned int nofPointsPerCell = KD_POINT_PER_CELL,
132  unsigned int maxDepth = KD_MAX_DEPTH );
133 
134  //! Create a void KdTree
135  KdTree( unsigned int size = 0,
136  unsigned int nofPointsPerCell = KD_POINT_PER_CELL,
137  unsigned int maxDepth = KD_MAX_DEPTH );
138 
139  //! Add a new vertex in the KdTree
140  template <class VectorDerived>
141  inline void add( const VectorDerived &p ){
142  // this is ok since the memory has been reserved at construction time
143  mPoints.push_back(p);
144  mIndices.push_back(mIndices.size());
145  mAABB.extend(p);
146  }
147 
148  inline void add(Scalar *position){
149  add(Eigen::Map< Eigen::Matrix<Scalar, 3, 1> >(position));
150  }
151 
152  //! Finalize the creation of the KdTree
153  inline
154  void finalize( );
155 
156  inline const AxisAlignedBoxType& aabb() const {return mAABB; }
157 
158  ~KdTree();
159 
160  /*!
161  * \brief Performs distance query and return vector coordinates
162  */
163  template<int stackSize, typename Container = std::vector<VectorType> >
164  inline void
165  doQueryDist(RangeQuery<stackSize>& query,
166  Container& result) const {
167  _doQueryDistIndicesWithFunctor(query, [&result,this](unsigned int i){
168  result.push_back(mPoints[i]);
169  });
170  }
171 
172  /*!
173  * \brief Performs distance query and return indices
174  */
175  template<int stackSize, typename IndexContainer = std::vector<Index> >
176  inline void
177  doQueryDistIndices(RangeQuery<stackSize>& query,
178  IndexContainer& result) const {
179  _doQueryDistIndicesWithFunctor(query, [&result,this](unsigned int i){
180  result.push_back(mIndices[i]);
181  });
182  }
183 
184  /*!
185  * \brief Performs distance query and return indices
186  */
187  template<int stackSize, typename Functor>
188  inline void
190  Functor f) const {
191  _doQueryDistIndicesWithFunctor(query, [f,this](unsigned int i){
192  f(mIndices[i]);
193  });
194  }
195 
196  /*!
197  * \brief Finds the closest element index within the range [0:sqrt(sqdist)]
198  * \param currentId Index of the querypoint if it belongs to the tree
199  */
200  template<int stackSize>
201  inline std::pair<Index, Scalar>
202  doQueryRestrictedClosestIndex(RangeQuery<stackSize> &query,
203  int currentId = -1) const;
204 
205  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
206 
207 protected:
208 
209  /*!
210  Used to build the tree: split the subset [start..end[ according to dim
211  and splitValue, and returns the index of the first element of the second
212  subset.
213  */
214  inline
215  unsigned int split(int start, int end, unsigned int dim, Scalar splitValue);
216 
217  void createTree(unsigned int nodeId,
218  unsigned int start,
219  unsigned int end,
220  unsigned int level,
221  unsigned int targetCellsize,
222  unsigned int targetMaxDepth);
223 
224 
225  /*!
226  * \brief Performs distance query and pass the internal id to a functor
227  */
228  template<int stackSize, typename Functor >
229  inline void
230  _doQueryDistIndicesWithFunctor(RangeQuery<stackSize>& query,
231  Functor f) const;
232 protected:
233 
238 
239  unsigned int _nofPointsPerCell;
240  unsigned int _maxDepth;
241 };
242 
243 
244 
245 
246 
247 /*!
248  \see KdTree(unsigned int size, unsigned int nofPointsPerCell, unsigned int maxDepth)
249  */
250 template<typename Scalar, typename Index>
251 KdTree<Scalar, Index>::KdTree(const PointList& points,
252  unsigned int nofPointsPerCell,
253  unsigned int maxDepth)
254  : mPoints(points),
255  mIndices(points.size()),
256  _nofPointsPerCell(nofPointsPerCell),
257  _maxDepth(maxDepth)
258 {
259  mAABB.extend(points.cbegin(), points.cend());
260  std::iota (mIndices.begin(), mIndices.end(), 0); // Fill with 0, 1, ..., 99.
261  finalize();
262 }
263 
264 /*!
265  Second way to create the KdTree, in two time. You must call finalize()
266  before requesting for closest points.
267 
268  \see finalize()
269  */
270 template<typename Scalar, typename Index>
271 KdTree<Scalar, Index>::KdTree(unsigned int size,
272  unsigned int nofPointsPerCell,
273  unsigned int maxDepth)
274  : _nofPointsPerCell(nofPointsPerCell),
275  _maxDepth(maxDepth)
276 {
277  mPoints.reserve(size);
278  mIndices.reserve(size);
279 }
280 
281 template<typename Scalar, typename Index>
282 void
283 KdTree<Scalar, Index>::finalize()
284 {
285  mNodes.clear();
286  mNodes.reserve(4*mPoints.size()/_nofPointsPerCell);
287  mNodes.emplace_back();
288  mNodes.back().leaf = 0;
289 #ifdef DEBUG
290  std::cout << "create tree" << std::endl;
291 #endif
292  createTree(0, 0, mPoints.size(), 1, _nofPointsPerCell, _maxDepth);
293 #ifdef DEBUG
294  std::cout << "create tree ... DONE (" << mPoints.size() << " points)" << std::endl;
295 #endif
296 }
297 
298 template<typename Scalar, typename Index>
299 KdTree<Scalar, Index>::~KdTree()
300 {
301 }
302 
303 
304 /*!
305 
306  This algorithm uses the simple distance to the split plane to prune nodes.
307  A more elaborated approach consists to track the closest corner of the cell
308  relatively to the current query point. This strategy allows to save about 5%
309  of the leaves. However, in practice the slight overhead due to this tracking
310  reduces the overall performance.
311 
312  This algorithm also use a simple stack while a priority queue using the squared
313  distances to the cells as a priority values allows to save about 10% of the leaves.
314  But, again, priority queue insertions and deletions are quite involved, and therefore
315  a simple stack is by far much faster.
316 
317  The optionnal parameter currentId is used when the query point is
318  stored in the tree, and must thus be avoided during the query
319 */
320 template<typename Scalar, typename Index>
321 template<int stackSize>
322 std::pair<Index, Scalar>
324  RangeQuery<stackSize>& query,
325  int currentId) const
326 {
327 
328  Index cl_id = invalidIndex();
329  Scalar cl_dist = query.sqdist;
330 
331  query.nodeStack[0].nodeId = 0;
332  query.nodeStack[0].sq = 0.f;
333  unsigned int count = 1;
334 
335  //int nbLoop = 0;
336  while (count)
337  {
338  //nbLoop++;
339  QueryNode& qnode = query.nodeStack[count-1];
340  const KdNode& node = mNodes[qnode.nodeId];
341 
342  if (qnode.sq < cl_dist)
343  {
344  if (node.leaf)
345  {
346  --count; // pop
347  const int end = node.start+node.size;
348  for (int i=node.start ; i<end ; ++i){
349  const Scalar sqdist = (query.queryPoint - mPoints[i]).squaredNorm();
350  if (sqdist <= cl_dist && mIndices[i] != currentId){
351  cl_dist = sqdist;
352  cl_id = mIndices[i];
353  }
354  }
355  }
356  else
357  {
358  // replace the stack top by the farthest and push the closest
359  const Scalar new_off = query.queryPoint[node.dim] - node.splitValue;
360 
361  //std::cout << "new_off = " << new_off << std::endl;
362 
363  if (new_off < 0.)
364  {
365  query.nodeStack[count].nodeId = node.firstChildId; // stack top the farthest
366  qnode.nodeId = node.firstChildId+1; // push the closest
367  }
368  else
369  {
370  query.nodeStack[count].nodeId = node.firstChildId+1;
371  qnode.nodeId = node.firstChildId;
372  }
373  query.nodeStack[count].sq = qnode.sq;
374  qnode.sq = new_off*new_off;
375  ++count;
376  }
377  }
378  else
379  {
380  // pop
381  --count;
382  }
383  }
384  return std::make_pair(cl_id, cl_dist);
385 }
386 
387 /*!
388  \see doQueryRestrictedClosestIndex For more information about the algorithm.
389 
390  This function is an alternative to doQueryDist(const VectorType& queryPoint)
391  that allow to perform the query by requesting a maximum distance instead of
392  neighborhood size.
393  */
394 template<typename Scalar, typename Index>
395 template<int stackSize, typename Functor >
396 void
398  RangeQuery<stackSize>& query,
399  Functor f) const
400 {
401  query.nodeStack[0].nodeId = 0;
402  query.nodeStack[0].sq = 0.f;
403  unsigned int count = 1;
404 
405  while (count)
406  {
407  QueryNode& qnode = query.nodeStack[count-1];
408  const KdNode & node = mNodes[qnode.nodeId];
409 
410  if (qnode.sq < query.sqdist)
411  {
412  if (node.leaf)
413  {
414  --count; // pop
415  unsigned int end = node.start+node.size;
416  for (unsigned int i=node.start ; i<end ; ++i)
417  if ( (query.queryPoint - mPoints[i]).squaredNorm() < query.sqdist){
418  f(i);
419  }
420  }
421  else
422  {
423  // replace the stack top by the farthest and push the closest
424  Scalar new_off = query.queryPoint[node.dim] - node.splitValue;
425  if (new_off < 0.)
426  {
427  query.nodeStack[count].nodeId = node.firstChildId;
428  qnode.nodeId = node.firstChildId+1;
429  }
430  else
431  {
432  query.nodeStack[count].nodeId = node.firstChildId+1;
433  qnode.nodeId = node.firstChildId;
434  }
435  query.nodeStack[count].sq = qnode.sq;
436  qnode.sq = new_off*new_off;
437  ++count;
438  }
439  }
440  else
441  {
442  // pop
443  --count;
444  }
445  }
446 }
447 
448 template<typename Scalar, typename Index>
449 unsigned int KdTree<Scalar, Index>::split(int start, int end, unsigned int dim, Scalar splitValue)
450 {
451  int l(start), r(end-1);
452  for ( ; l<r ; ++l, --r)
453  {
454  while (l < end && mPoints[l][dim] < splitValue)
455  l++;
456  while (r >= start && mPoints[r][dim] >= splitValue)
457  r--;
458  if (l > r)
459  break;
460  std::swap(mPoints[l],mPoints[r]);
461  std::swap(mIndices[l],mIndices[r]);
462  }
463  return (mPoints[l][dim] < splitValue ? l+1 : l);
464 }
465 
466 /*!
467 
468  Recursively builds the kdtree
469 
470 
471  The heuristic is the following:
472  - if the number of points in the node is lower than targetCellsize then make a leaf
473  - else compute the AABB of the points of the node and split it at the middle of
474  the largest AABB dimension.
475 
476  This strategy might look not optimal because it does not explicitly prune empty space,
477  unlike more advanced SAH-like techniques used for RT. On the other hand it leads to a shorter tree,
478  faster to traverse and our experience shown that in the special case of kNN queries,
479  this strategy is indeed more efficient (and much faster to build). Moreover, for volume data
480  (e.g., fluid simulation) pruning the empty space is useless.
481 
482  Actually, storing at each node the exact AABB (we therefore have a binary BVH) allows
483  to prune only about 10% of the leaves, but the overhead of this pruning (ball/ABBB intersection)
484  is more expensive than the gain it provides and the memory consumption is x4 higher !
485 */
486 template<typename Scalar, typename Index>
487 void KdTree<Scalar, Index>::createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level, unsigned int targetCellSize, unsigned int targetMaxDepth)
488 {
489 
490  KdNode& node = mNodes[nodeId];
491  AxisAlignedBoxType aabb;
492  //aabb.Set(mPoints[start]);
493  for (unsigned int i=start ; i<end ; ++i)
494  aabb.extend(mPoints[i]);
495 
496  VectorType diag = aabb.diagonal();
497  typename VectorType::Index dim;
498 
499 #ifdef DEBUG
500 
501 // std::cout << "createTree("
502 // << nodeId << ", "
503 // << start << ", "
504 // << end << ", "
505 // << level << ")"
506 // << std::endl;
507 
508  if (std::isnan(diag.maxCoeff(&dim))){
509  std::cerr << "NaN values discovered in the tree, abort" << std::endl;
510  return;
511  }
512 #else
513  diag.maxCoeff(&dim);
514 #endif
515 
516 
517 #undef DEBUG
518  node.dim = dim;
519  node.splitValue = aabb.center()(dim);
520 
521  unsigned int midId = split(start, end, dim, node.splitValue);
522 
523  node.firstChildId = mNodes.size();
524 
525  {
526  KdNode n;
527  n.size = 0;
528  mNodes.push_back(n);
529  mNodes.push_back(n);
530  }
531  //mNodes << Node() << Node();
532  //mNodes.resize(mNodes.size()+2);
533 
534  {
535  // left child
536  unsigned int childId = mNodes[nodeId].firstChildId;
537  KdNode& child = mNodes[childId];
538  if (midId-start <= targetCellSize || level>=targetMaxDepth)
539  {
540  child.leaf = 1;
541  child.start = start;
542  child.size = midId-start;
543  }
544  else
545  {
546  child.leaf = 0;
547  createTree(childId, start, midId, level+1, targetCellSize, targetMaxDepth);
548  }
549  }
550 
551  {
552  // right child
553  unsigned int childId = mNodes[nodeId].firstChildId+1;
554  KdNode& child = mNodes[childId];
555  if (end-midId <= targetCellSize || level>=targetMaxDepth)
556  {
557  child.leaf = 1;
558  child.start = midId;
559  child.size = end-midId;
560  }
561  else
562  {
563  child.leaf = 0;
564  createTree(childId, midId, end, level+1, targetCellSize, targetMaxDepth);
565  }
566  }
567 }
568 } //namespace gr
569 
570 
571 #endif // KDTREE_H
std::vector< VectorType > PointList
Definition: kdtree.h:101
Scalar sqdist
Definition: kdtree.h:119
Scalar sq
squared distance to the next node
Definition: kdtree.h:112
unsigned int _maxDepth
Definition: kdtree.h:240
void add(const VectorDerived &p)
Add a new vertex in the KdTree.
Definition: kdtree.h:141
IndexList mIndices
Definition: kdtree.h:235
Definition: kdtree.h:76
#define KD_MAX_DEPTH
Definition: kdtree.h:61
NodeList mNodes
Definition: kdtree.h:237
const PointList & _getPoints(void)
Definition: kdtree.h:124
PointList mPoints
Definition: kdtree.h:234
void finalize()
Finalize the creation of the KdTree.
Definition: kdtree.h:283
void _doQueryDistIndicesWithFunctor(RangeQuery< stackSize > &query, Functor f) const
Performs distance query and pass the internal id to a functor.
Definition: kdtree.h:397
~KdTree()
Definition: kdtree.h:299
Eigen::AlignedBox< _Scalar, 3 > AxisAlignedBoxType
Definition: kdtree.h:98
Definition: kdtree.h:116
void add(Scalar *position)
Definition: kdtree.h:148
void doQueryDistIndices(RangeQuery< stackSize > &query, IndexContainer &result) const
Performs distance query and return indices.
Definition: kdtree.h:177
const AxisAlignedBoxType & aabb() const
Definition: kdtree.h:156
void doQueryDistProcessIndices(RangeQuery< stackSize > &query, Functor f) const
Performs distance query and return indices.
Definition: kdtree.h:189
#define KD_POINT_PER_CELL
Definition: kdtree.h:64
QueryNode(unsigned int id)
Definition: kdtree.h:108
void createTree(unsigned int nodeId, unsigned int start, unsigned int end, unsigned int level, unsigned int targetCellsize, unsigned int targetMaxDepth)
Recursively builds the kdtree.
Definition: kdtree.h:487
KdTree(const PointList &points, unsigned int nofPointsPerCell=KD_POINT_PER_CELL, unsigned int maxDepth=KD_MAX_DEPTH)
Create the Kd-Tree using memory copy.
Definition: kdtree.h:251
std::vector< Index > IndexList
Definition: kdtree.h:102
const NodeList & _getNodes(void)
Definition: kdtree.h:123
CongruentSetExplorationBase< Traits, PointType, TransformVisitor, PairFilteringFunctor, OptExts... >::Scalar ComputeTransformation(const InputRange1 &P, const InputRange2 &Q, Eigen::Ref< typename CongruentSetExplorationBase< Traits, PointType, TransformVisitor, PairFilteringFunctor, OptExts... >::MatrixType > transformation, const Sampler< PointType > &sampler, TransformVisitor &v)
Definition: congruentSetExplorationBase.hpp:61
_Scalar Scalar
Definition: kdtree.h:92
element of the stack
Definition: kdtree.h:105
VectorType queryPoint
Definition: kdtree.h:118
_Index Index
Definition: kdtree.h:93
KdTree(unsigned int size=0, unsigned int nofPointsPerCell=KD_POINT_PER_CELL, unsigned int maxDepth=KD_MAX_DEPTH)
Create a void KdTree.
Definition: kdtree.h:271
void doQueryDist(RangeQuery< stackSize > &query, Container &result) const
Performs distance query and return vector coordinates.
Definition: kdtree.h:165
std::vector< KdNode > NodeList
Definition: kdtree.h:100
QueryNode()
Definition: kdtree.h:107
std::pair< Index, Scalar > doQueryRestrictedClosestIndex(RangeQuery< stackSize > &query, int currentId=-1) const
Finds the closest element index within the range [0:sqrt(sqdist)].
Definition: kdtree.h:323
unsigned int split(int start, int end, unsigned int dim, Scalar splitValue)
Used to build the tree: split the subset [start..end[ according to dim and splitValue, and returns the index of the first element of the second subset.
Definition: kdtree.h:449
unsigned int nodeId
id of the next node
Definition: kdtree.h:110
AxisAlignedBoxType mAABB
Definition: kdtree.h:236
static constexpr Index invalidIndex()
Definition: kdtree.h:95
unsigned int _nofPointsPerCell
Definition: kdtree.h:239
const PointList & _getIndices(void)
Definition: kdtree.h:125
QueryNode nodeStack[_stackSize]
Definition: kdtree.h:120