Point Cloud Library (PCL)  1.14.0-dev
spin_image.h
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2011, Willow Garage, Inc.
6  * Copyright (c) 2012-, Open Perception, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id$
38  */
39 
40 #pragma once
41 
42 #include <pcl/point_types.h>
43 #include <pcl/features/feature.h>
44 
45 namespace pcl
46 {
47  /** \brief Estimates spin-image descriptors in the given input points.
48  *
49  * This class represents spin image descriptor. Spin image is
50  * a histogram of point locations summed along the bins of the image.
51  * A 2D accumulator indexed by <VAR>a</VAR> and <VAR>b</VAR> is created. Next,
52  * the coordinates (<VAR>a</VAR>, <VAR>b</VAR>) are computed for a vertex in
53  * the surface mesh that is within the support of the spin image
54  * (explained below). The bin indexed by (<VAR>a</VAR>, <VAR>b</VAR>) in
55  * the accumulator is then incremented; bilinear interpolation is used
56  * to smooth the contribution of the vertex. This procedure is repeated
57  * for all vertices within the support of the spin image.
58  * The resulting accumulator can be thought of as an image;
59  * dark areas in the image correspond to bins that contain many projected points.
60  * As long as the size of the bins in the accumulator is greater
61  * than the median distance between vertices in the mesh
62  * (the definition of mesh resolution), the position of individual
63  * vertices will be averaged out during spin image generation.
64  *
65  * \attention The input normals given by \ref setInputNormals have to match
66  * the input point cloud given by \ref setInputCloud. This behavior is
67  * different than feature estimation methods that extend \ref
68  * FeatureFromNormals, which match the normals with the search surface.
69  *
70  * With the default parameters, pcl::Histogram<153> is a good choice for PointOutT.
71  * Of course the dimension of this descriptor must change to match the number
72  * of bins set by the parameters. If you use SpinImageEstimation with something
73  * other than pcl::Histogram<153>, you may need to put `#define PCL_NO_PRECOMPILE 1`
74  * before including `pcl/features/spin_image.h`.
75  *
76  * For further information please see:
77  *
78  * - Johnson, A. E., & Hebert, M. (1998). Surface Matching for Object
79  * Recognition in Complex 3D Scenes. Image and Vision Computing, 16,
80  * 635-651.
81  *
82  * The class also implements radial spin images and spin-images in angular domain
83  * (or both).
84  *
85  * \author Roman Shapovalov, Alexander Velizhev
86  * \ingroup features
87  */
88  template <typename PointInT, typename PointNT, typename PointOutT>
89  class SpinImageEstimation : public Feature<PointInT, PointOutT>
90  {
91  public:
92  using Ptr = shared_ptr<SpinImageEstimation<PointInT, PointNT, PointOutT> >;
93  using ConstPtr = shared_ptr<const SpinImageEstimation<PointInT, PointNT, PointOutT> >;
102 
104 
108 
112 
113  /** \brief Constructs empty spin image estimator.
114  *
115  * \param[in] image_width spin-image resolution, number of bins along one dimension
116  * \param[in] support_angle_cos minimal allowed cosine of the angle between
117  * the normals of input point and search surface point for the point
118  * to be retained in the support
119  * \param[in] min_pts_neighb min number of points in the support to correctly estimate
120  * spin-image. If at some point the support contains less points, exception is thrown
121  */
122  SpinImageEstimation (unsigned int image_width = 8,
123  double support_angle_cos = 0.0, // when 0, this is bogus, so not applied
124  unsigned int min_pts_neighb = 0);
125 
126  /** \brief Empty destructor */
127  ~SpinImageEstimation () override = default;
128 
129  /** \brief Sets spin-image resolution.
130  *
131  * \param[in] bin_count spin-image resolution, number of bins along one dimension
132  */
133  void
134  setImageWidth (unsigned int bin_count)
135  {
136  const unsigned int necessary_desc_size = (bin_count+1)*(2*bin_count+1);
137  if (necessary_desc_size > static_cast<unsigned int>(PointOutT::descriptorSize())) {
138  for(int i=0; ; ++i) { // Find the biggest possible image_width_
139  if(((i+1)*(2*i+1)) <= PointOutT::descriptorSize()) {
140  image_width_ = i;
141  } else {
142  break;
143  }
144  }
145  PCL_ERROR("[pcl::SpinImageEstimation] The chosen image width is too large, setting it to %u instead. "
146  "Consider using pcl::Histogram<%u> as output type of SpinImageEstimation "
147  "(possibly with `#define PCL_NO_PRECOMPILE 1`).\n", image_width_, ((bin_count+1)*(2*bin_count+1)));
148  } else if (necessary_desc_size < static_cast<unsigned int>(PointOutT::descriptorSize())) {
149  image_width_ = bin_count;
150  PCL_WARN("[pcl::SpinImageEstimation] The chosen image width is smaller than the output histogram allows. "
151  "This is not an error, but the last few histogram bins will not be set. "
152  "Consider using pcl::Histogram<%u> as output type of SpinImageEstimation "
153  "(possibly with `#define PCL_NO_PRECOMPILE 1`).\n", ((bin_count+1)*(2*bin_count+1)));
154  } else {
155  image_width_ = bin_count;
156  }
157  }
158 
159  /** \brief Sets the maximum angle for the point normal to get to support region.
160  *
161  * \param[in] support_angle_cos minimal allowed cosine of the angle between
162  * the normals of input point and search surface point for the point
163  * to be retained in the support
164  */
165  void
166  setSupportAngle (double support_angle_cos)
167  {
168  if (0.0 > support_angle_cos || support_angle_cos > 1.0) // may be permit negative cosine?
169  {
170  throw PCLException ("Cosine of support angle should be between 0 and 1",
171  "spin_image.h", "setSupportAngle");
172  }
173 
174  support_angle_cos_ = support_angle_cos;
175  }
176 
177  /** \brief Sets minimal points count for spin image computation.
178  *
179  * \param[in] min_pts_neighb min number of points in the support to correctly estimate
180  * spin-image. If at some point the support contains less points, exception is thrown
181  */
182  void
183  setMinPointCountInNeighbourhood (unsigned int min_pts_neighb)
184  {
185  min_pts_neighb_ = min_pts_neighb;
186  }
187 
188  /** \brief Provide a pointer to the input dataset that contains the point normals of
189  * the input XYZ dataset given by \ref setInputCloud
190  *
191  * \attention The input normals given by \ref setInputNormals have to match
192  * the input point cloud given by \ref setInputCloud. This behavior is
193  * different than feature estimation methods that extend \ref
194  * FeatureFromNormals, which match the normals with the search surface.
195  * \param[in] normals the const boost shared pointer to a PointCloud of normals.
196  * By convention, L2 norm of each normal should be 1.
197  */
198  inline void
200  {
201  input_normals_ = normals;
202  }
203 
204  /** \brief Sets single vector a rotation axis for all input points.
205  *
206  * It could be useful e.g. when the vertical axis is known.
207  * \param[in] axis unit-length vector that serves as rotation axis for reference frame
208  */
209  void
210  setRotationAxis (const PointNT& axis)
211  {
212  rotation_axis_ = axis;
213  use_custom_axis_ = true;
214  use_custom_axes_cloud_ = false;
215  }
216 
217  /** \brief Sets array of vectors as rotation axes for input points.
218  *
219  * Useful e.g. when one wants to use tangents instead of normals as rotation axes
220  * \param[in] axes unit-length vectors that serves as rotation axes for
221  * the corresponding input points' reference frames
222  */
223  void
225  {
226  rotation_axes_cloud_ = axes;
227 
228  use_custom_axes_cloud_ = true;
229  use_custom_axis_ = false;
230  }
231 
232  /** \brief Sets input normals as rotation axes (default setting). */
233  void
235  {
236  use_custom_axis_ = false;
237  use_custom_axes_cloud_ = false;
238  }
239 
240  /** \brief Sets/unsets flag for angular spin-image domain.
241  *
242  * Angular spin-image differs from the vanilla one in the way that not
243  * the points are collected in the bins but the angles between their
244  * normals and the normal to the reference point. For further
245  * information please see
246  * Endres, F., Plagemann, C., Stachniss, C., & Burgard, W. (2009).
247  * Unsupervised Discovery of Object Classes from Range Data using Latent Dirichlet Allocation.
248  * In Robotics: Science and Systems. Seattle, USA.
249  * \param[in] is_angular true for angular domain, false for point domain
250  */
251  void
252  setAngularDomain (bool is_angular = true) { is_angular_ = is_angular; }
253 
254  /** \brief Sets/unsets flag for radial spin-image structure.
255  *
256  * Instead of rectangular coordinate system for reference frame
257  * polar coordinates are used. Binning is done depending on the distance and
258  * inclination angle from the reference point
259  * \param[in] is_radial true for radial spin-image structure, false for rectangular
260  */
261  void
262  setRadialStructure (bool is_radial = true) { is_radial_ = is_radial; }
263 
264  protected:
265  /** \brief Estimate the Spin Image descriptors at a set of points given by
266  * setInputWithNormals() using the surface in setSearchSurfaceWithNormals() and the spatial locator
267  * \param[out] output the resultant point cloud that contains the Spin Image feature estimates
268  */
269  void
270  computeFeature (PointCloudOut &output) override;
271 
272  /** \brief initializes computations specific to spin-image.
273  *
274  * \return true iff input data and initialization are correct
275  */
276  bool
277  initCompute () override;
278 
279  /** \brief Computes a spin-image for the point of the scan.
280  * \param[in] index the index of the reference point in the input cloud
281  * \return estimated spin-image (or its variant) as a matrix
282  */
283  Eigen::ArrayXXd
284  computeSiForPoint (int index) const;
285 
286  private:
287  PointCloudNConstPtr input_normals_;
288  PointCloudNConstPtr rotation_axes_cloud_;
289 
290  bool is_angular_{false};
291 
292  PointNT rotation_axis_;
293  bool use_custom_axis_{false};
294  bool use_custom_axes_cloud_{false};
295 
296  bool is_radial_{false};
297 
298  unsigned int image_width_;
299  double support_angle_cos_;
300  unsigned int min_pts_neighb_;
301  };
302 }
303 
304 #ifdef PCL_NO_PRECOMPILE
305 #include <pcl/features/impl/spin_image.hpp>
306 #endif
Feature represents the base feature class.
Definition: feature.h:107
typename PointCloudIn::Ptr PointCloudInPtr
Definition: feature.h:121
shared_ptr< Feature< PointInT, PointOutT > > Ptr
Definition: feature.h:114
shared_ptr< const Feature< PointInT, PointOutT > > ConstPtr
Definition: feature.h:115
typename PointCloudIn::ConstPtr PointCloudInConstPtr
Definition: feature.h:122
PCL base class.
Definition: pcl_base.h:70
A base class for all pcl exceptions which inherits from std::runtime_error.
Definition: exceptions.h:66
shared_ptr< PointCloud< PointNT > > Ptr
Definition: point_cloud.h:413
shared_ptr< const PointCloud< PointNT > > ConstPtr
Definition: point_cloud.h:414
Estimates spin-image descriptors in the given input points.
Definition: spin_image.h:90
void setRotationAxis(const PointNT &axis)
Sets single vector a rotation axis for all input points.
Definition: spin_image.h:210
typename Feature< PointInT, PointOutT >::PointCloudOut PointCloudOut
Definition: spin_image.h:103
Eigen::ArrayXXd computeSiForPoint(int index) const
Computes a spin-image for the point of the scan.
Definition: spin_image.hpp:69
void useNormalsAsRotationAxis()
Sets input normals as rotation axes (default setting).
Definition: spin_image.h:234
void setRadialStructure(bool is_radial=true)
Sets/unsets flag for radial spin-image structure.
Definition: spin_image.h:262
void setAngularDomain(bool is_angular=true)
Sets/unsets flag for angular spin-image domain.
Definition: spin_image.h:252
~SpinImageEstimation() override=default
Empty destructor.
typename PointCloudN::Ptr PointCloudNPtr
Definition: spin_image.h:106
void setImageWidth(unsigned int bin_count)
Sets spin-image resolution.
Definition: spin_image.h:134
void setMinPointCountInNeighbourhood(unsigned int min_pts_neighb)
Sets minimal points count for spin image computation.
Definition: spin_image.h:183
void setInputNormals(const PointCloudNConstPtr &normals)
Provide a pointer to the input dataset that contains the point normals of the input XYZ dataset given...
Definition: spin_image.h:199
typename PointCloudN::ConstPtr PointCloudNConstPtr
Definition: spin_image.h:107
SpinImageEstimation(unsigned int image_width=8, double support_angle_cos=0.0, unsigned int min_pts_neighb=0)
Constructs empty spin image estimator.
Definition: spin_image.hpp:52
bool initCompute() override
initializes computations specific to spin-image.
Definition: spin_image.hpp:239
void setSupportAngle(double support_angle_cos)
Sets the maximum angle for the point normal to get to support region.
Definition: spin_image.h:166
void computeFeature(PointCloudOut &output) override
Estimate the Spin Image descriptors at a set of points given by setInputWithNormals() using the surfa...
Definition: spin_image.hpp:324
void setInputRotationAxes(const PointCloudNConstPtr &axes)
Sets array of vectors as rotation axes for input points.
Definition: spin_image.h:224
Defines all the PCL implemented PointT point type structures.