Point Cloud Library (PCL)
1.7.0
|
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