utils.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_UTILS_H_
49 #define _OPENGR_ACCELERATORS_UTILS_H_
50 
51 #include <string>
52 #include <stdexcept> //out_of_range
53 #include <cmath> //floor
54 #include <array>
55 
56 #ifndef M_PI
57 #define M_PI 3.14159265358979323846
58 #endif
59 
60 
61 namespace gr{
62 namespace Utils{
63 
64 //! \brief Compile time pow
65 template<typename baseT, typename expoT>
66 constexpr baseT POW(baseT base, expoT expo)
67 {
68  return (expo != 0 )? base * POW(base, expo -1) : 1;
69 }
70 
71 
72 #ifndef PARSED_BY_DOXYGEN
73 namespace internal{
74 
75 /*!
76  * \brief Helper structure used to (conditionnaly) validate indices.
77  * The template parameter enable allows to control the validation, without
78  * overload when the validation is disabled.
79  *
80  * Throw std::out_of_range exception when the validation is enabled and an
81  * invalid case is detected
82  */
83 template <bool enable>
84 struct IndexValidator{
85  /*!
86  * \brief Check if n is within [0:gsize] if enable=true
87  * \throw std::out_of_range
88  */
89  template <class IndexT, class SizeT>
90  static inline
91  constexpr IndexT validate(const IndexT& n,
92  const SizeT& gsize);
93 
94  /*!
95  * \brief Test used internally to validate the input index
96  */
97  template <class IndexT, class SizeT>
98  static inline
99  constexpr bool _test(const IndexT& n, const SizeT& gsize){
100  return n < gsize;
101  }
102 };
103 
104 template <>
105 template <class IndexT, class SizeT>
106 constexpr IndexT
107 IndexValidator<true>::validate(const IndexT& n,
108  const SizeT& gsize)
109 {
110  return IndexValidator<true>::_test(n, gsize) ?
111  n :
112  throw std::out_of_range(
113  std::string("[IndexValidator] ") +
114  std::to_string(n) +
115  std::string(" bigger than ") +
116  std::to_string(gsize) );
117 }
118 
119 template <>
120 template <class IndexT, class SizeT>
121 constexpr IndexT
122 IndexValidator<false>::validate(const IndexT& n,
123  const SizeT& /*gsize*/)
124 {
125  return n;
126 }
127 } // namespace gr::Utils::internal
128 #endif
129 
130 /*!
131  * \brief Convert a normalized n-d vector to a linear index in a uniform regular grid
132  * This function is recursive, and unrolled at compile time (loop over n).
133  *
134  * \param coord Input coordinates defined in the normalized n-hypercube.
135  * \param cdim Working dimension, must be called with n.
136  * \param gsize Dimension of the grid, must be consistent in all dimensions
137  *
138  * \tparam validate Enable or disable the range validation
139  * \tparam PointT Type of the input points (deduced)
140  * \tparam IndexT Index type (deduced)
141  * \tparam IndexT Size type (deduced)
142  *
143  * \see internal::IndexValidator for the validation procedure
144  */
145 template<bool validate, class ndIndexT, class IndexT, class SizeT>
146 constexpr inline IndexT
148  IndexT cdim,
149  SizeT gsize){
150  return (cdim != 0)
154 }
155 
156 
157 /*!
158  * \brief Convert a normalized n-d vector to a linear index in a uniform regular
159  * grid, moved by moved by an offset defined as a integer move in the n-d grid.
160  * This function is recursive, and unrolled at compile time (loop over n). In
161  * addition, it allows to offset the input coordinates.
162  *
163  * \param coord Input coordinates defined in the normalized n-hypercube.
164  * \param cdim Working dimension, must be called with n.
165  * \param gsize Dimension of the grid, must be consistent in all dimensions
166  *
167  * \see UnrollIndexLoop<class PointT>
168  */
169 template<bool validate, class ndIndexT, class IndexT, class SizeT>
170 constexpr inline IndexT
172  const ndIndexT& offset,
173  IndexT cdim,
174  SizeT gsize){
175  return (cdim != 0)
179 }
180 
181 
182 /// Compute the 3^dim neighborhood for a cell
183 /// \TODO This implementation is not efficient and must be improved
184 /// e.g., do no allocate any array, just call a function with the ids.
186  /// helper class
187  template <int dim>
189  using type = std::array<int, Utils::POW(3, dim) >;
190  using ptr = int*;
191  };
192 
193  /// \param queryId Linear index of the query
194  /// \param nbElementPerDim Number of cells in the grid per dimension
195  /// Total size of the grid is `pow(nbElementPerDim, dim)`.
196  /// \return An array of the neighboring cells ids. When the query is
197  /// on the grid boundaries, out of bounds cells ids are marked
198  /// with -1 in the output array.
199  template <int dim>
200  inline void get(
201  int queryId,
202  int nElPerDim,
203  typename NeighborhoodType<dim>::type& nei) {
204  get<dim> ( queryId, nElPerDim, 0, nei.data(), nei.data()+nei.size() );
205  }
206 
207 private:
208  template <int dim>
209  inline void get(
210  int /*queryId*/,
211  int /*nElPerDim*/,
212  int /*offset*/,
213  typename NeighborhoodType<dim>::ptr first,
214  typename NeighborhoodType<dim>::ptr last) {
215  std::fill(first, last, -1);
216  }
217 };
218 
219 
220 template<>
221 inline void
223  int queryId,
224  int nElPerDim,
225  int offset,
226  typename NeighborhoodType<1>::ptr first,
227  typename NeighborhoodType<1>::ptr last)
228 {
229  if ( queryId < 0 || queryId >= nElPerDim ) {
230  std::fill(first, last, -1);
231  } else {
232  *first++ = (queryId > 0) ? queryId-1 : -1;
233  *first++ = queryId;
234  *first++ = (queryId < nElPerDim-1) ? queryId+1 : -1;
235  }
236 }
237 template<>
238 inline void
240  int queryId,
241  int nElPerDim,
242  int offset,
243  typename NeighborhoodType<2>::ptr first,
244  typename NeighborhoodType<2>::ptr last)
245 {
246  int offQueryId = queryId - offset;
248  std::fill(first, last, -1);
249  } else {
251 
252  // previous row
253  if ( d.quot == 0 ) {
254  std::fill(first, first + 3, -1); first+=3;
255  }
256  else {
257  *first++ = (d.rem > 0) ? queryId-1-nElPerDim : -1;
258  *first++ = queryId - nElPerDim;
259  *first++ = (d.rem < nElPerDim-1) ? queryId+1-nElPerDim : -1;
260  }
261 
262  // current row
263  *first++ = (d.rem > 0) ? queryId-1: -1;
264  *first++ = queryId;
265  *first++ = (d.rem < nElPerDim-1) ? queryId+1 : -1;
266 
267  if ( d.quot+1 >= nElPerDim ) {
268  std::fill(first, first + 3, -1); first+=3;
269  }
270  else {
271  *first++ = (d.rem > 0) ? queryId-1+nElPerDim : -1;
272  *first++ = queryId + nElPerDim;
273  *first++ = (d.rem < nElPerDim-1) ? queryId+1+nElPerDim : -1;
274  }
275  }
276 }
277 template<>
278 inline void
280  int queryId,
281  int nElPerDim,
282  int /*offset*/,
283  typename NeighborhoodType<3>::ptr first,
284  typename NeighborhoodType<3>::ptr /*last*/)
285 {
287  int neiSliceSize = 9;
288  std::div_t d = std::div( queryId, sliceSize );
292 }
293 
294 
295 } //namespace gr::Utils
296 } //namespace gr
297 
298 
299 #endif
#define M_PI
Definition: utils.h:57
constexpr baseT POW(baseT base, expoT expo)
Compile time pow.
Definition: utils.h:66
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
void get(int queryId, int nElPerDim, int, typename NeighborhoodType< 3 >::ptr first, typename NeighborhoodType< 3 >::ptr)
Definition: utils.h:279