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 #include <pointcloud_registration/icp/registration_correspondences_check.h>
00035
00036 #ifndef _ICP_CORRESPONDENCES_CHECK_H_
00037 #define _ICP_CORRESPONDENCES_CHECK_H_
00038
00039 namespace pcl
00040 {
00044
00045 template <typename PointSource, typename PointTarget>
00046 class IterativeClosestPointCorrespondencesCheck : public RegistrationCorrespondencesCheck<PointSource, PointTarget>
00047 {
00048 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::reg_name_;
00049 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::getClassName;
00050 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::input_;
00051 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::indices_;
00052 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::target_;
00053 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::nr_iterations_;
00054 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::max_iterations_;
00055 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::previous_transformation_;
00056 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::final_transformation_;
00057 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::transformation_;
00058 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::transformation_epsilon_;
00059 using RegistrationCorrespondencesCheck<PointSource, PointTarget>::converged_;
00060
00061 typedef typename RegistrationCorrespondencesCheck<PointSource, PointTarget>::PointCloudSource PointCloudSource;
00062 typedef typename PointCloudSource::Ptr PointCloudSourcePtr;
00063 typedef typename PointCloudSource::ConstPtr PointCloudSourceConstPtr;
00064
00065 typedef typename RegistrationCorrespondencesCheck<PointSource, PointTarget>::PointCloudTarget PointCloudTarget;
00066
00067 typedef PointIndices::Ptr PointIndicesPtr;
00068 typedef PointIndices::ConstPtr PointIndicesConstPtr;
00069
00070 double radius_, epsilon_z_, epsilon_curvature_;
00071 int max_nn_;
00072 bool curvature_check_;
00073 time_t start, end;
00074 std::string field_;
00075 public:
00077
00079 IterativeClosestPointCorrespondencesCheck(){reg_name_ = "IterativeClosestPointCorrespondencesCheck";};
00081 IterativeClosestPointCorrespondencesCheck ( double radius, int max_nn, double epsilon_z, double epsilon_curvature, bool curvature_check):
00082 radius_(radius),
00083 max_nn_(max_nn),
00084 epsilon_z_(epsilon_z),
00085 epsilon_curvature_(epsilon_curvature),
00086 curvature_check_(curvature_check){reg_name_ = "IterativeClosestPointCorrespondencesCheck";};
00087
00089
00090 virtual ~IterativeClosestPointCorrespondencesCheck () {};
00091
00092 protected:
00093
00095
00098 virtual void computeTransformation (PointCloudSource &output)
00099 {
00100
00101 std::vector<int> nn_indices (max_nn_);
00102 std::vector<float> nn_dists (max_nn_);
00103
00104 int count = 0;
00105 this->nr_iterations_ = 0;
00106 while (!this->converged_)
00107 {
00108 ROS_INFO("[IterativeClosestPointCorrespondencesCheck:] Iteration Number: %d", this->nr_iterations_);
00109
00110 PointCloudTarget model_corresp;
00111 PointCloudSource source_corresp;
00112
00113 count = 0;
00114 source_corresp.points.reserve(this->indices_->size());
00115 model_corresp.points.reserve(this->indices_->size());
00116
00117 this->previous_transformation_ = this->transformation_;
00118 ROS_INFO("[IterativeClosestPointCorrespondencesCheck:] finding correpondences for %ld points, %d, %lf",
00119 this->indices_->size(), max_nn_, radius_);
00120 start = time(NULL);
00121
00122 for (size_t idx = 0; idx < this->indices_->size (); idx++)
00123
00124 {
00125
00126 if (!searchForNeighbors (output, idx, radius_, max_nn_, nn_indices, nn_dists))
00127 {
00128
00129 continue;
00130 }
00131 for(size_t i = 0 ; i < nn_indices.size(); i++)
00132 {
00133
00134 if(fabs(output.points[idx].z - this->target_->points[nn_indices[i]].z) < epsilon_z_ && field_ == "z")
00135 {
00136 if(curvature_check_)
00137 {
00138
00139 if(fabs(output.points[idx].curvature - this->target_->points[nn_indices[i]].curvature) > epsilon_curvature_)
00140 {
00141 continue;
00142 }
00143 }
00144 count++;
00145 source_corresp.points.push_back (output.points[idx]);
00146 model_corresp.points.push_back (this->target_->points[nn_indices[i]]);
00147 break;
00148 }
00149 else if(fabs(output.points[idx].y - this->target_->points[nn_indices[i]].y) < epsilon_z_ && field_ == "y")
00150 {
00151 if(curvature_check_)
00152 {
00153
00154 if(fabs(output.points[idx].curvature - this->target_->points[nn_indices[i]].curvature) > epsilon_curvature_)
00155 {
00156 continue;
00157 }
00158 }
00159 count++;
00160 source_corresp.points.push_back (output.points[idx]);
00161 model_corresp.points.push_back (this->target_->points[nn_indices[i]]);
00162 break;
00163 }
00164 else if(fabs(output.points[idx].x - this->target_->points[nn_indices[i]].x) < epsilon_z_ && field_ == "x")
00165 {
00166 if(curvature_check_)
00167 {
00168
00169 if(fabs(output.points[idx].curvature - this->target_->points[nn_indices[i]].curvature) > epsilon_curvature_)
00170 {
00171 continue;
00172 }
00173 }
00174 count++;
00175 source_corresp.points.push_back (output.points[idx]);
00176 model_corresp.points.push_back (this->target_->points[nn_indices[i]]);
00177 break;
00178 }
00179 else
00180 {
00181
00182
00183
00184
00185
00186
00187
00188 }
00189 }
00190 }
00191 end = time(NULL);
00192 ROS_INFO("[IterativeClosestPointCorrespondencesCheck:] found correpondences in %d seconds", (int)(end - start));
00193
00194
00195 if(source_corresp.points.size() == 0)
00196 {
00197 ROS_ERROR("[IterativeClosestPointCorrespondencesCheck:] No correspondences found. Try to relax the conditions.", getClassName().c_str());
00198 return;
00199 }
00200
00201
00202 for(size_t i = 0; i < source_corresp.points.size(); i++)
00203 {
00204 if (field_ == "z")
00205 {
00206 source_corresp.points[i].z = 0.0;
00207 model_corresp.points[i].z = 0.0;
00208 }
00209 else if (field_ == "y")
00210 {
00211 source_corresp.points[i].y = 0.0;
00212 model_corresp.points[i].y = 0.0;
00213 }
00214 else if (field_ == "x")
00215 {
00216 source_corresp.points[i].x = 0.0;
00217 model_corresp.points[i].x = 0.0;
00218 }
00219 else
00220 {
00221 ROS_WARN("[IterativeClosestPointCorrespondencesCheck:] Unknown field_ %s. Has to be x, y or z.", field_.c_str());
00222 return;
00223 }
00224 }
00225
00226 start = time(NULL);
00227
00228 estimateRigidTransformationSVD (source_corresp, model_corresp, this->transformation_);
00229 end = time(NULL);
00230 ROS_INFO("[IterativeClosestPointCorrespondencesCheck:] estimateRigidTransformationSVD in %d seconds", (int)(end - start));
00231
00232
00233 transformPointCloud (output, output, this->transformation_);
00234
00235
00236 this->final_transformation_ = this->transformation_ * this->final_transformation_;
00237
00238
00239 double transformation_change = fabs ((this->transformation_ - this->previous_transformation_).sum ());
00240
00241
00242
00243 this->nr_iterations_++;
00244 ROS_INFO("[IterativeClosestPointCorrespondencesCheck] number of iterations: %d", this->nr_iterations_);
00245
00246 if (this->nr_iterations_ >= this->max_iterations_ ||
00247 transformation_change < this->transformation_epsilon_)
00248 {
00249 this->converged_ = true;
00250 ROS_INFO ("[IterativeClosestPointCorrespondencesCheck:] Convergence reached. Number of iterations: %d out of %d. Transformation difference: %g",
00251 getClassName().c_str(), this->nr_iterations_, this->max_iterations_, fabs ((this->transformation_ - this->previous_transformation_).sum ()));
00252 }
00253 }
00254 }
00255
00256 public:
00258
00264 void estimateRigidTransformationSVD (const PointCloudSource &cloud_src, const PointCloudTarget &cloud_tgt, Eigen::Matrix4f &transformation_matrix)
00265 {
00266 ROS_ASSERT (cloud_src.points.size () == cloud_tgt.points.size ());
00267
00268
00269 transformation_matrix.setIdentity ();
00270
00271 Eigen::Vector4f centroid_src, centroid_tgt;
00272
00273 compute3DCentroid (cloud_src, centroid_src);
00274 compute3DCentroid (cloud_tgt, centroid_tgt);
00275
00276
00277 Eigen::MatrixXf cloud_src_demean;
00278 demeanPointCloud (cloud_src, centroid_src, cloud_src_demean);
00279
00280
00281 Eigen::MatrixXf cloud_tgt_demean;
00282 demeanPointCloud (cloud_tgt, centroid_tgt, cloud_tgt_demean);
00283
00284
00285 Eigen::Matrix3f H = (cloud_src_demean * cloud_tgt_demean.transpose ()).topLeftCorner<3, 3>();
00286
00287
00288 Eigen::JacobiSVD<Eigen::Matrix3f> svd (H, Eigen::ComputeFullU | Eigen::ComputeFullV);
00289 Eigen::Matrix3f u = svd.matrixU ();
00290 Eigen::Matrix3f v = svd.matrixV ();
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 Eigen::Matrix3f R = v * u.transpose ();
00301
00302
00303 transformation_matrix.topLeftCorner<3, 3> () = R;
00304 Eigen::Vector3f Rc = R * centroid_src.head<3> ();
00305 transformation_matrix.block <3, 1> (0, 3) = centroid_tgt.head<3> () - Rc;
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 }
00328
00330
00331 void setParameters( double radius, int max_nn, double epsilon_z, double epsilon_curvature, bool curvature_check, std::string field)
00332 {
00333 radius_ = radius;
00334 max_nn_ = max_nn;
00335 epsilon_z_ = epsilon_z;
00336 epsilon_curvature_ = epsilon_curvature;
00337 curvature_check_ = curvature_check;
00338 field_ = field;
00339 }
00340 };
00341 }
00342
00343 #endif //#ifndef _ICP_CORRESPONDENCES_CHECK_H_