intersectionNode.h
Go to the documentation of this file.
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 _OPENGR_ACCELERATORS_INTERSECTION_NODE_H_
49 #define _OPENGR_ACCELERATORS_INTERSECTION_NODE_H_
50 
51 #include <list>
52 #include "gr/accelerators/utils.h"
53 
54 namespace gr{
55 
56 /*!
57  \brief Multidimensional node used for intersection query
58 
59  Each instance store references to the data arrays:
60  - const access to the input points
61  - writing access to the dereferencing id array
62 
63  The working dimension is deduced from the Point class
64  */
65 template <class Point,
66  int _dim,
67  typename Scalar,
68  class _PointContainer = std::vector<Point>,
69  class _IdContainer = std::vector<unsigned int> >
70 class NdNode{
71 public:
72  enum { Dim = _dim };
75 
76 protected:
77  const PointContainer& _points; //!< Input points. Needed to compute split
78  IdContainer& _ids; //!< Ids used to access _points[_ids[i]]
79  Point _center; //!< Center of the node in the nd-space
80  unsigned int _begin, //!< First element id in the node
81  _end; //!< Last element id in the node
82 
83 public:
84  inline NdNode(const PointContainer& points,
86  const Point& p = Point::Zero(),
87  unsigned int begin = 0,
88  unsigned int end = 0)
90 
95 
98  {
99  //_points = rhs._points; // Nodes must be working on the same container
100  _ids = rhs._ids;
101  _center = rhs._center;
102  _begin = rhs._begin;
103  _end = rhs._end;
104 
105  return *this;
106  }
107 
108  inline ~NdNode(){}
109 
110  //! \brief Length of the range covered by this node in the id array
111  inline int rangeLength() const { return int(_end) - int(_begin); }
112  //! \brief First position in the id array defining the current instance range
113  inline unsigned int rangeBegin() const { return _begin; }
114  //! \brief Last position in the id array defining the current instance range
115  inline unsigned int rangeEnd() const { return _end; }
116  //! \brief Access to the i-eme point in the node. Range limits are NOT tested!
117  inline const Point& pointInRange(unsigned int i) const
118  { return _points[_ids[i+_begin]]; }
119  //! \brief Access to the i-eme point in the node. Range limits are NOT tested!
120  inline unsigned int idInRange(unsigned int i) const
121  { return _ids[i+_begin]; }
122 
123  //! \brief Center of the current node
124  inline const Point& center() const { return _center; }
125 
126  //! Split the node and compute child nodes \note Childs are not stored
127  //! \todo See how to introduce dimension specialization (useful for 2D and 3D)
128  void
129  split(
132 
133  inline static
136  IdContainer& ids)
137  {
139  points, ids, Point::Ones() / 2., 0, ids.size());
140  }
141 
142  private:
143  inline unsigned int _split(int start, int end,
144  unsigned int dim,
146 };
147 
148 
149 template <class Point,
150  int _dim,
151  typename Scalar,
152  class _PointContainer,
153  class _IdContainer>
154 unsigned int
156  int start,
157  int end,
158  unsigned int dim,
160 {
161  int l(start), r(end-1);
162  for ( ; l<r ; ++l, --r)
163  {
164  while (l < end && _points[_ids[l]][dim] < splitValue)
165  l++;
166  while (r >= start && _points[_ids[r]][dim] >= splitValue)
167  r--;
168  if (l > r)
169  break;
170  std::swap(_ids[l],_ids[r]);
171  }
172  if(l>=end) return end;
173  return _points[_ids[l]][dim] < splitValue ? l+1 : l;
174 }
175 
176 /*!
177  \brief Split the current node in 2^Dim childs using a regular grid.
178  The IdContainer is updated to partially sort the input ids wrt to the childs
179  range limits.
180 
181  \param ChildContainer in:
182  */
183 template <class Point,
184  int _dim,
185  typename Scalar,
186  class _PointContainer,
187  class _IdContainer>
188 void
192 {
194 
195  //! Compute number of childs at compile time
196  const int nbNode = Utils::POW(int(2),int(Dim));
197  const int offset = childs.size();
198 
199  // init all potential nodes using the root values
200  childs.resize(offset+nbNode, *this);
201 
202  /// Split successively along all the dimensions of the ambiant space
203  /// This algorithm cannot be parallelized
204  for(unsigned int d = 0; d < Dim; d++){
205  const unsigned int nbInterval = Utils::POW(int(2),int(d+1)); // can be deduced at
206  const unsigned int nbSplit = nbInterval/2; // compile time with
207  const unsigned int intervalNode = nbNode / nbSplit; // loop unrollement
208  const unsigned int midNode = nbNode / nbInterval;
209 
210  /// Iterate over all splits and compute them for the current dimension
211  for(unsigned int s = 0; s != nbSplit; s++) {
212  const unsigned int beginNodeId = s * intervalNode + offset;
213  const unsigned int endNodeId = (s+1) * intervalNode + offset;
214 
216 
217  const unsigned int splitId = _split(childs[beginNodeId]._begin,
218  childs[endNodeId-1]._end,
219  d,
223 
224  /// Transmit the split to the related nodes
225  for (unsigned int i = beginNodeId; i != beginNodeId + midNode; i++){
227  childs[i]._end = splitId;
228  }
229 
230  for (unsigned int i = beginNodeId + midNode; i != endNodeId; i++){
232  childs[i]._begin = splitId;
233  }
234  }
235  }
236 
237  // Remove childs not containing any element
238  if (!childs.empty()) {
239  childs.erase(std::remove_if(childs.begin(), childs.end(), [](const Node& c)
240  { return c.rangeLength() == 0; }), childs.end());
241  }
242 }
243 
244 } // namespace gr
245 
246 #endif
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