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_