PointCloudMetrics.cpp
Go to the documentation of this file.
00001 
00012 // RAIL Recognition
00013 #include "rail_recognition/PointCloudMetrics.h"
00014 
00015 // ROS
00016 #include <pcl_conversions/pcl_conversions.h>
00017 
00018 // PCL
00019 #include <pcl/common/transforms.h>
00020 #include <pcl/filters/extract_indices.h>
00021 #include <pcl/kdtree/kdtree_flann.h>
00022 #include <pcl/registration/icp.h>
00023 
00024 using namespace std;
00025 using namespace rail::pick_and_place;
00026 
00027 void point_cloud_metrics::rosPointCloud2ToPCLPointCloud(const sensor_msgs::PointCloud2 in,
00028     const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &out)
00029 {
00030   pcl::PCLPointCloud2 converter;
00031   pcl_conversions::toPCL(in, converter);
00032   pcl::fromPCLPointCloud2(converter, *out);
00033 }
00034 
00035 void point_cloud_metrics::pclPointCloudToROSPointCloud2(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &in,
00036     sensor_msgs::PointCloud2 &out)
00037 {
00038   // convert to PCL PointCloud2
00039   pcl::PCLPointCloud2 converter;
00040   pcl::toPCLPointCloud2(*in, converter);
00041   // convert to ROS message
00042   pcl_conversions::fromPCL(converter, out);
00043 }
00044 
00045 void point_cloud_metrics::transformToOrigin(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00046     const geometry_msgs::Point &centroid)
00047 {
00048   // transformation matrix
00049   Eigen::Matrix4f tf;
00050   tf << 1, 0, 0, -centroid.x,
00051       0, 1, 0, -centroid.y,
00052       0, 0, 1, -centroid.z,
00053       0, 0, 0, 1;
00054 
00055   // transform the point cloud
00056   pcl::transformPointCloud(*pc, *pc, tf);
00057 }
00058 
00059 void point_cloud_metrics::transformToOrigin(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc)
00060 {
00061   // compute the centroid
00062   geometry_msgs::Point centroid = point_cloud_metrics::computeCentroid(pc);
00063   // transform the point cloud
00064   point_cloud_metrics::transformToOrigin(pc, centroid);
00065 }
00066 
00067 void point_cloud_metrics::transformToOrigin(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00068     vector<graspdb::Grasp> &grasps, const geometry_msgs::Point &centroid)
00069 {
00070   // start with the point cloud
00071   point_cloud_metrics::transformToOrigin(pc, centroid);
00072 
00073   // transform each grasp
00074   for (size_t i = 0; i < grasps.size(); i++)
00075   {
00076     graspdb::Position &position = grasps[i].getGraspPose().getPosition();
00077     position.setX(position.getX() - centroid.x);
00078     position.setY(position.getY() - centroid.y);
00079     position.setZ(position.getZ() - centroid.z);
00080   }
00081 }
00082 
00083 void point_cloud_metrics::transformToOrigin(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00084     vector<graspdb::Grasp> &grasps)
00085 {
00086   // compute the centroid
00087   geometry_msgs::Point centroid = point_cloud_metrics::computeCentroid(pc);
00088   // transform the point cloud and grasps
00089   point_cloud_metrics::transformToOrigin(pc, grasps, centroid);
00090 }
00091 
00092 void point_cloud_metrics::filterPointCloudOutliers(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00093     const double filter_outlier_search_radius, const double filter_outlier_min_num_neighbors)
00094 {
00095   // use a KD tree to search
00096   pcl::KdTreeFLANN<pcl::PointXYZRGB> search_tree;
00097   search_tree.setInputCloud(pc);
00098   vector<int> indices;
00099   vector<float> distances;
00100 
00101   // check each point
00102   pcl::IndicesPtr to_keep(new vector<int>);
00103   for (size_t i = 0; i < pc->size(); i++)
00104   {
00105     // check how many neighbors pass the test
00106     int neighbors = search_tree.radiusSearch(pc->at(i), filter_outlier_search_radius, indices, distances);
00107     if (neighbors >= filter_outlier_min_num_neighbors)
00108     {
00109       to_keep->push_back(i);
00110     }
00111   }
00112 
00113   // extract the point we wish to keep
00114   pcl::ExtractIndices<pcl::PointXYZRGB> extract;
00115   extract.setInputCloud(pc);
00116   extract.setIndices(to_keep);
00117   extract.filter(*pc);
00118 }
00119 
00120 void point_cloud_metrics::filterRedundantPoints(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &pc,
00121     const double filter_redundant_search_radius)
00122 {
00123   // non-empty clouds only
00124   if (pc->size() > 0)
00125   {
00126     // use a KD tree to search
00127     pcl::KdTreeFLANN<pcl::PointXYZRGB> search_tree;
00128     search_tree.setInputCloud(pc);
00129 
00130     // use int to prevent overflow
00131     for (int i = ((int) pc->size()) - 1; i >= 0; i--)
00132     {
00133       // see if the number of neighbors is non-empty (includes the point itself)
00134       vector<int> indices;
00135       vector<float> distances;
00136       int neighbors = search_tree.radiusSearch(pc->at(i), filter_redundant_search_radius, indices, distances);
00137       if (neighbors >= 2)
00138       {
00139         // remove this point
00140         pc->erase(pc->begin() + i);
00141       }
00142     }
00143   }
00144 }
00145 
00146 geometry_msgs::Point point_cloud_metrics::computeCentroid(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc)
00147 {
00148   // compute the centroid
00149   Eigen::Vector4f centroid;
00150   pcl::compute3DCentroid(*pc, centroid);
00151   geometry_msgs::Point ros_centroid;
00152   ros_centroid.x = centroid[0];
00153   ros_centroid.y = centroid[1];
00154   ros_centroid.z = centroid[2];
00155 
00156   return ros_centroid;
00157 }
00158 
00159 double point_cloud_metrics::calculateRegistrationMetricDistanceError(
00160     const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &base, const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &target)
00161 {
00162   // search using a KD tree
00163   pcl::KdTreeFLANN<pcl::PointXYZRGB> search_tree;
00164   search_tree.setInputCloud(base);
00165 
00166   // search for the nearest point to each point
00167   double score = 0;
00168   for (size_t i = 0; i < target->size(); i++)
00169   {
00170     vector<int> indices;
00171     vector<float> distances;
00172     search_tree.nearestKSearch(target->at(i), 1, indices, distances);
00173     score += (double) distances[0];
00174   }
00175 
00176   return score;
00177 }
00178 
00179 void point_cloud_metrics::calculateAvgColors(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc, double &avg_r,
00180     double &avg_g, double &avg_b)
00181 {
00182   // simply go through each point
00183   avg_r = 0;
00184   avg_g = 0;
00185   avg_b = 0;
00186   for (size_t i = 0; i < pc->size(); i++)
00187   {
00188     const pcl::PointXYZRGB &point = pc->at(i);
00189     avg_r += point.r;
00190     avg_g += point.g;
00191     avg_b += point.b;
00192   }
00193 
00194   // average the values
00195   avg_r /= (double) pc->size();
00196   avg_g /= (double) pc->size();
00197   avg_b /= (double) pc->size();
00198 }
00199 
00200 double point_cloud_metrics::calculateStdDevColors(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc,
00201     double &std_dev_r, double &std_dev_g, double &std_dev_b)
00202 {
00203   // calculate the averages first
00204   double avg_r, avg_g, avg_b;
00205   point_cloud_metrics::calculateAvgColors(pc, avg_r, avg_g, avg_b);
00206   point_cloud_metrics::calculateStdDevColors(pc, std_dev_r, std_dev_g, std_dev_b, avg_r, avg_g, avg_b);
00207 }
00208 
00209 double point_cloud_metrics::calculateStdDevColors(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &pc,
00210     double &std_dev_r, double &std_dev_g, double &std_dev_b, const double avg_r, const double avg_g, const double avg_b)
00211 {
00212   double variance_r = 0;
00213   double variance_g = 0;
00214   double variance_b = 0;
00215   for (size_t i = 0; i < pc->size(); i++)
00216   {
00217     const pcl::PointXYZRGB &point = pc->at(i);
00218     variance_r += pow(point.r - avg_r, 2);
00219     variance_g += pow(point.g - avg_r, 2);
00220     variance_b += pow(point.b - avg_r, 2);
00221   }
00222   variance_r /= (double) pc->size();
00223   variance_g /= (double) pc->size();
00224   variance_b /= (double) pc->size();
00225 
00226   std_dev_r = sqrt(variance_r);
00227   std_dev_g = sqrt(variance_g);
00228   std_dev_b = sqrt(variance_b);
00229 }
00230 
00231 void point_cloud_metrics::calculateRegistrationMetricOverlap(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &base,
00232     const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &target, double &overlap, double &color_error,
00233     const double metric_overlap_search_radius)
00234 {
00235   // search with a KD tree
00236   pcl::KdTreeFLANN<pcl::PointXYZRGB> search_tree;
00237   search_tree.setInputCloud(base);
00238 
00239   // search each point
00240   double score = 0;
00241   double error = 0;
00242   for (size_t i = 0; i < target->size(); i++)
00243   {
00244     // get the current point
00245     vector<int> indices;
00246     vector<float> distances;
00247     const pcl::PointXYZRGB &search_point = target->at(i);
00248     // perform a radius search to see how many neighbors are found
00249     int neighbors = search_tree.radiusSearch(search_point, metric_overlap_search_radius, indices, distances);
00250     // check if there are enough neighbors
00251     if (neighbors > 0)
00252     {
00253       score++;
00254       // check the average RGB color distance
00255       double rgb_distance = 0;
00256       for (size_t j = 0; j < indices.size(); j++)
00257       {
00258         const pcl::PointXYZRGB &point = base->at(indices[j]);
00259         rgb_distance += sqrt(pow(search_point.r - point.r, 2) + pow(search_point.g - point.g, 2) +
00260                              pow(search_point.b - point.b, 2));
00261       }
00262       // normalize the distance
00263       rgb_distance /= neighbors;
00264       error += rgb_distance;
00265     }
00266   }
00267 
00268   // normalize the errors
00269   color_error = error / score;
00270   overlap = score / (double) target->size();
00271 }
00272 
00273 bool point_cloud_metrics::classifyMerge(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &base,
00274     const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &target)
00275 {
00276   // calculate the metrics we need
00277   double overlap, color_error;
00278   point_cloud_metrics::calculateRegistrationMetricOverlap(base, target, overlap, color_error);
00279 
00280   double distance_error = point_cloud_metrics::calculateRegistrationMetricDistanceError(base, target);
00281 
00282   // values found via decision tree training (standard kinect)
00283   //return (overlap > 0.471303) && (color_error <= 97.0674);
00284 
00285   // values found via decision tree training (hd kinect v2)
00286   return distance_error <= .347063 && color_error <= 113.569;
00287 }
00288 
00289 tf2::Transform point_cloud_metrics::performICP(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &target,
00290     const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &source, const pcl::PointCloud<pcl::PointXYZRGB>::Ptr &result)
00291 {
00292   // set the ICP point clouds
00293   pcl::IterativeClosestPoint<pcl::PointXYZRGB, pcl::PointXYZRGB> icp;
00294   icp.setInputSource(source);
00295   icp.setInputTarget(target);
00296   // run the alignment
00297   icp.align(*result);
00298 
00299   // get the resulting transform
00300   Eigen::Matrix4f transform = icp.getFinalTransformation();
00301 
00302   // tanslate to a TF2 transform
00303   tf2::Matrix3x3 rotation(transform(0, 0), transform(0, 1), transform(0, 2),
00304                           transform(1, 0), transform(1, 1), transform(1, 2),
00305                           transform(2, 0), transform(2, 1), transform(2, 2));
00306   tf2::Vector3 translation(transform(0, 3), transform(1, 3), transform(2, 3));
00307   tf2::Transform tf_icp(rotation, translation);
00308   return tf_icp;
00309 }


rail_recognition
Author(s): David Kent , Russell Toris , bhetherman
autogenerated on Sun Mar 6 2016 11:39:13