Super4PCS Library  V1.1.2(719f5c0)
intersectionFunctor.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_FUNCTOR_H_
49 #define _SUPER4PCS_ACCELERATORS_INTERSECTION_FUNCTOR_H_
50 
51 #include "super4pcs/accelerators/pairExtraction/intersectionNode.h"
52 #include <list>
53 #include <iostream>
54 
55 namespace GlobalRegistration{
56 namespace Accelerators{
57 namespace PairExtraction{
58 
59 template <typename Scalar>
60 static Scalar GetRoundedEpsilonValue(Scalar epsilon, int* lvl = nullptr) {
61  const int lvlMax = -std::log2(epsilon);
62 
63  if (lvl != nullptr) *lvl = lvlMax;
64 
65  // Refine epsilon by the closest conservative values
66  return 1.f/pow(2,lvlMax);
67 }
68 
70 
75 template <class _Primitive, class _Point, int _dim, typename _Scalar>
77  typedef _Point Point;
78  typedef _Primitive Primitive;
79  typedef _Scalar Scalar;
80  enum { dim = _dim };
81 
82  template <class PrimitiveContainer,
83  class PointContainer,
84  class ProcessingFunctor>
85  void
86  process(
87  const PrimitiveContainer& M,
88  const PointContainer & Q,
89  Scalar &epsilon,
90  unsigned int minNodeSize,
91  ProcessingFunctor& functor
92  );
93 
94 };
95 
96 
100 template <class Primitive, class Point, int dim, typename Scalar>
101 template <class PrimitiveContainer,
102  class PointContainer,
103  class ProcessingFunctor>
104 void
106  const PrimitiveContainer& M,
107  const PointContainer & Q,
108  Scalar &epsilon,
109  unsigned int minNodeSize,
110  ProcessingFunctor& functor
111  )
112 {
113  using std::pow;
114 
115  // types definitions
117  typedef typename std::vector<Node> NodeContainer;
118 
119  typedef typename Node::IdContainer IdContainer;
120  typedef typename std::pair<unsigned int, unsigned int> ResPair;
121  typedef typename std::vector<ResPair> ResContainer;
122 
123  // Global variables
124  const unsigned int nbPoint = Q.size();
125  int lvlMax = 0;
126  epsilon = GetRoundedEpsilonValue(epsilon, &lvlMax);
127 
128  int clvl = 0;
129 
130  // Use local array and manipulate references to avoid array copies
131  NodeContainer ping, pong;
132  NodeContainer* nodes = &ping;
133  NodeContainer* childNodes = &pong;
134 
136  std::vector< std::pair<Node, Scalar> > earlyNodes;
137 //
138 // // Fill the idContainer with identity values
139  if (functor.ids.size() != nbPoint){
140  std::cout << "[IntersectionFunctor] Init id array" << std::endl;
141  functor.ids.clear();
142  for(unsigned int i = 0; i < nbPoint; i++)
143  functor.ids.push_back(i);
144  }
145 
146 
147  // Buid root node in the child node, will be copied to the current nodes
148  childNodes->push_back(Node::buildUnitRootNode(Q, functor.ids));
149 
150  Scalar edgeLength = 0.f;
151  Scalar edgeHalfLength = 0.f;
152 
153  // First Loop
154  while (clvl != lvlMax-1){
155  // Stop if we not have any nodes to checks
156  if (childNodes->empty())
157  break;
158 
159  edgeLength = Scalar(1.f)/pow(2, clvl);
160  edgeHalfLength = edgeLength/Scalar(2.f);
161 
162  // swap pointers
163  std::swap(nodes, childNodes);
164  childNodes->clear();
165 
166 //#pragma omp parallel
167  for(typename NodeContainer::iterator nit = nodes->begin();
168  nit != nodes->end(); nit++){
169  Node &n = *nit;
170 
171  // Check if the current node intersect one of the primitives
172  // In this case, subdivide, store new nodes and stop the loop
173  for(typename PrimitiveContainer::const_iterator pit = M.begin();
174  pit != M.end(); pit++){
175 
176  if ((*pit).intersect(n.center(), edgeHalfLength+epsilon)){
177  // There is two options now: either there is already few points in the
178  // current node, in that case we stop splitting it, or we split.
179  if (n.rangeLength() > int(minNodeSize)){
180 //#pragma omp critical
181  n.split(*childNodes, edgeHalfLength);
182  }else{
183 //#pragma omp critical
184  earlyNodes.emplace_back(n, edgeHalfLength+epsilon);
185  }
186  break;
187  }
188  }
189  }
190  clvl++;
191  }
192 
193  // Second Loop
194  ResContainer results;
195  results.reserve(childNodes->size());
196 
197  unsigned int pId = 0;
198  for(typename PrimitiveContainer::const_iterator itP = M.begin();
199  itP != M.end(); itP++, pId++){
200  // add childs
201  for(typename NodeContainer::const_iterator itN = childNodes->begin();
202  itN != childNodes->end(); itN++){
203  if ((*itP).intersect((*itN).center(), epsilon*2.f)){
204 
205  functor.beginPrimitiveCollect(pId);
206  for(unsigned int j = 0; j!= (*itN).rangeLength(); j++){
207  if(pId>(*itN).idInRange(j))
208  if((*itP).intersectPoint((*itN).pointInRange(j),epsilon))
209  functor.process(pId, (*itN).idInRange(j));
210  }
211  functor.endPrimitiveCollect(pId);
212  }
213  }
214 
215  // add other leafs
216  for(typename std::vector< std::pair<Node, Scalar> >::const_iterator itPairs =
217  earlyNodes.begin();
218  itPairs != earlyNodes.end();
219  itPairs++){
220  if((*itP).intersect((*itPairs).first.center(), (*itPairs).second)){
221 
222  // Notice the functor we are collecting points for the current primitive
223  functor.beginPrimitiveCollect(pId);
224  for(unsigned int j = 0; j!= (*itPairs).first.rangeLength(); j++){
225  if(pId>(*itPairs).first.idInRange(j))
226  if((*itP).intersectPoint((*itPairs).first.pointInRange(j),epsilon))
227  functor.process(pId, (*itPairs).first.idInRange(j));
228 
229  }
230  functor.endPrimitiveCollect(pId);
231  }
232  }
233  }
234 }
235 
236 } // namespace PairExtraction
237 } // namespace Accelerators
238 } // namespace Super4PCS
239 
240 #endif
241 
Extract pairs of points by rasterizing primitives and collect points.
Definition: intersectionFunctor.h:76
Definition: bbox.h:54
void process(const PrimitiveContainer &M, const PointContainer &Q, Scalar &epsilon, unsigned int minNodeSize, ProcessingFunctor &functor)
< Process the extracted pairs
Definition: intersectionFunctor.h:105
Multidimensional node used for intersection query.
Definition: intersectionNode.h:72
_Primitive Primitive
Definition: intersectionFunctor.h:78