Super4PCS Library  V1.1.2(719f5c0)
normalset.hpp
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_INDEXED_NORMAL_SET_HPP_
49 #define _SUPER4PCS_ACCELERATORS_INDEXED_NORMAL_SET_HPP_
50 
51 #include <math.h>
52 #include <set>
53 #include <Eigen/Geometry>
54 
55 namespace GlobalRegistration{
56 
57 template <class Point, int dim, int _ngSize, typename Scalar>
58 constexpr Scalar
59 IndexedNormalSet<Point, dim, _ngSize, Scalar>::_nepsilon;
60 
61 template <class Point, int dim, int _ngSize, typename Scalar>
63  for(unsigned int i = 0; i != _grid.size(); i++)
64  delete(_grid[i]);
65 }
66 
71 template <class Point, int dim, int _ngSize, typename Scalar>
72 int
74  const Point& p) const
75 {
76  // Unroll the loop over the different dimensions at compile time
77  return Utils::UnrollIndexLoop<VALIDATE_INDICES>( coordinatesPos(p), dim-1, _egSize );
78 }
79 
84 template <class Point, int dim, int _ngSize, typename Scalar>
85 int
87  const Point& n) const
88 {
89  // Unroll the loop over the different dimension at compile time
90  return Utils::UnrollIndexLoop<VALIDATE_INDICES>( coordinatesNormal(n), dim-1, _ngSize);
91 }
92 
93 
94 template <class Point, int dim, int _ngSize, typename Scalar>
95 int
97  const Point& pCoord) const
98 {
99  // Unroll the loop over the different dimensions at compile time
100  return Utils::UnrollIndexLoop<VALIDATE_INDICES>( pCoord, dim-1, _egSize );
101 }
102 
103 
104 template <class Point, int dim, int _ngSize, typename Scalar>
105 int
107  const Point& nCoord) const
108 {
109  // Unroll the loop over the different dimension at compile time
110  return Utils::UnrollIndexLoop<VALIDATE_INDICES>( nCoord, dim-1, _ngSize);
111 }
112 
113 
114 template <class Point, int dim, int _ngSize, typename Scalar>
115 bool
117  const Point& p,
118  const Point& n,
119  unsigned int id)
120 {
121  const int pId = indexPos(p);
122  if (pId == -1) return false;
123 
124  const int nId = indexNormal(n);
125  if (nId == -1) return false;
126 
127  if (_grid[pId] == NULL) _grid[pId] = new AngularGrid;
128  (_grid[pId])->at(nId).push_back(id);
129 
130  return true;
131 }
132 
133 
134 template <class Point, int dim, int _ngSize, typename Scalar>
135 void
137  const Point& p,
138  std::vector<unsigned int>&nei)
139 {
140  AngularGrid* grid = angularGrid(p);
141  if ( grid == NULL ) return;
142 
143  for(typename AngularGrid::const_iterator it = grid->cbegin();
144  it != grid->cend(); it++){
145  const std::vector<unsigned int>& lnei = *it;
146  nei.insert( nei.end(), lnei.begin(), lnei.end() );
147  }
148 }
149 
150 
151 template <class Point, int dim, int _ngSize, typename Scalar>
152 void
154  const Point& p,
155  const Point& n,
156  std::vector<unsigned int>&nei)
157 {
158  AngularGrid* grid = angularGrid(p);
159  if ( grid == NULL ) return;
160 
161  const std::vector<unsigned int>& lnei = grid->at(indexNormal(n));
162  nei.insert( nei.end(), lnei.begin(), lnei.end() );
163 }
164 
165 
166 template <class Point, int dim, int _ngSize, typename Scalar>
167 void
169  const Point& p,
170  const Point& n,
171  Scalar cosAlpha,
172  std::vector<unsigned int>&nei,
173  bool tryReverse)
174 {
175  AngularGrid* grid = angularGrid(p);
176  if ( grid == NULL ) return;
177 
178  const Scalar alpha = std::acos(cosAlpha);
179  const Scalar perimeter = Scalar(2) * M_PI * std::atan(alpha);
180  const unsigned int nbSample = 2*std::ceil(perimeter*Scalar(_ngSize) /Scalar(2.));
181  const Scalar angleStep = Scalar(2) * M_PI / Scalar(nbSample);
182 
183  const Scalar sinAlpha = std::sin(alpha);
184 
185  Eigen::Quaternion<Scalar> q;
186  q.setFromTwoVectors(Point(0.,0.,1.), n);
187 
188  std::set<unsigned int> colored;
189 
190  // Do the rendering independently of the content
191  for(unsigned int a = 0; a != nbSample; a++){
192  Scalar theta = Scalar(a) * angleStep;
193  const Point dir = ( q * Point(sinAlpha*std::cos(theta),
194  sinAlpha*std::sin(theta),
195  cosAlpha ) ).normalized();
196  int id = indexNormal( dir );
197  if(grid->at(id).size() != 0){
198  colored.insert(id);
199  }
200 
201  if (tryReverse){
202  id = indexNormal( -dir );
203  if(grid->at(id).size() != 0){
204  colored.insert(id);
205  }
206  }
207  }
208 
209  for( std::set<unsigned int>::const_iterator it = colored.cbegin();
210  it != colored.cend(); it++){
211  const std::vector<unsigned int>& lnei = grid->at(*it);
212  nei.insert( nei.end(), lnei.begin(), lnei.end() );
213  }
214 }
215 
216 } // namespace Super4CS
217 
218 
219 #endif // _INDEXED_NORMAL_SET_HPP_
220 
Normal set indexed by a position in euclidean space.
Definition: normalset.h:71
virtual ~IndexedNormalSet()
Definition: normalset.hpp:62
bool addElement(const Point &pos, const Point &normal, unsigned int id)
Add a new couple pos/normal, and its associated id.
Definition: normalset.hpp:116
Definition: bbox.h:54
std::array< std::vector< unsigned int >, Utils::POW(_ngSize, dim)> AngularGrid
Definition: normalset.h:73
_Scalar Scalar
Definition: normalset.h:76
void getNeighbors(const Point &p, std::vector< unsigned int > &nei)
Get closest points in euclidean space.
Definition: normalset.hpp:136