Point Cloud Library (PCL)  1.7.0
/tmp/buildd/pcl-1.7-1.7.0/registration/include/pcl/registration/lum.h
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2012, 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: lum.h 5663 2012-05-02 13:49:39Z florentinus $
00038  *
00039  */
00040 
00041 #ifndef PCL_REGISTRATION_LUM_H_
00042 #define PCL_REGISTRATION_LUM_H_
00043 
00044 #include <pcl/pcl_base.h>
00045 #include <pcl/registration/eigen.h>
00046 #include <pcl/registration/boost.h>
00047 #include <pcl/common/transforms.h>
00048 #include <pcl/correspondence.h>
00049 #include <pcl/registration/boost_graph.h>
00050 
00051 namespace Eigen
00052 {
00053   typedef Eigen::Matrix<float, 6, 1> Vector6f;
00054   typedef Eigen::Matrix<float, 6, 6> Matrix6f;
00055 }
00056 
00057 namespace pcl
00058 {
00059   namespace registration
00060   {
00061     /** \brief Globally Consistent Scan Matching based on an algorithm by Lu and Milios.
00062       * \details A GraphSLAM algorithm where registration data is managed in a graph:
00063       * <ul>
00064       *  <li>Vertices represent poses and hold the point cloud data and relative transformations.</li>
00065       *  <li>Edges represent pose constraints and hold the correspondence data between two point clouds.</li>
00066       * </ul>
00067       * Computation uses the first point cloud in the SLAM graph as a reference pose and attempts to align all other point clouds to it simultaneously.
00068       * For more information:
00069       * <ul><li>
00070       * F. Lu, E. Milios,
00071       * Globally Consistent Range Scan Alignment for Environment Mapping,
00072       * Autonomous Robots 4, April 1997
00073       * </li><li>
00074       * Dorit Borrmann, Jan Elseberg, Kai Lingemann, Andreas Nüchter, and Joachim Hertzberg,
00075       * The Efficient Extension of Globally Consistent Scan Matching to 6 DoF,
00076       * In Proceedings of the 4th International Symposium on 3D Data Processing, Visualization and Transmission (3DPVT '08), June 2008
00077       * </li></ul>
00078       * Usage example:
00079       * \code
00080       * pcl::registration::LUM<pcl::PointXYZ> lum;
00081       * // Add point clouds as vertices to the SLAM graph
00082       * lum.addPointCloud (cloud_0);
00083       * lum.addPointCloud (cloud_1);
00084       * lum.addPointCloud (cloud_2);
00085       * // Use your favorite pairwise correspondence estimation algorithm(s)
00086       * corrs_0_to_1 = someAlgo (cloud_0, cloud_1);
00087       * corrs_1_to_2 = someAlgo (cloud_1, cloud_2);
00088       * corrs_2_to_0 = someAlgo (lum.getPointCloud (2), lum.getPointCloud (0));
00089       * // Add the correspondence results as edges to the SLAM graph
00090       * lum.setCorrespondences (0, 1, corrs_0_to_1);
00091       * lum.setCorrespondences (1, 2, corrs_1_to_2);
00092       * lum.setCorrespondences (2, 0, corrs_2_to_0);
00093       * // Change the computation parameters
00094       * lum.setMaxIterations (5);
00095       * lum.setConvergenceThreshold (0.0);
00096       * // Perform the actual LUM computation
00097       * lum.compute ();
00098       * // Return the concatenated point cloud result
00099       * cloud_out = lum.getConcatenatedCloud ();
00100       * // Return the separate point cloud transformations
00101       * for(int i = 0; i < lum.getNumVertices (); i++)
00102       * {
00103       *   transforms_out[i] = lum.getTransformation (i);
00104       * }
00105       * \endcode
00106       * \author Frits Florentinus, Jochen Sprickerhof
00107       * \ingroup registration
00108       */
00109     template<typename PointT>
00110     class LUM
00111     {
00112       public:
00113         typedef boost::shared_ptr<LUM<PointT> > Ptr;
00114         typedef boost::shared_ptr<const LUM<PointT> > ConstPtr;
00115 
00116         typedef pcl::PointCloud<PointT> PointCloud;
00117         typedef typename PointCloud::Ptr PointCloudPtr;
00118         typedef typename PointCloud::ConstPtr PointCloudConstPtr;
00119 
00120         struct VertexProperties
00121         {
00122           PointCloudPtr cloud_;
00123           Eigen::Vector6f pose_;
00124           EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00125         };
00126         struct EdgeProperties
00127         {
00128           pcl::CorrespondencesPtr corrs_;
00129           Eigen::Matrix6f cinv_;
00130           Eigen::Vector6f cinvd_;
00131           EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00132         };
00133 
00134         typedef boost::adjacency_list<boost::eigen_vecS, boost::eigen_vecS, boost::bidirectionalS, VertexProperties, EdgeProperties, boost::no_property, boost::eigen_listS> SLAMGraph;
00135         typedef boost::shared_ptr<SLAMGraph> SLAMGraphPtr;
00136         typedef typename SLAMGraph::vertex_descriptor Vertex;
00137         typedef typename SLAMGraph::edge_descriptor Edge;
00138 
00139         /** \brief Empty constructor.
00140           */
00141         LUM () 
00142           : slam_graph_ (new SLAMGraph)
00143           , max_iterations_ (5)
00144           , convergence_threshold_ (0.0)
00145         {
00146         }
00147 
00148         /** \brief Set the internal SLAM graph structure.
00149           * \details All data used and produced by LUM is stored in this boost::adjacency_list.
00150           * It is recommended to use the LUM class itself to build the graph.
00151           * This method could otherwise be useful for managing several SLAM graphs in one instance of LUM.
00152           * \param[in] slam_graph The new SLAM graph.
00153           */
00154         inline void
00155         setLoopGraph (const SLAMGraphPtr &slam_graph);
00156 
00157         /** \brief Get the internal SLAM graph structure.
00158           * \details All data used and produced by LUM is stored in this boost::adjacency_list.
00159           * It is recommended to use the LUM class itself to build the graph.
00160           * This method could otherwise be useful for managing several SLAM graphs in one instance of LUM.
00161           * \return The current SLAM graph.
00162           */
00163         inline SLAMGraphPtr
00164         getLoopGraph () const;
00165 
00166         /** \brief Get the number of vertices in the SLAM graph.
00167           * \return The current number of vertices in the SLAM graph.
00168           */
00169         typename SLAMGraph::vertices_size_type
00170         getNumVertices () const;
00171 
00172         /** \brief Set the maximum number of iterations for the compute() method.
00173           * \details The compute() method finishes when max_iterations are met or when the convergence criteria is met.
00174           * \param[in] max_iterations The new maximum number of iterations (default = 5).
00175           */
00176         void
00177         setMaxIterations (int max_iterations);
00178 
00179         /** \brief Get the maximum number of iterations for the compute() method.
00180           * \details The compute() method finishes when max_iterations are met or when the convergence criteria is met.
00181           * \return The current maximum number of iterations (default = 5).
00182           */
00183         inline int
00184         getMaxIterations () const;
00185 
00186         /** \brief Set the convergence threshold for the compute() method.
00187           * \details When the compute() method computes the new poses relative to the old poses, it will determine the length of the difference vector.
00188           * When the average length of all difference vectors becomes less than the convergence_threshold the convergence is assumed to be met.
00189           * \param[in] convergence_threshold The new convergence threshold (default = 0.0).
00190           */
00191         void
00192         setConvergenceThreshold (float convergence_threshold);
00193 
00194         /** \brief Get the convergence threshold for the compute() method.
00195           * \details When the compute() method computes the new poses relative to the old poses, it will determine the length of the difference vector.
00196           * When the average length of all difference vectors becomes less than the convergence_threshold the convergence is assumed to be met.
00197           * \return The current convergence threshold (default = 0.0).
00198           */
00199         inline float
00200         getConvergenceThreshold () const;
00201 
00202         /** \brief Add a new point cloud to the SLAM graph.
00203           * \details This method will add a new vertex to the SLAM graph and attach a point cloud to that vertex.
00204           * Optionally you can specify a pose estimate for this point cloud.
00205           * A vertex' pose is always relative to the first vertex in the SLAM graph, i.e. the first point cloud that was added.
00206           * Because this first vertex is the reference, you can not set a pose estimate for this vertex.
00207           * Providing pose estimates to the vertices in the SLAM graph will reduce overall computation time of LUM.
00208           * \note Vertex descriptors are typecastable to int.
00209           * \param[in] cloud The new point cloud.
00210           * \param[in] pose (optional) The pose estimate relative to the reference pose (first point cloud that was added).
00211           * \return The vertex descriptor of the newly created vertex.
00212           */
00213         Vertex
00214         addPointCloud (const PointCloudPtr &cloud, const Eigen::Vector6f &pose = Eigen::Vector6f::Zero ());
00215 
00216         /** \brief Change a point cloud on one of the SLAM graph's vertices.
00217           * \details This method will change the point cloud attached to an existing vertex and will not alter the SLAM graph structure.
00218           * Note that the correspondences attached to this vertex will not change and may need to be updated manually.
00219           * \note Vertex descriptors are typecastable to int.
00220           * \param[in] vertex The vertex descriptor of which to change the point cloud.
00221           * \param[in] cloud The new point cloud for that vertex.
00222           */
00223         inline void
00224         setPointCloud (const Vertex &vertex, const PointCloudPtr &cloud);
00225 
00226         /** \brief Return a point cloud from one of the SLAM graph's vertices.
00227           * \note Vertex descriptors are typecastable to int.
00228           * \param[in] vertex The vertex descriptor of which to return the point cloud.
00229           * \return The current point cloud for that vertex.
00230           */
00231         inline PointCloudPtr
00232         getPointCloud (const Vertex &vertex) const;
00233 
00234         /** \brief Change a pose estimate on one of the SLAM graph's vertices.
00235           * \details A vertex' pose is always relative to the first vertex in the SLAM graph, i.e. the first point cloud that was added.
00236           * Because this first vertex is the reference, you can not set a pose estimate for this vertex.
00237           * Providing pose estimates to the vertices in the SLAM graph will reduce overall computation time of LUM.
00238           * \note Vertex descriptors are typecastable to int.
00239           * \param[in] vertex The vertex descriptor of which to set the pose estimate.
00240           * \param[in] pose The new pose estimate for that vertex.
00241           */
00242         inline void
00243         setPose (const Vertex &vertex, const Eigen::Vector6f &pose);
00244 
00245         /** \brief Return a pose estimate from one of the SLAM graph's vertices.
00246           * \note Vertex descriptors are typecastable to int.
00247           * \param[in] vertex The vertex descriptor of which to return the pose estimate.
00248           * \return The current pose estimate of that vertex.
00249           */
00250         inline Eigen::Vector6f
00251         getPose (const Vertex &vertex) const;
00252 
00253         /** \brief Return a pose estimate from one of the SLAM graph's vertices as an affine transformation matrix.
00254           * \note Vertex descriptors are typecastable to int.
00255           * \param[in] vertex The vertex descriptor of which to return the transformation matrix.
00256           * \return The current transformation matrix of that vertex.
00257           */
00258         inline Eigen::Affine3f
00259         getTransformation (const Vertex &vertex) const;
00260 
00261         /** \brief Add/change a set of correspondences for one of the SLAM graph's edges.
00262           * \details The edges in the SLAM graph are directional and point from source vertex to target vertex.
00263           * The query indices of the correspondences, index the points at the source vertex' point cloud.
00264           * The matching indices of the correspondences, index the points at the target vertex' point cloud.
00265           * If no edge was present at the specified location, this method will add a new edge to the SLAM graph and attach the correspondences to that edge.
00266           * If the edge was already present, this method will overwrite the correspondence information of that edge and will not alter the SLAM graph structure.
00267           * \note Vertex descriptors are typecastable to int.
00268           * \param[in] source_vertex The vertex descriptor of the correspondences' source point cloud.
00269           * \param[in] target_vertex The vertex descriptor of the correspondences' target point cloud.
00270           * \param[in] corrs The new set of correspondences for that edge.
00271           */
00272         void
00273         setCorrespondences (const Vertex &source_vertex, 
00274                             const Vertex &target_vertex, 
00275                             const pcl::CorrespondencesPtr &corrs);
00276 
00277         /** \brief Return a set of correspondences from one of the SLAM graph's edges.
00278           * \note Vertex descriptors are typecastable to int.
00279           * \param[in] source_vertex The vertex descriptor of the correspondences' source point cloud.
00280           * \param[in] target_vertex The vertex descriptor of the correspondences' target point cloud.
00281           * \return The current set of correspondences of that edge.
00282           */
00283         inline pcl::CorrespondencesPtr
00284         getCorrespondences (const Vertex &source_vertex, const Vertex &target_vertex) const;
00285 
00286         /** \brief Perform LUM's globally consistent scan matching.
00287           * \details Computation uses the first point cloud in the SLAM graph as a reference pose and attempts to align all other point clouds to it simultaneously.
00288           * <br>
00289           * Things to keep in mind:
00290           * <ul>
00291           *  <li>Only those parts of the graph connected to the reference pose will properly align to it.</li>
00292           *  <li>All sets of correspondences should span the same space and need to be sufficient to determine a rigid transformation.</li>
00293           *  <li>The algorithm draws it strength from loops in the graph because it will distribute errors evenly amongst those loops.</li>
00294           * </ul>
00295           * Computation ends when either of the following conditions hold:
00296           * <ul>
00297           *  <li>The number of iterations reaches max_iterations. Use setMaxIterations() to change.</li>
00298           *  <li>The convergence criteria is met. Use setConvergenceThreshold() to change.</li>
00299           * </ul>
00300           * Computation will change the pose estimates for the vertices of the SLAM graph, not the point clouds attached to them.
00301           * The results can be retrieved with getPose(), getTransformation(), getTransformedCloud() or getConcatenatedCloud().
00302           */
00303         void
00304         compute ();
00305 
00306         /** \brief Return a point cloud from one of the SLAM graph's vertices compounded onto its current pose estimate.
00307           * \note Vertex descriptors are typecastable to int.
00308           * \param[in] vertex The vertex descriptor of which to return the transformed point cloud.
00309           * \return The transformed point cloud of that vertex.
00310           */
00311         PointCloudPtr
00312         getTransformedCloud (const Vertex &vertex) const;
00313 
00314         /** \brief Return a concatenated point cloud of all the SLAM graph's point clouds compounded onto their current pose estimates.
00315           * \return The concatenated transformed point clouds of the entire SLAM graph.
00316           */
00317         PointCloudPtr
00318         getConcatenatedCloud () const;
00319 
00320       protected:
00321         /** \brief Linearized computation of C^-1 and C^-1*D (results stored in slam_graph_). */
00322         void
00323         computeEdge (const Edge &e);
00324 
00325         /** \brief Returns a pose corrected 6DoF incidence matrix. */
00326         inline Eigen::Matrix6f
00327         incidenceCorrection (const Eigen::Vector6f &pose);
00328 
00329       private:
00330         /** \brief The internal SLAM graph structure. */
00331         SLAMGraphPtr slam_graph_;
00332 
00333         /** \brief The maximum number of iterations for the compute() method. */
00334         int max_iterations_;
00335 
00336         /** \brief The convergence threshold for the summed vector lengths of all poses. */
00337         float convergence_threshold_;
00338     };
00339   }
00340 }
00341 
00342 #ifdef PCL_NO_PRECOMPILE
00343 #include <pcl/registration/impl/lum.hpp>
00344 #endif
00345 
00346 #endif  // PCL_REGISTRATION_LUM_H_
00347