Point Cloud Library (PCL)  1.7.0
/tmp/buildd/pcl-1.7-1.7.0/features/include/pcl/features/spin_image.h
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *  Copyright (c) 2012-, Open Perception, Inc.
00007  *
00008  *  All rights reserved.
00009  *
00010  *  Redistribution and use in source and binary forms, with or without
00011  *  modification, are permitted provided that the following conditions
00012  *  are met:
00013  *
00014  *   * Redistributions of source code must retain the above copyright
00015  *     notice, this list of conditions and the following disclaimer.
00016  *   * Redistributions in binary form must reproduce the above
00017  *     copyright notice, this list of conditions and the following
00018  *     disclaimer in the documentation and/or other materials provided
00019  *     with the distribution.
00020  *   * Neither the name of the copyright holder(s) nor the names of its
00021  *     contributors may be used to endorse or promote products derived
00022  *     from this software without specific prior written permission.
00023  *
00024  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00025  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00026  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00027  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00028  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00029  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00030  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00031  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00032  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00033  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00034  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00035  *  POSSIBILITY OF SUCH DAMAGE.
00036  *
00037  * $Id$
00038  */
00039 
00040 #ifndef PCL_SPIN_IMAGE_H_
00041 #define PCL_SPIN_IMAGE_H_
00042 
00043 #include <pcl/point_types.h>
00044 #include <pcl/features/feature.h>
00045 
00046 namespace pcl
00047 {
00048   /** \brief Estimates spin-image descriptors in the  given input points. 
00049     *  
00050     * This class represents spin image descriptor. Spin image is
00051     * a histogram of point locations summed along the bins of the image.
00052     * A 2D accumulator indexed by <VAR>a</VAR> and <VAR>b</VAR> is created. Next, 
00053     * the coordinates (<VAR>a</VAR>, <VAR>b</VAR>) are computed for a vertex in 
00054     * the surface mesh that is within the support of the spin image 
00055     * (explained below). The bin indexed by (<VAR>a</VAR>, <VAR>b</VAR>) in 
00056     * the accumulator is then incremented; bilinear interpolation is used 
00057     * to smooth the contribution of the vertex. This procedure is repeated 
00058     * for all vertices within the support of the spin image. 
00059     * The resulting accumulator can be thought of as an image; 
00060     * dark areas in the image correspond to bins that contain many projected points. 
00061     * As long as the size of the bins in the accumulator is greater 
00062     * than the median distance between vertices in the mesh 
00063     * (the definition of mesh resolution), the position of individual 
00064     * vertices will be averaged out during spin image generation.
00065     *
00066     * \attention The input normals given by \ref setInputNormals have to match
00067     * the input point cloud given by \ref setInputCloud. This behavior is
00068     * different than feature estimation methods that extend \ref
00069     * FeatureFromNormals, which match the normals with the search surface.
00070     *
00071     * With the default paramters, pcl::Histogram<153> is a good choice for PointOutT.
00072     * Of course the dimension of this descriptor must change to match the number
00073     * of bins set by the parameters.
00074     *
00075     * For further information please see:
00076     *
00077     *  - Johnson, A. E., & Hebert, M. (1998). Surface Matching for Object
00078     *    Recognition in Complex 3D Scenes. Image and Vision Computing, 16,
00079     *    635-651.
00080     * 
00081     * The class also implements radial spin images and spin-images in angular domain 
00082     * (or both).
00083     * 
00084     * \author Roman Shapovalov, Alexander Velizhev
00085     * \ingroup features
00086     */
00087   template <typename PointInT, typename PointNT, typename PointOutT>
00088   class SpinImageEstimation : public Feature<PointInT, PointOutT>
00089   {
00090     public:
00091       typedef boost::shared_ptr<SpinImageEstimation<PointInT, PointNT, PointOutT> > Ptr;
00092       typedef boost::shared_ptr<const SpinImageEstimation<PointInT, PointNT, PointOutT> > ConstPtr;
00093       using Feature<PointInT, PointOutT>::feature_name_;
00094       using Feature<PointInT, PointOutT>::getClassName;
00095       using Feature<PointInT, PointOutT>::indices_;
00096       using Feature<PointInT, PointOutT>::search_radius_;
00097       using Feature<PointInT, PointOutT>::k_;
00098       using Feature<PointInT, PointOutT>::surface_;
00099       using Feature<PointInT, PointOutT>::fake_surface_;
00100       using PCLBase<PointInT>::input_;
00101 
00102       typedef typename Feature<PointInT, PointOutT>::PointCloudOut PointCloudOut;
00103 
00104       typedef typename pcl::PointCloud<PointNT> PointCloudN;
00105       typedef typename PointCloudN::Ptr PointCloudNPtr;
00106       typedef typename PointCloudN::ConstPtr PointCloudNConstPtr;
00107 
00108       typedef typename pcl::PointCloud<PointInT> PointCloudIn;
00109       typedef typename PointCloudIn::Ptr PointCloudInPtr;
00110       typedef typename PointCloudIn::ConstPtr PointCloudInConstPtr;
00111       
00112       /** \brief Constructs empty spin image estimator.
00113         * 
00114         * \param[in] image_width spin-image resolution, number of bins along one dimension
00115         * \param[in] support_angle_cos minimal allowed cosine of the angle between 
00116         *   the normals of input point and search surface point for the point 
00117         *   to be retained in the support
00118         * \param[in] min_pts_neighb min number of points in the support to correctly estimate 
00119         *   spin-image. If at some point the support contains less points, exception is thrown
00120         */
00121       SpinImageEstimation (unsigned int image_width = 8,
00122                            double support_angle_cos = 0.0,   // when 0, this is bogus, so not applied
00123                            unsigned int min_pts_neighb = 0);
00124       
00125       /** \brief Empty destructor */
00126       virtual ~SpinImageEstimation () {}
00127 
00128       /** \brief Sets spin-image resolution.
00129         * 
00130         * \param[in] bin_count spin-image resolution, number of bins along one dimension
00131         */
00132       void 
00133       setImageWidth (unsigned int bin_count)
00134       {
00135         image_width_ = bin_count;
00136       }
00137 
00138       /** \brief Sets the maximum angle for the point normal to get to support region.
00139         * 
00140         * \param[in] support_angle_cos minimal allowed cosine of the angle between 
00141         *   the normals of input point and search surface point for the point 
00142         *   to be retained in the support
00143         */
00144       void 
00145       setSupportAngle (double support_angle_cos)
00146       {
00147         if (0.0 > support_angle_cos || support_angle_cos > 1.0)  // may be permit negative cosine?
00148         {
00149           throw PCLException ("Cosine of support angle should be between 0 and 1",
00150             "spin_image.h", "setSupportAngle");
00151         }
00152 
00153         support_angle_cos_ = support_angle_cos;
00154       }
00155 
00156       /** \brief Sets minimal points count for spin image computation.
00157         *
00158         * \param[in] min_pts_neighb min number of points in the support to correctly estimate 
00159         *   spin-image. If at some point the support contains less points, exception is thrown
00160         */
00161       void 
00162       setMinPointCountInNeighbourhood (unsigned int min_pts_neighb)
00163       {
00164         min_pts_neighb_ = min_pts_neighb;
00165       }
00166 
00167       /** \brief Provide a pointer to the input dataset that contains the point normals of 
00168         * the input XYZ dataset given by \ref setInputCloud
00169         * 
00170         * \attention The input normals given by \ref setInputNormals have to match
00171         * the input point cloud given by \ref setInputCloud. This behavior is
00172         * different than feature estimation methods that extend \ref
00173         * FeatureFromNormals, which match the normals with the search surface.
00174         * \param[in] normals the const boost shared pointer to a PointCloud of normals. 
00175         * By convention, L2 norm of each normal should be 1. 
00176         */
00177       inline void 
00178       setInputNormals (const PointCloudNConstPtr &normals)
00179       { 
00180         input_normals_ = normals; 
00181       }
00182 
00183       /** \brief Sets single vector a rotation axis for all input points.
00184         * 
00185         * It could be useful e.g. when the vertical axis is known.
00186         * \param[in] axis unit-length vector that serves as rotation axis for reference frame
00187         */
00188       void 
00189       setRotationAxis (const PointNT& axis)
00190       {
00191         rotation_axis_ = axis;
00192         use_custom_axis_ = true;
00193         use_custom_axes_cloud_ = false;
00194       }
00195 
00196       /** \brief Sets array of vectors as rotation axes for input points.
00197         * 
00198         * Useful e.g. when one wants to use tangents instead of normals as rotation axes
00199         * \param[in] axes unit-length vectors that serves as rotation axes for 
00200         *   the corresponding input points' reference frames
00201         */
00202       void 
00203       setInputRotationAxes (const PointCloudNConstPtr& axes)
00204       {
00205         rotation_axes_cloud_ = axes;
00206 
00207         use_custom_axes_cloud_ = true;
00208         use_custom_axis_ = false;
00209       }
00210 
00211       /** \brief Sets input normals as rotation axes (default setting). */
00212       void 
00213       useNormalsAsRotationAxis () 
00214       { 
00215         use_custom_axis_ = false; 
00216         use_custom_axes_cloud_ = false;
00217       }
00218 
00219       /** \brief Sets/unsets flag for angular spin-image domain.
00220         * 
00221         * Angular spin-image differs from the vanilla one in the way that not 
00222         * the points are collected in the bins but the angles between their
00223         * normals and the normal to the reference point. For further
00224         * information please see 
00225         * Endres, F., Plagemann, C., Stachniss, C., & Burgard, W. (2009). 
00226         * Unsupervised Discovery of Object Classes from Range Data using Latent Dirichlet Allocation. 
00227         * In Robotics: Science and Systems. Seattle, USA.
00228         * \param[in] is_angular true for angular domain, false for point domain
00229         */
00230       void 
00231       setAngularDomain (bool is_angular = true) { is_angular_ = is_angular; }
00232 
00233       /** \brief Sets/unsets flag for radial spin-image structure.
00234         * 
00235         * Instead of rectangular coordinate system for reference frame 
00236         * polar coordinates are used. Binning is done depending on the distance and 
00237         * inclination angle from the reference point
00238         * \param[in] is_radial true for radial spin-image structure, false for rectangular
00239         */
00240       void 
00241       setRadialStructure (bool is_radial = true) { is_radial_ = is_radial; }
00242 
00243     protected:
00244       /** \brief Estimate the Spin Image descriptors at a set of points given by
00245         * setInputWithNormals() using the surface in setSearchSurfaceWithNormals() and the spatial locator 
00246         * \param[out] output the resultant point cloud that contains the Spin Image feature estimates
00247         */
00248       virtual void 
00249       computeFeature (PointCloudOut &output); 
00250 
00251       /** \brief initializes computations specific to spin-image.
00252         * 
00253         * \return true iff input data and initialization are correct
00254         */
00255       virtual bool
00256       initCompute ();
00257 
00258       /** \brief Computes a spin-image for the point of the scan. 
00259         * \param[in] index the index of the reference point in the input cloud
00260         * \return estimated spin-image (or its variant) as a matrix
00261         */
00262       Eigen::ArrayXXd 
00263       computeSiForPoint (int index) const;
00264 
00265     private:
00266       PointCloudNConstPtr input_normals_;
00267       PointCloudNConstPtr rotation_axes_cloud_;
00268       
00269       bool is_angular_;
00270 
00271       PointNT rotation_axis_;
00272       bool use_custom_axis_;
00273       bool use_custom_axes_cloud_;
00274 
00275       bool is_radial_;
00276 
00277       unsigned int image_width_;
00278       double support_angle_cos_;
00279       unsigned int min_pts_neighb_;
00280   };
00281 }
00282 
00283 #ifdef PCL_NO_PRECOMPILE
00284 #include <pcl/features/impl/spin_image.hpp>
00285 #endif
00286 
00287 #endif  //#ifndef PCL_SPIN_IMAGE_H_
00288