motion_estimation_icp.cpp
Go to the documentation of this file.
00001 
00024 #include "ccny_rgbd/registration/motion_estimation_icp.h"
00025 
00026 namespace ccny_rgbd {
00027 
00028 MotionEstimationICP::MotionEstimationICP(
00029   const ros::NodeHandle& nh, 
00030   const ros::NodeHandle& nh_private):
00031   MotionEstimation(nh, nh_private)
00032 {
00033   // *** init params  
00034   
00035   int history_size;
00036   
00037   if (!nh_private_.getParam ("fixed_frame", fixed_frame_))
00038     fixed_frame_ = "/odom";
00039   if (!nh_private_.getParam ("base_frame", base_frame_))
00040     base_frame_ = "/camera_link";
00041 
00042   if (!nh_private_.getParam ("reg/ICP/tf_epsilon_linear", tf_epsilon_linear_))
00043     tf_epsilon_linear_ = 1e-3; // 1 mm
00044   if (!nh_private_.getParam ("reg/ICP/tf_epsilon_angular", tf_epsilon_angular_))
00045     tf_epsilon_angular_ = 1.7e-2; // 1 deg
00046   if (!nh_private_.getParam ("reg/ICP/max_iterations", max_iterations_))
00047     max_iterations_ = 10;
00048   if (!nh_private_.getParam ("reg/ICP/min_correspondences", min_correspondences_))
00049     min_correspondences_ = 15; 
00050   if (!nh_private_.getParam ("reg/ICP/max_corresp_dist_eucl", max_corresp_dist_eucl_))
00051     max_corresp_dist_eucl_ = 0.15;
00052   if (!nh_private_.getParam ("reg/ICP/publish_model_cloud", publish_model_))
00053     publish_model_ = false;
00054   if (!nh_private_.getParam ("reg/ICP/history_size", history_size))
00055     history_size = 5;
00056 
00057   feature_history_.setCapacity(history_size);
00058   
00059   // derived
00060   
00061   max_corresp_dist_eucl_sq_ = max_corresp_dist_eucl_ * max_corresp_dist_eucl_;
00062   
00063   // **** init variables
00064   
00065   f2b_.setIdentity();
00066   
00067   model_ptr_.reset(new PointCloudFeature());
00068   model_ptr_->header.frame_id = fixed_frame_;
00069   
00070   // **** publishers
00071 
00072   if (publish_model_)
00073   {
00074     model_publisher_ = nh_.advertise<PointCloudFeature>(
00075       "model/cloud", 1);
00076   }
00077 }
00078 
00079 MotionEstimationICP::~MotionEstimationICP()
00080 {
00081 
00082 }
00083 
00084 bool MotionEstimationICP::getMotionEstimationImpl(
00085   RGBDFrame& frame,
00086   const tf::Transform& prediction,
00087   tf::Transform& motion)
00088 {
00090   bool result;
00091  
00092   // **** create a data cloud from the means
00093   
00094   Vector3fVector data_means;
00095   removeInvalidMeans(frame.kp_means, frame.kp_valid, data_means);
00096   transformMeans(data_means, f2b_ * b2c_);
00097   
00098   // **** align ********************************************************
00099  
00100   if (model_ptr_->points.empty())
00101   {
00102     ROS_INFO("No points in model: initializing from features.");
00103     motion.setIdentity();
00104     result = true;
00105   }
00106   else
00107   {
00108     // align using icp 
00109     result = alignICPEuclidean(data_means, motion);
00110   }
00111 
00112   if (result)
00113   { 
00114     constrainMotion(motion);
00115     f2b_ = motion * f2b_;
00116   }
00117   else
00118   {
00119     feature_history_.reset();
00120     motion.setIdentity();
00121   }
00122   
00123   // **** update model  ***********************************************
00124  
00125   // transform features using the new estimate for the fixed frame
00126   PointCloudFeature features;
00127   frame.constructFeaturePointCloud(features);
00128   pcl::transformPointCloud(features , features, eigenFromTf(f2b_* b2c_));
00129   
00130   // aggregate in feature history
00131   features.header.frame_id = fixed_frame_;
00132   feature_history_.add(features);
00133 
00134    // update model
00135   model_ptr_->points.clear();
00136   feature_history_.getAll(*model_ptr_); 
00137   model_tree_.setInputCloud(model_ptr_);
00138   
00139   // **** publish visuals *********************************************
00140       
00141   if (publish_model_)
00142   {
00143     // update model pointcloud and publish
00144     model_ptr_->header.stamp = frame.header.stamp;
00145     model_ptr_->width = model_ptr_->points.size();
00146     model_publisher_.publish(model_ptr_);
00147   }
00148   
00149   return result;
00150 }
00151 
00152 bool MotionEstimationICP::alignICPEuclidean(
00153   const Vector3fVector& data_means,
00154   tf::Transform& correction)
00155 {
00156   TransformationEstimationSVD svd;
00157 
00158   // create a point cloud from the means
00159   PointCloudFeature data_cloud;
00160   pointCloudFromMeans(data_means, data_cloud);
00161 
00162   // initialize the result transform
00163   Eigen::Matrix4f final_transformation; 
00164   final_transformation.setIdentity();
00165   
00166   for (int iteration = 0; iteration < max_iterations_; ++iteration)
00167   {    
00168     // get corespondences
00169     IntVector data_indices, model_indices;
00170     getCorrespEuclidean(data_cloud, data_indices, model_indices);
00171    
00172     if ((int)data_indices.size() <  min_correspondences_)
00173     {
00174       ROS_WARN("[ICP] Not enough correspondences (%d of %d minimum). Leacing ICP loop",
00175         (int)data_indices.size(),  min_correspondences_);
00176       return false;
00177     }
00178 
00179     // estimae transformation
00180     Eigen::Matrix4f transformation; 
00181     svd.estimateRigidTransformation (data_cloud, data_indices,
00182                                      *model_ptr_, model_indices,
00183                                      transformation);
00184     
00185     // rotate   
00186     pcl::transformPointCloud(data_cloud, data_cloud, transformation);
00187     
00188     // accumulate incremental tf
00189     final_transformation = transformation * final_transformation;
00190 
00191     // check for convergence
00192     double linear, angular;
00193     getTfDifference(
00194       tfFromEigen(transformation), linear, angular);
00195     if (linear  < tf_epsilon_linear_ &&
00196         angular < tf_epsilon_angular_)
00197     {
00198       //printf("(%f %f) conv. at [%d] leaving loop\n", 
00199       //  linear*1000.0, angular*10.0*180.0/3.14, iteration);
00200       break; 
00201     }
00202   }
00203   
00204   correction = tfFromEigen(final_transformation);
00205   return true;
00206 }
00207 
00208 void MotionEstimationICP::getCorrespEuclidean(
00209   const PointCloudFeature& data_cloud,
00210   IntVector& data_indices,
00211   IntVector& model_indices)
00212 {
00213   for (unsigned int data_idx = 0; data_idx < data_cloud.size(); ++data_idx)
00214   {
00215     const PointFeature& data_point = data_cloud.points[data_idx];
00216     
00217     int eucl_nn_idx;
00218     double eucl_dist_sq;
00219     
00220     bool nn_result = getNNEuclidean(data_point, eucl_nn_idx, eucl_dist_sq);
00221     
00222     if (nn_result && eucl_dist_sq < max_corresp_dist_eucl_sq_)
00223     {
00224       data_indices.push_back(data_idx);
00225       model_indices.push_back(eucl_nn_idx);
00226     }
00227   }  
00228 }
00229 
00230 bool MotionEstimationICP::getNNEuclidean(
00231   const PointFeature& data_point,
00232   int& eucl_nn_idx, double& eucl_dist_sq)
00233 {
00234   // find n Euclidean nearest neighbors
00235   IntVector indices;
00236   FloatVector dist_sq;
00237   
00238   indices.resize(1);
00239   dist_sq.resize(1);
00240   
00241   int n_retrieved = model_tree_.nearestKSearch(data_point, 1, indices, dist_sq);
00242   
00243   if (n_retrieved != 0)
00244   {
00245     eucl_nn_idx = indices[0];
00246     eucl_dist_sq = dist_sq[0];
00247     return true;
00248   }
00249   else return false;
00250 }
00251 
00252 } // namespace ccny_rgbd
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends


ccny_rgbd
Author(s): Ivan Dryanovski
autogenerated on Fri Apr 12 2013 20:38:48