00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #ifndef PCL_REGISTRATION_IMPL_LUM_HPP_
00042 #define PCL_REGISTRATION_IMPL_LUM_HPP_
00043
00045 template<typename PointT> inline void
00046 pcl::registration::LUM<PointT>::setLoopGraph (const SLAMGraphPtr &slam_graph)
00047 {
00048 slam_graph_ = slam_graph;
00049 }
00050
00052 template<typename PointT> inline typename pcl::registration::LUM<PointT>::SLAMGraphPtr
00053 pcl::registration::LUM<PointT>::getLoopGraph () const
00054 {
00055 return (slam_graph_);
00056 }
00057
00059 template<typename PointT> typename pcl::registration::LUM<PointT>::SLAMGraph::vertices_size_type
00060 pcl::registration::LUM<PointT>::getNumVertices () const
00061 {
00062 return (num_vertices (*slam_graph_));
00063 }
00064
00066 template<typename PointT> void
00067 pcl::registration::LUM<PointT>::setMaxIterations (int max_iterations)
00068 {
00069 max_iterations_ = max_iterations;
00070 }
00071
00073 template<typename PointT> inline int
00074 pcl::registration::LUM<PointT>::getMaxIterations () const
00075 {
00076 return (max_iterations_);
00077 }
00078
00080 template<typename PointT> void
00081 pcl::registration::LUM<PointT>::setConvergenceThreshold (float convergence_threshold)
00082 {
00083 convergence_threshold_ = convergence_threshold;
00084 }
00085
00087 template<typename PointT> inline float
00088 pcl::registration::LUM<PointT>::getConvergenceThreshold () const
00089 {
00090 return (convergence_threshold_);
00091 }
00092
00094 template<typename PointT> typename pcl::registration::LUM<PointT>::Vertex
00095 pcl::registration::LUM<PointT>::addPointCloud (const PointCloudPtr &cloud, const Eigen::Vector6f &pose)
00096 {
00097 Vertex v = add_vertex (*slam_graph_);
00098 (*slam_graph_)[v].cloud_ = cloud;
00099 if (v == 0 && pose != Eigen::Vector6f::Zero ())
00100 {
00101 PCL_WARN("[pcl::registration::LUM::addPointCloud] The pose estimate is ignored for the first cloud in the graph since that will become the reference pose.\n");
00102 (*slam_graph_)[v].pose_ = Eigen::Vector6f::Zero ();
00103 return (v);
00104 }
00105 (*slam_graph_)[v].pose_ = pose;
00106 return (v);
00107 }
00108
00110 template<typename PointT> inline void
00111 pcl::registration::LUM<PointT>::setPointCloud (const Vertex &vertex, const PointCloudPtr &cloud)
00112 {
00113 if (vertex >= getNumVertices ())
00114 {
00115 PCL_ERROR("[pcl::registration::LUM::setPointCloud] You are attempting to set a point cloud to a non-existing graph vertex.\n");
00116 return;
00117 }
00118 (*slam_graph_)[vertex].cloud_ = cloud;
00119 }
00120
00122 template<typename PointT> inline typename pcl::registration::LUM<PointT>::PointCloudPtr
00123 pcl::registration::LUM<PointT>::getPointCloud (const Vertex &vertex) const
00124 {
00125 if (vertex >= getNumVertices ())
00126 {
00127 PCL_ERROR("[pcl::registration::LUM::getPointCloud] You are attempting to get a point cloud from a non-existing graph vertex.\n");
00128 return (PointCloudPtr ());
00129 }
00130 return ((*slam_graph_)[vertex].cloud_);
00131 }
00132
00134 template<typename PointT> inline void
00135 pcl::registration::LUM<PointT>::setPose (const Vertex &vertex, const Eigen::Vector6f &pose)
00136 {
00137 if (vertex >= getNumVertices ())
00138 {
00139 PCL_ERROR("[pcl::registration::LUM::setPose] You are attempting to set a pose estimate to a non-existing graph vertex.\n");
00140 return;
00141 }
00142 if (vertex == 0)
00143 {
00144 PCL_ERROR("[pcl::registration::LUM::setPose] The pose estimate is ignored for the first cloud in the graph since that will become the reference pose.\n");
00145 return;
00146 }
00147 (*slam_graph_)[vertex].pose_ = pose;
00148 }
00149
00151 template<typename PointT> inline Eigen::Vector6f
00152 pcl::registration::LUM<PointT>::getPose (const Vertex &vertex) const
00153 {
00154 if (vertex >= getNumVertices ())
00155 {
00156 PCL_ERROR("[pcl::registration::LUM::getPose] You are attempting to get a pose estimate from a non-existing graph vertex.\n");
00157 return (Eigen::Vector6f::Zero ());
00158 }
00159 return ((*slam_graph_)[vertex].pose_);
00160 }
00161
00163 template<typename PointT> inline Eigen::Affine3f
00164 pcl::registration::LUM<PointT>::getTransformation (const Vertex &vertex) const
00165 {
00166 Eigen::Vector6f pose = getPose (vertex);
00167 return (pcl::getTransformation (pose (0), pose (1), pose (2), pose (3), pose (4), pose (5)));
00168 }
00169
00171 template<typename PointT> void
00172 pcl::registration::LUM<PointT>::setCorrespondences (const Vertex &source_vertex, const Vertex &target_vertex, const pcl::CorrespondencesPtr &corrs)
00173 {
00174 if (source_vertex >= getNumVertices () || target_vertex >= getNumVertices () || source_vertex == target_vertex)
00175 {
00176 PCL_ERROR("[pcl::registration::LUM::setCorrespondences] You are attempting to set a set of correspondences between non-existing or identical graph vertices.\n");
00177 return;
00178 }
00179 Edge e;
00180 bool present;
00181 boost::tuples::tie (e, present) = edge (source_vertex, target_vertex, *slam_graph_);
00182 if (!present)
00183 boost::tuples::tie (e, present) = add_edge (source_vertex, target_vertex, *slam_graph_);
00184 (*slam_graph_)[e].corrs_ = corrs;
00185 }
00186
00188 template<typename PointT> inline pcl::CorrespondencesPtr
00189 pcl::registration::LUM<PointT>::getCorrespondences (const Vertex &source_vertex, const Vertex &target_vertex) const
00190 {
00191 if (source_vertex >= getNumVertices () || target_vertex >= getNumVertices ())
00192 {
00193 PCL_ERROR("[pcl::registration::LUM::getCorrespondences] You are attempting to get a set of correspondences between non-existing graph vertices.\n");
00194 return (pcl::CorrespondencesPtr ());
00195 }
00196 Edge e;
00197 bool present;
00198 boost::tuples::tie (e, present) = edge (source_vertex, target_vertex, *slam_graph_);
00199 if (!present)
00200 {
00201 PCL_ERROR("[pcl::registration::LUM::getCorrespondences] You are attempting to get a set of correspondences from a non-existing graph edge.\n");
00202 return (pcl::CorrespondencesPtr ());
00203 }
00204 return ((*slam_graph_)[e].corrs_);
00205 }
00206
00208 template<typename PointT> void
00209 pcl::registration::LUM<PointT>::compute ()
00210 {
00211 int n = static_cast<int> (getNumVertices ());
00212 if (n < 2)
00213 {
00214 PCL_ERROR("[pcl::registration::LUM::compute] The slam graph needs at least 2 vertices.\n");
00215 return;
00216 }
00217 for (int i = 0; i < max_iterations_; ++i)
00218 {
00219
00220 typename SLAMGraph::edge_iterator e, e_end;
00221 for (boost::tuples::tie (e, e_end) = edges (*slam_graph_); e != e_end; ++e)
00222 computeEdge (*e);
00223
00224
00225 Eigen::MatrixXf G = Eigen::MatrixXf::Zero (6 * (n - 1), 6 * (n - 1));
00226 Eigen::VectorXf B = Eigen::VectorXf::Zero (6 * (n - 1));
00227
00228
00229 for (int vi = 1; vi != n; ++vi)
00230 {
00231 for (int vj = 0; vj != n; ++vj)
00232 {
00233
00234 Edge e;
00235 bool present1, present2;
00236 boost::tuples::tie (e, present1) = edge (vi, vj, *slam_graph_);
00237 if (!present1)
00238 {
00239 boost::tuples::tie (e, present2) = edge (vj, vi, *slam_graph_);
00240 if (!present2)
00241 continue;
00242 }
00243
00244
00245 if (vj > 0)
00246 G.block (6 * (vi - 1), 6 * (vj - 1), 6, 6) = -(*slam_graph_)[e].cinv_;
00247 G.block (6 * (vi - 1), 6 * (vi - 1), 6, 6) += (*slam_graph_)[e].cinv_;
00248 B.segment (6 * (vi - 1), 6) += (present1 ? 1 : -1) * (*slam_graph_)[e].cinvd_;
00249 }
00250 }
00251
00252
00253
00254 Eigen::VectorXf X = G.colPivHouseholderQr ().solve (B);
00255
00256
00257 float sum = 0.0;
00258 for (int vi = 1; vi != n; ++vi)
00259 {
00260 Eigen::Vector6f difference_pose = static_cast<Eigen::Vector6f> (-incidenceCorrection (getPose (vi)).inverse () * X.segment (6 * (vi - 1), 6));
00261 sum += difference_pose.norm ();
00262 setPose (vi, getPose (vi) + difference_pose);
00263 }
00264
00265
00266 if (sum <= convergence_threshold_ * static_cast<float> (n - 1))
00267 return;
00268 }
00269 }
00270
00272 template<typename PointT> typename pcl::registration::LUM<PointT>::PointCloudPtr
00273 pcl::registration::LUM<PointT>::getTransformedCloud (const Vertex &vertex) const
00274 {
00275 PointCloudPtr out (new PointCloud);
00276 pcl::transformPointCloud (*getPointCloud (vertex), *out, getTransformation (vertex));
00277 return (out);
00278 }
00279
00281 template<typename PointT> typename pcl::registration::LUM<PointT>::PointCloudPtr
00282 pcl::registration::LUM<PointT>::getConcatenatedCloud () const
00283 {
00284 PointCloudPtr out (new PointCloud);
00285 typename SLAMGraph::vertex_iterator v, v_end;
00286 for (boost::tuples::tie (v, v_end) = vertices (*slam_graph_); v != v_end; ++v)
00287 {
00288 PointCloud temp;
00289 pcl::transformPointCloud (*getPointCloud (*v), temp, getTransformation (*v));
00290 *out += temp;
00291 }
00292 return (out);
00293 }
00294
00296 template<typename PointT> void
00297 pcl::registration::LUM<PointT>::computeEdge (const Edge &e)
00298 {
00299
00300 PointCloudPtr source_cloud = (*slam_graph_)[source (e, *slam_graph_)].cloud_;
00301 PointCloudPtr target_cloud = (*slam_graph_)[target (e, *slam_graph_)].cloud_;
00302 Eigen::Vector6f source_pose = (*slam_graph_)[source (e, *slam_graph_)].pose_;
00303 Eigen::Vector6f target_pose = (*slam_graph_)[target (e, *slam_graph_)].pose_;
00304 pcl::CorrespondencesPtr corrs = (*slam_graph_)[e].corrs_;
00305
00306
00307 std::vector <Eigen::Vector3f> corrs_aver (corrs->size ());
00308 std::vector <Eigen::Vector3f> corrs_diff (corrs->size ());
00309 int oci = 0;
00310 for (int ici = 0; ici != static_cast<int> (corrs->size ()); ++ici)
00311 {
00312
00313 Eigen::Vector3f source_compounded = pcl::getTransformation (source_pose (0), source_pose (1), source_pose (2), source_pose (3), source_pose (4), source_pose (5)) * source_cloud->points[(*corrs)[ici].index_query].getVector3fMap ();
00314 Eigen::Vector3f target_compounded = pcl::getTransformation (target_pose (0), target_pose (1), target_pose (2), target_pose (3), target_pose (4), target_pose (5)) * target_cloud->points[(*corrs)[ici].index_match].getVector3fMap ();
00315
00316
00317 if (!pcl_isfinite (source_compounded (0)) || !pcl_isfinite (source_compounded (1)) || !pcl_isfinite (source_compounded (2)) || !pcl_isfinite (target_compounded (0)) || !pcl_isfinite (target_compounded (1)) || !pcl_isfinite (target_compounded (2)))
00318 continue;
00319
00320
00321 corrs_aver[oci] = 0.5 * (source_compounded + target_compounded);
00322 corrs_diff[oci] = source_compounded - target_compounded;
00323 oci++;
00324 }
00325 corrs_aver.resize (oci);
00326 corrs_diff.resize (oci);
00327
00328
00329 if (oci < 3)
00330 {
00331 PCL_WARN("[pcl::registration::LUM::compute] The correspondences between vertex %d and %d do not contain enough valid correspondences to be considered for computation.\n", source (e, *slam_graph_), target (e, *slam_graph_));
00332 (*slam_graph_)[e].cinv_ = Eigen::Matrix6f::Zero ();
00333 (*slam_graph_)[e].cinvd_ = Eigen::Vector6f::Zero ();
00334 return;
00335 }
00336
00337
00338 Eigen::Matrix6f MM = Eigen::Matrix6f::Zero ();
00339 Eigen::Vector6f MZ = Eigen::Vector6f::Zero ();
00340 for (int ci = 0; ci != oci; ++ci)
00341 {
00342
00343 MM (0, 4) -= corrs_aver[ci] (1);
00344 MM (0, 5) += corrs_aver[ci] (2);
00345 MM (1, 3) -= corrs_aver[ci] (2);
00346 MM (1, 4) += corrs_aver[ci] (0);
00347 MM (2, 3) += corrs_aver[ci] (1);
00348 MM (2, 5) -= corrs_aver[ci] (0);
00349 MM (3, 4) -= corrs_aver[ci] (0) * corrs_aver[ci] (2);
00350 MM (3, 5) -= corrs_aver[ci] (0) * corrs_aver[ci] (1);
00351 MM (4, 5) -= corrs_aver[ci] (1) * corrs_aver[ci] (2);
00352 MM (3, 3) += corrs_aver[ci] (1) * corrs_aver[ci] (1) + corrs_aver[ci] (2) * corrs_aver[ci] (2);
00353 MM (4, 4) += corrs_aver[ci] (0) * corrs_aver[ci] (0) + corrs_aver[ci] (1) * corrs_aver[ci] (1);
00354 MM (5, 5) += corrs_aver[ci] (0) * corrs_aver[ci] (0) + corrs_aver[ci] (2) * corrs_aver[ci] (2);
00355
00356
00357 MZ (0) += corrs_diff[ci] (0);
00358 MZ (1) += corrs_diff[ci] (1);
00359 MZ (2) += corrs_diff[ci] (2);
00360 MZ (3) += corrs_aver[ci] (1) * corrs_diff[ci] (2) - corrs_aver[ci] (2) * corrs_diff[ci] (1);
00361 MZ (4) += corrs_aver[ci] (0) * corrs_diff[ci] (1) - corrs_aver[ci] (1) * corrs_diff[ci] (0);
00362 MZ (5) += corrs_aver[ci] (2) * corrs_diff[ci] (0) - corrs_aver[ci] (0) * corrs_diff[ci] (2);
00363 }
00364
00365 MM (0, 0) = MM (1, 1) = MM (2, 2) = static_cast<float> (oci);
00366 MM (4, 0) = MM (0, 4);
00367 MM (5, 0) = MM (0, 5);
00368 MM (3, 1) = MM (1, 3);
00369 MM (4, 1) = MM (1, 4);
00370 MM (3, 2) = MM (2, 3);
00371 MM (5, 2) = MM (2, 5);
00372 MM (4, 3) = MM (3, 4);
00373 MM (5, 3) = MM (3, 5);
00374 MM (5, 4) = MM (4, 5);
00375
00376
00377 Eigen::Vector6f D = static_cast<Eigen::Vector6f> (MM.inverse () * MZ);
00378
00379
00380 float ss = 0.0f;
00381 for (int ci = 0; ci != oci; ++ci)
00382 ss += static_cast<float> (pow (corrs_diff[ci] (0) - (D (0) + corrs_aver[ci] (2) * D (5) - corrs_aver[ci] (1) * D (4)), 2.0f)
00383 + pow (corrs_diff[ci] (1) - (D (1) + corrs_aver[ci] (0) * D (4) - corrs_aver[ci] (2) * D (3)), 2.0f)
00384 + pow (corrs_diff[ci] (2) - (D (2) + corrs_aver[ci] (1) * D (3) - corrs_aver[ci] (0) * D (5)), 2.0f));
00385
00386
00387 if (ss < 0.0000000000001 || !pcl_isfinite (ss))
00388 {
00389 (*slam_graph_)[e].cinv_ = Eigen::Matrix6f::Zero ();
00390 (*slam_graph_)[e].cinvd_ = Eigen::Vector6f::Zero ();
00391 return;
00392 }
00393
00394
00395 (*slam_graph_)[e].cinv_ = MM * (1.0f / ss);
00396 (*slam_graph_)[e].cinvd_ = MZ * (1.0f / ss);
00397 }
00398
00400 template<typename PointT> inline Eigen::Matrix6f
00401 pcl::registration::LUM<PointT>::incidenceCorrection (const Eigen::Vector6f &pose)
00402 {
00403 Eigen::Matrix6f out = Eigen::Matrix6f::Identity ();
00404 float cx = cosf (pose (3)), sx = sinf (pose (3)), cy = cosf (pose (4)), sy = sinf (pose (4));
00405 out (0, 4) = pose (1) * sx - pose (2) * cx;
00406 out (0, 5) = pose (1) * cx * cy + pose (2) * sx * cy;
00407 out (1, 3) = pose (2);
00408 out (1, 4) = -pose (0) * sx;
00409 out (1, 5) = -pose (0) * cx * cy + pose (2) * sy;
00410 out (2, 3) = -pose (1);
00411 out (2, 4) = pose (0) * cx;
00412 out (2, 5) = -pose (0) * sx * cy - pose (1) * sy;
00413 out (3, 5) = sy;
00414 out (4, 4) = sx;
00415 out (4, 5) = cx * cy;
00416 out (5, 4) = cx;
00417 out (5, 5) = -sx * cy;
00418 return (out);
00419 }
00420
00421 #define PCL_INSTANTIATE_LUM(T) template class PCL_EXPORTS pcl::registration::LUM<T>;
00422
00423 #endif // PCL_REGISTRATION_IMPL_LUM_HPP_
00424