Super4PCS Library  V1.1.2(719f5c0)
intersectionNode.h
1 // Copyright 2014 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: Nicolas Mellado
18 //
19 // An 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 
48 #ifndef _SUPER4PCS_ACCELERATORS_INTERSECTION_NODE_H_
49 #define _SUPER4PCS_ACCELERATORS_INTERSECTION_NODE_H_
50 
51 #include <list>
52 #include "super4pcs/accelerators/utils.h"
53 
54 namespace GlobalRegistration{
55 namespace Accelerators{
56 namespace PairExtraction{
57 
67 template <class Point,
68  int _dim,
69  typename Scalar,
70  class _PointContainer = std::vector<Point>,
71  class _IdContainer = std::vector<unsigned int> >
72 class NdNode{
73 public:
74  enum { Dim = _dim };
75  typedef _PointContainer PointContainer;
76  typedef _IdContainer IdContainer;
77 
78 protected:
79  const PointContainer& _points;
80  IdContainer& _ids;
81  Point _center;
82  unsigned int _begin,
83  _end;
84 
85 public:
86  inline NdNode(const PointContainer& points,
87  IdContainer& ids,
88  const Point& p = Point::Zero(),
89  unsigned int begin = 0,
90  unsigned int end = 0)
91  : _points(points), _ids(ids), _center(p), _begin(begin), _end(end) {}
92 
94  : _points(other._points), _ids(other._ids),
95  _center(other._center),
96  _begin (other._begin), _end(other._end) {}
97 
100  {
101  //_points = rhs._points; // Nodes must be working on the same container
102  _ids = rhs._ids;
103  _center = rhs._center;
104  _begin = rhs._begin;
105  _end = rhs._end;
106 
107  return *this;
108  }
109 
110  inline ~NdNode(){}
111 
113  inline int rangeLength() const { return int(_end) - int(_begin); }
115  inline unsigned int rangeBegin() const { return _begin; }
117  inline unsigned int rangeEnd() const { return _end; }
119  inline const Point& pointInRange(unsigned int i) const
120  { return _points[_ids[i+_begin]]; }
122  inline unsigned int idInRange(unsigned int i) const
123  { return _ids[i+_begin]; }
124 
126  inline const Point& center() const { return _center; }
127 
130  void
131  split(
133  Scalar rootEdgeHalfLength );
134 
135  inline static
137  buildUnitRootNode(const PointContainer& points,
138  IdContainer& ids)
139  {
141  points, ids, Point::Ones() / 2., 0, ids.size());
142  }
143 
144  private:
145  inline unsigned int _split(int start, int end,
146  unsigned int dim,
147  Scalar splitValue);
148 };
149 
150 
151 template <class Point,
152  int _dim,
153  typename Scalar,
154  class _PointContainer,
155  class _IdContainer>
156 unsigned int
158  int start,
159  int end,
160  unsigned int dim,
161  Scalar splitValue)
162 {
163  int l(start), r(end-1);
164  for ( ; l<r ; ++l, --r)
165  {
166  while (l < end && _points[_ids[l]][dim] < splitValue)
167  l++;
168  while (r >= start && _points[_ids[r]][dim] >= splitValue)
169  r--;
170  if (l > r)
171  break;
172  std::swap(_ids[l],_ids[r]);
173  }
174  if(l>=end) return end;
175  return _points[_ids[l]][dim] < splitValue ? l+1 : l;
176 }
177 
185 template <class Point,
186  int _dim,
187  typename Scalar,
188  class _PointContainer,
189  class _IdContainer>
190 void
193  Scalar rootEdgeHalfLength )
194 {
196  typedef std::vector< Node > Container;
197 
199  const int nbNode = Utils::POW(int(2),int(Dim));
200  const int offset = childs.size();
201 
202  // init all potential nodes using the root values
203  childs.resize(offset+nbNode, *this);
204 
207  for(unsigned int d = 0; d < Dim; d++){
208  const unsigned int nbInterval = Utils::POW(int(2),int(d+1)); // can be deduced at
209  const unsigned int nbSplit = nbInterval/2; // compile time with
210  const unsigned int intervalNode = nbNode / nbSplit; // loop unrollement
211  const unsigned int midNode = nbNode / nbInterval;
212 
214  for(unsigned int s = 0; s != nbSplit; s++) {
215  const unsigned int beginNodeId = s * intervalNode + offset;
216  const unsigned int endNodeId = (s+1) * intervalNode + offset;
217 
218  Scalar currentCenterD = childs[beginNodeId]._center[d];
219 
220  const unsigned int splitId = _split(childs[beginNodeId]._begin,
221  childs[endNodeId-1]._end,
222  d,
223  currentCenterD);
224  const Scalar beforeCenterD = currentCenterD - rootEdgeHalfLength/Scalar(2);
225  const Scalar afterCenterD = currentCenterD + rootEdgeHalfLength/Scalar(2);
226 
228  for (unsigned int i = beginNodeId; i != beginNodeId + midNode; i++){
229  childs[i]._center[d] = beforeCenterD;
230  childs[i]._end = splitId;
231  }
232 
233  for (unsigned int i = beginNodeId + midNode; i != endNodeId; i++){
234  childs[i]._center[d] = afterCenterD;
235  childs[i]._begin = splitId;
236  }
237  }
238  }
239 
240  // Remove childs not containing any element
241  if (!childs.empty()) {
242  childs.erase(std::remove_if(childs.begin(), childs.end(), [](const Node& c)
243  { return c.rangeLength() == 0; }), childs.end());
244  }
245 }
246 
247 } // namespace Accelerators
248 } // namespace PairExtraction
249 } // namespace Super4PCS
250 
251 #endif
252 
_PointContainer PointContainer
Definition: intersectionNode.h:75
unsigned int rangeBegin() const
First position in the id array defining the current instance range.
Definition: intersectionNode.h:115
NdNode(const PointContainer &points, IdContainer &ids, const Point &p=Point::Zero(), unsigned int begin=0, unsigned int end=0)
Definition: intersectionNode.h:86
const Point & pointInRange(unsigned int i) const
Access to the i-eme point in the node. Range limits are NOT tested!
Definition: intersectionNode.h:119
const Point & center() const
Center of the current node.
Definition: intersectionNode.h:126
static NdNode< Point, _dim, Scalar, _PointContainer, _IdContainer > buildUnitRootNode(const PointContainer &points, IdContainer &ids)
Definition: intersectionNode.h:137
Definition: bbox.h:54
constexpr baseT POW(baseT base, expoT expo)
Compile time pow.
Definition: utils.h:62
unsigned int rangeEnd() const
Last position in the id array defining the current instance range.
Definition: intersectionNode.h:117
_IdContainer IdContainer
Definition: intersectionNode.h:76
unsigned int idInRange(unsigned int i) const
Access to the i-eme point in the node. Range limits are NOT tested!
Definition: intersectionNode.h:122
NdNode(const NdNode< Point, _dim, Scalar, _PointContainer, _IdContainer > &other)
Definition: intersectionNode.h:93
void split(std::vector< NdNode< Point, _dim, Scalar, _PointContainer, _IdContainer > > &childs, Scalar rootEdgeHalfLength)
Split the node and compute child nodes.
Definition: intersectionNode.h:191
int rangeLength() const
Length of the range covered by this node in the id array.
Definition: intersectionNode.h:113
Multidimensional node used for intersection query.
Definition: intersectionNode.h:72