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 <ros/ros.h>
00035 
00036 
00037 #include <tf/transform_datatypes.h>
00038 
00039 
00040 #include <opencv2/highgui/highgui.hpp>
00041 
00042 
00043 #include <pcl16/common/common.h>
00044 #include <pcl16/common/eigen.h>
00045 #include <pcl16/common/centroid.h>
00046 #include <pcl16/ModelCoefficients.h>
00047 #include <pcl16/sample_consensus/method_types.h>
00048 #include <pcl16/sample_consensus/model_types.h>
00049 #include <pcl16/segmentation/sac_segmentation.h>
00050 #include <pcl16/segmentation/extract_clusters.h>
00051 #include <pcl16/segmentation/segment_differences.h>
00052 #include <pcl16/segmentation/organized_multi_plane_segmentation.h>
00053 #include <pcl16/search/search.h>
00054 #include <pcl16/search/kdtree.h>
00055 #include <pcl16/filters/voxel_grid.h>
00056 #include <pcl16/filters/passthrough.h>
00057 #include <pcl16/filters/extract_indices.h>
00058 #include <pcl16/surface/concave_hull.h>
00059 #include <pcl16/registration/icp.h>
00060 #include <pcl16/registration/icp_nl.h>
00061 #include <pcl16/features/integral_image_normal.h>
00062 #include <pcl16/features/normal_3d.h>
00063 
00064 
00065 #include <sstream>
00066 
00067 #include <tabletop_pushing/point_cloud_segmentation.h>
00068 #include <tabletop_pushing/extern/Timer.hpp>
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 #define randf() static_cast<float>(rand())/RAND_MAX
00077 
00078 typedef pcl16::search::KdTree<pcl16::PointXYZ>::Ptr KdTreePtr;
00079 typedef pcl16::search::KdTree<pcl16::PointXYZ>::KdTreeFLANNPtr KdTreeFLANNPtr;
00080 using pcl16::PointXYZ;
00081 
00082 namespace tabletop_pushing
00083 {
00084 
00085 PointCloudSegmentation::PointCloudSegmentation(boost::shared_ptr<tf::TransformListener> tf) : tf_(tf)
00086 {
00087   for (int i = 0; i < 200; ++i)
00088   {
00089     cv::Vec3f rand_color;
00090     rand_color[0] = randf();
00091     rand_color[1] = randf();
00092     rand_color[2] = randf();
00093     colors_.push_back(rand_color);
00094   }
00095 }
00096 
00097 void PointCloudSegmentation::getTablePlane(XYZPointCloud& cloud, XYZPointCloud& objs_cloud, XYZPointCloud& plane_cloud,
00098                                            Eigen::Vector4f& table_centroid, bool find_hull, bool find_centroid)
00099 {
00100 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00101   long long get_table_plane_start_time = Timer::nanoTime();
00102 #endif
00103 
00104   XYZPointCloud cloud_downsampled;
00105   if (use_voxel_down_)
00106   {
00107     pcl16::VoxelGrid<PointXYZ> downsample;
00108     downsample.setInputCloud(cloud.makeShared());
00109     downsample.setLeafSize(voxel_down_res_, voxel_down_res_, voxel_down_res_);
00110     downsample.filter(cloud_downsampled);
00111   }
00112 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00113   double downsample_elapsed_time = (((double)(Timer::nanoTime() - get_table_plane_start_time)) /
00114                                   Timer::NANOSECONDS_PER_SECOND);
00115   long long filter_cloud_z_start_time = Timer::nanoTime();
00116 #endif
00117   
00118   XYZPointCloud cloud_z_filtered, cloud_filtered;
00119   pcl16::PassThrough<PointXYZ> z_pass;
00120   if (use_voxel_down_)
00121   {
00122     z_pass.setInputCloud(cloud_downsampled.makeShared());
00123   }
00124   else
00125   {
00126     z_pass.setInputCloud(cloud.makeShared());
00127   }
00128   z_pass.setFilterFieldName("z");
00129   z_pass.setFilterLimits(min_table_z_, max_table_z_);
00130   z_pass.filter(cloud_z_filtered);
00131 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00132   double filter_cloud_z_elapsed_time = (((double)(Timer::nanoTime() - filter_cloud_z_start_time)) /
00133                                   Timer::NANOSECONDS_PER_SECOND);
00134   long long filter_cloud_x_start_time = Timer::nanoTime();
00135 #endif
00136   
00137   pcl16::PassThrough<PointXYZ> x_pass;
00138   x_pass.setInputCloud(cloud_z_filtered.makeShared());
00139   x_pass.setFilterFieldName("x");
00140   x_pass.setFilterLimits(min_workspace_x_, max_workspace_x_);
00141   x_pass.filter(cloud_filtered);
00142 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00143   double filter_cloud_x_elapsed_time = (((double)(Timer::nanoTime() - filter_cloud_x_start_time)) /
00144                                   Timer::NANOSECONDS_PER_SECOND);
00145   long long RANSAC_start_time = Timer::nanoTime();
00146 #endif
00147   
00148   pcl16::ModelCoefficients coefficients;
00149   pcl16::PointIndices plane_inliers;
00150 
00151   
00152   pcl16::SACSegmentation<PointXYZ> plane_seg;
00153   plane_seg.setOptimizeCoefficients(true);
00154   
00155   plane_seg.setModelType(pcl16::SACMODEL_PERPENDICULAR_PLANE);
00156   plane_seg.setMethodType(pcl16::SAC_RANSAC);
00157   plane_seg.setDistanceThreshold(table_ransac_thresh_);
00158   plane_seg.setInputCloud(cloud_filtered.makeShared());
00159   Eigen::Vector3f z_axis(0.0, 0.0, 1.0);
00160   plane_seg.setAxis(z_axis);
00161   
00162   plane_seg.segment(plane_inliers, coefficients);
00163   pcl16::copyPointCloud(cloud_filtered, plane_inliers, plane_cloud);
00164 
00165   
00166   pcl16::ExtractIndices<PointXYZ> extract;
00167   extract.setInputCloud(cloud_filtered.makeShared());
00168   extract.setIndices(boost::make_shared<pcl16::PointIndices>(plane_inliers));
00169   extract.setNegative(true);
00170   extract.filter(objs_cloud);
00171   objs_cloud.header = cloud.header;
00172 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00173   double RANSAC_elapsed_time = (((double)(Timer::nanoTime() - RANSAC_start_time)) / Timer::NANOSECONDS_PER_SECOND);
00174   long long find_centroid_start_time = Timer::nanoTime();
00175 #endif
00176   
00177   if (find_hull)
00178   {
00179     ROS_INFO_STREAM("finding concave hull. Plane size: " <<
00180                     plane_cloud.size());
00181     XYZPointCloud hull_cloud;
00182     pcl16::ConcaveHull<PointXYZ> hull;
00183     hull.setInputCloud(plane_cloud.makeShared());
00184     hull.setAlpha(hull_alpha_);
00185     hull.reconstruct(hull_cloud);
00186     ROS_INFO_STREAM("hull_cloud.size() " << hull_cloud.size());
00187     
00188     
00189   }
00190 
00191   
00192   if (find_centroid)
00193   {
00194     pcl16::compute3DCentroid(plane_cloud, table_centroid);
00195     min_workspace_z_ = table_centroid[2];
00196   }
00197   
00198   
00199   
00200   
00201 
00202 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00203   double get_table_plane_elapsed_time = (((double)(Timer::nanoTime() - get_table_plane_start_time)) /
00204                                         Timer::NANOSECONDS_PER_SECOND);
00205   double find_centroid_elapsed_time = (((double)(Timer::nanoTime() - find_centroid_start_time)) /
00206                                        Timer::NANOSECONDS_PER_SECOND);
00207   ROS_INFO_STREAM("\t get Table Plane Elapsed Time " << get_table_plane_elapsed_time);
00208   ROS_INFO_STREAM("\t\t downsample Elapsed Time " << downsample_elapsed_time);
00209   ROS_INFO_STREAM("\t\t filter Z Elapsed Time " << filter_cloud_z_elapsed_time);
00210   ROS_INFO_STREAM("\t\t filter X Elapsed Time " << filter_cloud_x_elapsed_time);
00211   ROS_INFO_STREAM("\t\t RANSAC Elapsed Time " << RANSAC_elapsed_time);
00212   ROS_INFO_STREAM("\t\t find Centroid Elapsed Time " << find_centroid_elapsed_time);
00213 #endif
00214 
00215 }
00216 
00217 void PointCloudSegmentation::getTablePlaneMPS(XYZPointCloud& input_cloud, XYZPointCloud& objs_cloud,
00218                                               XYZPointCloud& plane_cloud, Eigen::Vector4f& center,
00219                                               bool find_hull, bool find_centroid)
00220 {
00221   pcl16::IntegralImageNormalEstimation<PointXYZ, pcl16::Normal> ne;
00222   ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);
00223   ne.setMaxDepthChangeFactor(0.03f);
00224   ne.setNormalSmoothingSize(20.0f);
00225   pcl16::PointCloud<pcl16::Normal>::Ptr normal_cloud(new pcl16::PointCloud<pcl16::Normal>);
00226   ne.setInputCloud(input_cloud.makeShared());
00227   ne.compute(*normal_cloud);
00228 
00229   
00230   
00231   
00232   
00233   
00234   
00235   
00236   
00237   
00238   
00239   
00240   
00241 
00242   pcl16::OrganizedMultiPlaneSegmentation<PointXYZ, pcl16::Normal, pcl16::Label> mps;
00243   mps.setMinInliers(mps_min_inliers_);
00244   mps.setAngularThreshold(mps_min_angle_thresh_*M_PI/180.);
00245   mps.setDistanceThreshold(mps_min_dist_thresh_);
00246   mps.setInputNormals(normal_cloud);
00247   mps.setInputCloud(input_cloud.makeShared());
00248   std::vector<pcl16::PlanarRegion<PointXYZ>,
00249               Eigen::aligned_allocator<pcl16::PlanarRegion<PointXYZ> > > regions;
00250   regions.clear();
00251   std::vector<pcl16::ModelCoefficients> coefficients;
00252   std::vector<pcl16::PointIndices> point_indices;
00253   pcl16::PointCloud<pcl16::Label>::Ptr labels(new pcl16::PointCloud<pcl16::Label>());
00254   std::vector<pcl16::PointIndices> label_indices;
00255   std::vector<pcl16::PointIndices> boundary_indices;
00256   point_indices.clear();
00257   label_indices.clear();
00258   boundary_indices.clear();
00259   mps.segmentAndRefine(regions, coefficients, point_indices, labels, label_indices, boundary_indices);
00260 
00261   
00262 
00263   
00264   if (regions.size() > 0)
00265   {
00266     pcl16::copyPointCloud(input_cloud, point_indices[0], plane_cloud);
00267     center[0] = regions[0].getCentroid()[0];
00268     center[1] = regions[0].getCentroid()[1];
00269     center[2] = regions[0].getCentroid()[2];
00270     center[3] = 1.0;
00271 
00272     
00273     pcl16::ExtractIndices<PointXYZ> extract;
00274     extract.setInputCloud(input_cloud.makeShared());
00275     extract.setIndices(boost::make_shared<pcl16::PointIndices>(point_indices[0]));
00276     extract.setNegative(true);
00277     extract.filter(objs_cloud);
00278   }
00279   
00280   
00281   
00282   
00283   
00284   
00285   
00286   
00287   
00288   
00289   
00290 }
00291 
00292 
00301 void PointCloudSegmentation::findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs, bool use_mps)
00302 {
00303   XYZPointCloud objs_cloud;
00304   findTabletopObjects(input_cloud, objs, objs_cloud, use_mps);
00305 }
00306 
00316 void PointCloudSegmentation::findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs,
00317                                                  XYZPointCloud& objs_cloud, bool use_mps)
00318 {
00319   XYZPointCloud table_cloud;
00320   findTabletopObjects(input_cloud, objs, objs_cloud, table_cloud, use_mps);
00321 }
00322 
00333 void PointCloudSegmentation::findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs,
00334                                                  XYZPointCloud& objs_cloud,
00335                                                  XYZPointCloud& plane_cloud, bool use_mps)
00336 {
00337 #ifdef PROFILE_OBJECT_SEGMENTATION_TIME
00338   long long find_tabletop_objects_start_time = Timer::nanoTime();
00339 #endif
00340 
00341   
00342   if (use_mps)
00343   {
00344     getTablePlaneMPS(input_cloud, objs_cloud, plane_cloud, table_centroid_, false);
00345   }
00346   else
00347   {
00348     getTablePlane(input_cloud, objs_cloud, plane_cloud, table_centroid_, false);
00349   }
00350 
00351 #ifdef PROFILE_OBJECT_SEGMENTATION_TIME
00352   double segment_table_elapsed_time = (((double)(Timer::nanoTime() - find_tabletop_objects_start_time)) /
00353                                     Timer::NANOSECONDS_PER_SECOND);
00354   long long cluster_objects_start_time = Timer::nanoTime();
00355 #endif
00356 
00357   
00358   
00359   
00360   XYZPointCloud objects_cloud_down;
00361   downsampleCloud(objs_cloud, objects_cloud_down);
00362   
00363   if (objects_cloud_down.size() > 0)
00364   {
00365     clusterProtoObjects(objects_cloud_down, objs);
00366   }
00367   
00368 #ifdef PROFILE_OBJECT_SEGMENTATION_TIME
00369   double find_tabletop_objects_elapsed_time = (((double)(Timer::nanoTime() - find_tabletop_objects_start_time)) /
00370                                            Timer::NANOSECONDS_PER_SECOND);
00371   double cluster_objects_elapsed_time = (((double)(Timer::nanoTime() - cluster_objects_start_time)) /
00372                                       Timer::NANOSECONDS_PER_SECOND);
00373   ROS_INFO_STREAM("find_tabletop_objects_elapsed_time " << find_tabletop_objects_elapsed_time);
00374   if (use_mps)
00375   {
00376     ROS_INFO_STREAM("\t segment Table MPS Time " << segment_table_elapsed_time);
00377   }
00378   else
00379   {
00380     ROS_INFO_STREAM("\t segment table RANSAC Time " << segment_table_elapsed_time);
00381   }
00382   ROS_INFO_STREAM("\t cluster_objects_elapsed_time " << cluster_objects_elapsed_time << "\n");
00383 #endif
00384 
00385 }
00386 
00393 void PointCloudSegmentation::clusterProtoObjects(XYZPointCloud& objects_cloud, ProtoObjects& objs)
00394 {
00395 #ifdef PROFILE_OBJECT_CLUSTER_TIME
00396   long long cluster_objects_start_time = Timer::nanoTime();
00397 #endif
00398   std::vector<pcl16::PointIndices> clusters;
00399   pcl16::EuclideanClusterExtraction<PointXYZ> pcl_cluster;
00400   const KdTreePtr clusters_tree(new pcl16::search::KdTree<PointXYZ>);
00401   clusters_tree->setInputCloud(objects_cloud.makeShared());
00402 
00403   pcl_cluster.setClusterTolerance(cluster_tolerance_);
00404   pcl_cluster.setMinClusterSize(min_cluster_size_);
00405   pcl_cluster.setMaxClusterSize(max_cluster_size_);
00406   pcl_cluster.setSearchMethod(clusters_tree);
00407   pcl_cluster.setInputCloud(objects_cloud.makeShared());
00408   pcl_cluster.extract(clusters);
00409   ROS_DEBUG_STREAM("Number of clusters found matching the given constraints: "
00410                    << clusters.size());
00411 #ifdef PROFILE_OBJECT_CLUSTER_TIME
00412   double pcl_cluster_elapsed_time = (((double)(Timer::nanoTime() - cluster_objects_start_time)) /
00413                                      Timer::NANOSECONDS_PER_SECOND);
00414   long long proto_object_start_time = Timer::nanoTime();
00415 #endif
00416 
00417   for (unsigned int i = 0; i < clusters.size(); ++i)
00418   {
00419     
00420     ProtoObject po;
00421     po.push_history.clear();
00422     po.boundary_angle_dist.clear();
00423     pcl16::copyPointCloud(objects_cloud, clusters[i], po.cloud);
00424     pcl16::compute3DCentroid(po.cloud, po.centroid);
00425     po.id = i;
00426     po.moved = false;
00427     po.transform = Eigen::Matrix4f::Identity();
00428     po.singulated = false;
00429     objs.push_back(po);
00430   }
00431 #ifdef PROFILE_OBJECT_CLUSTER_TIME
00432   double cluster_objects_elapsed_time = (((double)(Timer::nanoTime() - cluster_objects_start_time)) /
00433                                          Timer::NANOSECONDS_PER_SECOND);
00434   double proto_object_elapsed_time = (((double)(Timer::nanoTime() - proto_object_start_time)) /
00435                                       Timer::NANOSECONDS_PER_SECOND);
00436   ROS_INFO_STREAM("\t cluster_objects_elapsed_time " << cluster_objects_elapsed_time);
00437   ROS_INFO_STREAM("\t\t pcl_cluster_elapsed_time " << pcl_cluster_elapsed_time);
00438   ROS_INFO_STREAM("\t\t proto_object_elapsed_time " << proto_object_elapsed_time);
00439 #endif
00440 
00441 }
00442 
00451 double PointCloudSegmentation::ICPProtoObjects(ProtoObject& a, ProtoObject& b,
00452                                                Eigen::Matrix4f& transform)
00453 {
00454   
00455   
00456   pcl16::IterativeClosestPoint<PointXYZ, PointXYZ> icp;
00457   icp.setMaximumIterations(icp_max_iters_);
00458   icp.setTransformationEpsilon(icp_transform_eps_);
00459   icp.setMaxCorrespondenceDistance(icp_max_cor_dist_);
00460   icp.setRANSACOutlierRejectionThreshold(icp_ransac_thresh_);
00461   icp.setInputCloud(boost::make_shared<XYZPointCloud>(a.cloud));
00462   icp.setInputTarget(boost::make_shared<XYZPointCloud>(b.cloud));
00463   XYZPointCloud aligned;
00464   icp.align(aligned);
00465   double score = icp.getFitnessScore();
00466   transform = icp.getFinalTransformation();
00467   return score;
00468 }
00469 
00479 double PointCloudSegmentation::ICPBoundarySamples(XYZPointCloud& hull_t_0, XYZPointCloud& hull_t_1,
00480                                                   Eigen::Matrix4f& transform, XYZPointCloud& aligned)
00481 {
00482   
00483   pcl16::IterativeClosestPointNonLinear<PointXYZ, PointXYZ> icp;
00484   
00485   icp.setMaximumIterations(icp_max_iters_);
00486   icp.setTransformationEpsilon(icp_transform_eps_);
00487   icp.setMaxCorrespondenceDistance(icp_max_cor_dist_);
00488   icp.setRANSACOutlierRejectionThreshold(icp_ransac_thresh_);
00489   icp.setInputCloud(boost::make_shared<XYZPointCloud>(hull_t_0));
00490   icp.setInputTarget(boost::make_shared<XYZPointCloud>(hull_t_1));
00491   icp.align(aligned);
00492   double score = icp.getFitnessScore();
00493   transform = icp.getFinalTransformation();
00494   return score;
00495 }
00496 
00505 void PointCloudSegmentation::getMovedRegions(XYZPointCloud& prev_cloud, XYZPointCloud& cur_cloud,
00506                                              ProtoObjects& moved, std::string suf)
00507 {
00508   
00509   pcl16::SegmentDifferences<PointXYZ> pcl_diff;
00510   pcl_diff.setDistanceThreshold(cloud_diff_thresh_);
00511   pcl_diff.setInputCloud(prev_cloud.makeShared());
00512   pcl_diff.setTargetCloud(cur_cloud.makeShared());
00513   XYZPointCloud cloud_out;
00514   pcl_diff.segment(cloud_out);
00515   if (cloud_out.size() < 1)
00516   {
00517     ROS_INFO_STREAM("Returning nothing moved as there are no points.");
00518     return;
00519   }
00520 
00521   clusterProtoObjects(cloud_out, moved);
00522 
00523 #ifdef DISPLAY_CLOUD_DIFF
00524   cv::Size img_size(320, 240);
00525   cv::Mat moved_img = projectProtoObjectsIntoImage(moved, img_size, prev_cloud.header.frame_id);
00526   std::stringstream cluster_title;
00527   cluster_title << "moved clusters" << suf;
00528   displayObjectImage(moved_img, cluster_title.str());
00529 #endif // DISPLAY_CLOUD_DIFF
00530 }
00531 
00539 void PointCloudSegmentation::matchMovedRegions(ProtoObjects& objs,
00540                                                ProtoObjects& moved_regions)
00541 {
00542   
00543   for (unsigned int i = 0; i < moved_regions.size(); ++i)
00544   {
00545     for (unsigned int j = 0; j < objs.size(); ++j)
00546     {
00547       if(cloudsIntersect(objs[j].cloud, moved_regions[i].cloud))
00548       {
00549         if (!objs[j].moved)
00550         {
00551           objs[j].moved = true;
00552         }
00553       }
00554     }
00555   }
00556 }
00557 
00565 void PointCloudSegmentation::fitCylinderRANSAC(ProtoObject& obj, XYZPointCloud& cylinder_cloud,
00566                                                pcl16::ModelCoefficients& coefficients)
00567 {
00568   pcl16::NormalEstimation<PointXYZ, pcl16::Normal> ne;
00569   ne.setInputCloud(obj.cloud.makeShared());
00570   pcl16::search::KdTree<PointXYZ>::Ptr tree (new pcl16::search::KdTree<PointXYZ> ());
00571   ne.setSearchMethod (tree);
00572   ne.setRadiusSearch (0.03);
00573   ne.compute(obj.normals);
00574 
00575   
00576   Eigen::Vector3f z_axis(0.0,0.0,1.0);
00577   pcl16::PointIndices cylinder_inliers;
00578   pcl16::SACSegmentationFromNormals<PointXYZ,pcl16::Normal> cylinder_seg;
00579   cylinder_seg.setOptimizeCoefficients(optimize_cylinder_coefficients_);
00580   cylinder_seg.setModelType(pcl16::SACMODEL_CYLINDER);
00581   cylinder_seg.setMethodType(pcl16::SAC_RANSAC);
00582   cylinder_seg.setDistanceThreshold(cylinder_ransac_thresh_);
00583   cylinder_seg.setAxis(z_axis);
00584   
00585   cylinder_seg.setInputCloud(obj.cloud.makeShared());
00586   cylinder_seg.setInputNormals(obj.normals.makeShared());
00587   cylinder_seg.segment(cylinder_inliers, coefficients);
00588 
00589   pcl16::copyPointCloud(obj.cloud, cylinder_inliers, cylinder_cloud);
00590 }
00591 
00599 void PointCloudSegmentation::fitSphereRANSAC(ProtoObject& obj, XYZPointCloud& sphere_cloud,
00600                                              pcl16::ModelCoefficients& coefficients)
00601 {
00602   
00603   pcl16::PointIndices sphere_inliers;
00604   pcl16::SACSegmentation<PointXYZ> sphere_seg;
00605   sphere_seg.setOptimizeCoefficients(true);
00606   sphere_seg.setModelType(pcl16::SACMODEL_SPHERE);
00607   sphere_seg.setMethodType(pcl16::SAC_RANSAC);
00608   sphere_seg.setDistanceThreshold(sphere_ransac_thresh_);
00609   sphere_seg.setInputCloud(obj.cloud.makeShared());
00610   sphere_seg.segment(sphere_inliers, coefficients);
00611 
00612   pcl16::copyPointCloud(obj.cloud, sphere_inliers, sphere_cloud);
00613 }
00614 
00625 bool PointCloudSegmentation::cloudsIntersect(XYZPointCloud cloud0, XYZPointCloud cloud1)
00626 {
00627   int moved_count = 0;
00628   for (unsigned int i = 0; i < cloud0.size(); ++i)
00629   {
00630     const PointXYZ pt0 = cloud0.at(i);
00631     for (unsigned int j = 0; j < cloud1.size(); ++j)
00632     {
00633       const PointXYZ pt1 = cloud1.at(j);
00634       if (dist(pt0, pt1) < cloud_intersect_thresh_)
00635       {
00636         moved_count++;
00637       }
00638       if (moved_count > moved_count_thresh_)
00639       {
00640         return true;
00641       }
00642     }
00643   }
00644   return false;
00645 }
00646 
00647 bool PointCloudSegmentation::cloudsIntersect(XYZPointCloud cloud0, XYZPointCloud cloud1, double thresh)
00648 {
00649   for (unsigned int i = 0; i < cloud0.size(); ++i)
00650   {
00651     const PointXYZ pt0 = cloud0.at(i);
00652     for (unsigned int j = 0; j < cloud1.size(); ++j)
00653     {
00654       const PointXYZ pt1 = cloud1.at(j);
00655       if (dist(pt0, pt1) < thresh) return true;
00656     }
00657   }
00658   return false;
00659 }
00660 
00661 bool PointCloudSegmentation::pointIntersectsCloud(XYZPointCloud cloud, geometry_msgs::Point pt, double thresh)
00662 {
00663   for (unsigned int i = 0; i < cloud.size(); ++i)
00664   {
00665     const PointXYZ pt_c = cloud.at(i);
00666     if (dist(pt_c, pt) < thresh) return true;
00667   }
00668   return false;
00669 }
00670 
00671 float PointCloudSegmentation::pointLineXYDist(PointXYZ p, Eigen::Vector3f vec, Eigen::Vector4f base)
00672 {
00673   Eigen::Vector3f x0(p.x,p.y,0.0);
00674   Eigen::Vector3f x1(base[0],base[1],0.0);
00675   Eigen::Vector3f x2 = x1+vec;
00676   Eigen::Vector3f num = (x0 - x1);
00677   num = num.cross(x0 - x2);
00678   Eigen::Vector3f den = x2 - x1;
00679   float d = num.norm()/den.norm();
00680   return d;
00681 }
00682 
00683 void PointCloudSegmentation::lineCloudIntersection(XYZPointCloud& cloud, Eigen::Vector3f vec,
00684                                                    Eigen::Vector4f base, XYZPointCloud& line_cloud)
00685 {
00686   
00687   
00688   
00689   pcl16::PointIndices line_inliers;
00690   for (unsigned int i = 0; i < cloud.size(); ++i)
00691   {
00692     const PointXYZ pt = cloud.at(i);
00693     if (pointLineXYDist(pt, vec, base) < cloud_intersect_thresh_)
00694     {
00695       line_inliers.indices.push_back(i);
00696     }
00697   }
00698 
00699   
00700   pcl16::ExtractIndices<PointXYZ> extract;
00701   extract.setInputCloud(cloud.makeShared());
00702   extract.setIndices(boost::make_shared<pcl16::PointIndices>(line_inliers));
00703   extract.filter(line_cloud);
00704 }
00705 
00706 void PointCloudSegmentation::lineCloudIntersectionEndPoints(XYZPointCloud& cloud, Eigen::Vector3f vec,
00707                                                             Eigen::Vector4f base, std::vector<PointXYZ>& points)
00708 {
00709   XYZPointCloud intersection;
00710   lineCloudIntersection(cloud, vec, base, intersection);
00711   unsigned int min_y_idx = intersection.size();
00712   unsigned int max_y_idx = intersection.size();
00713   unsigned int min_x_idx = intersection.size();
00714   unsigned int max_x_idx = intersection.size();
00715   float min_y = FLT_MAX;
00716   float max_y = -FLT_MAX;
00717   float min_x = FLT_MAX;
00718   float max_x = -FLT_MAX;
00719   for (unsigned int i = 0; i < intersection.size(); ++i)
00720   {
00721     if (intersection.at(i).y < min_y)
00722     {
00723       min_y = intersection.at(i).y;
00724       min_y_idx = i;
00725     }
00726     if (intersection.at(i).y > max_y)
00727     {
00728       max_y = intersection.at(i).y;
00729       max_y_idx = i;
00730     }
00731     if (intersection.at(i).x < min_x)
00732     {
00733       min_x = intersection.at(i).x;
00734       min_x_idx = i;
00735     }
00736     if (intersection.at(i).x > max_x)
00737     {
00738       max_x = intersection.at(i).x;
00739       max_x_idx = i;
00740     }
00741   }
00742   const double y_dist_obs = max_y - min_y;
00743   const double x_dist_obs = max_x - min_x;
00744   int start_idx = min_x_idx;
00745   int end_idx = max_x_idx;
00746 
00747   if (x_dist_obs > y_dist_obs)
00748   {
00749     
00750     if (vec[0] > 0)
00751     {
00752       
00753       start_idx = min_x_idx;
00754       end_idx = max_x_idx;
00755     }
00756     else
00757     {
00758       
00759       start_idx = max_x_idx;
00760       end_idx = min_x_idx;
00761     }
00762   }
00763   else
00764   {
00765     
00766     if (vec[1] > 0)
00767     {
00768       
00769       start_idx = min_y_idx;
00770       end_idx = max_y_idx;
00771     }
00772     else
00773     {
00774       
00775       start_idx = max_y_idx;
00776       end_idx = min_y_idx;
00777     }
00778   }
00779   PointXYZ start_point, end_point;
00780   start_point.x = intersection.at(start_idx).x;
00781   start_point.y = intersection.at(start_idx).y;
00782   start_point.z = intersection.at(start_idx).z;
00783   end_point.x = intersection.at(end_idx).x;
00784   end_point.y = intersection.at(end_idx).y;
00785   end_point.z = intersection.at(end_idx).z;
00786   points.push_back(start_point);
00787   points.push_back(end_point);
00788 }
00789 
00798 void PointCloudSegmentation::downsampleCloud(XYZPointCloud& cloud_in, XYZPointCloud& cloud_down)
00799 {
00800   XYZPointCloud cloud_z_filtered, cloud_x_filtered;
00801   pcl16::PassThrough<PointXYZ> z_pass;
00802   z_pass.setFilterFieldName("z");
00803   ROS_DEBUG_STREAM("Number of points in cloud_in is: " <<
00804                    cloud_in.size());
00805   z_pass.setInputCloud(cloud_in.makeShared());
00806   z_pass.setFilterLimits(min_workspace_z_, max_workspace_z_);
00807   z_pass.filter(cloud_z_filtered);
00808   ROS_DEBUG_STREAM("Number of points in cloud_z_filtered is: " <<
00809                    cloud_z_filtered.size());
00810 
00811   pcl16::PassThrough<PointXYZ> x_pass;
00812   x_pass.setInputCloud(cloud_z_filtered.makeShared());
00813   x_pass.setFilterFieldName("x");
00814   x_pass.setFilterLimits(min_workspace_x_, max_workspace_x_);
00815   x_pass.filter(cloud_x_filtered);
00816 
00817   pcl16::VoxelGrid<PointXYZ> downsample_outliers;
00818   downsample_outliers.setInputCloud(cloud_x_filtered.makeShared());
00819   downsample_outliers.setLeafSize(voxel_down_res_, voxel_down_res_,
00820                                   voxel_down_res_);
00821   downsample_outliers.filter(cloud_down);
00822   ROS_DEBUG_STREAM("Number of points in objs_downsampled: " <<
00823                    cloud_down.size());
00824 }
00825 
00835 cv::Mat PointCloudSegmentation::projectProtoObjectsIntoImage(ProtoObjects& objs, cv::Size img_size,
00836                                                              std::string target_frame)
00837 {
00838   cv::Mat obj_img(img_size, CV_8UC1, cv::Scalar(0));
00839   for (unsigned int i = 0; i < objs.size(); ++i)
00840   {
00841     projectPointCloudIntoImage(objs[i].cloud, obj_img,
00842                                cur_camera_header_.frame_id, i+1);
00843   }
00844 
00845   return obj_img;
00846 }
00847 
00857 cv::Mat PointCloudSegmentation::projectProtoObjectIntoImage(ProtoObject& obj, cv::Size img_size,
00858                                                             std::string target_frame)
00859 {
00860   cv::Mat obj_img(img_size, CV_8UC1, cv::Scalar(0));
00861   projectPointCloudIntoImage(obj.cloud, obj_img, cur_camera_header_.frame_id, 1);
00862   return obj_img;
00863 }
00864 
00871 cv::Mat PointCloudSegmentation::displayObjectImage(cv::Mat& obj_img,
00872                                                    std::string win_name,
00873                                                    bool use_display)
00874 {
00875   cv::Mat obj_disp_img(obj_img.size(), CV_32FC3, cv::Scalar(0.0,0.0,0.0));
00876   for (int r = 0; r < obj_img.rows; ++r)
00877   {
00878     for (int c = 0; c < obj_img.cols; ++c)
00879     {
00880       unsigned int id = obj_img.at<uchar>(r,c);
00881       if (id > 0)
00882       {
00883         obj_disp_img.at<cv::Vec3f>(r,c) = colors_[id-1];
00884       }
00885     }
00886   }
00887   if (use_display)
00888   {
00889     cv::imshow(win_name, obj_disp_img);
00890   }
00891   return obj_disp_img;
00892 }
00893 
00894 void PointCloudSegmentation::projectPointCloudIntoImage(XYZPointCloud& cloud,
00895                                                         cv::Mat& lbl_img,
00896                                                         std::string target_frame,
00897                                                         unsigned int id)
00898 {
00899   for (unsigned int i = 0; i < cloud.size(); ++i)
00900   {
00901     cv::Point img_idx = projectPointIntoImage(cloud.at(i),
00902                                               cloud.header.frame_id,
00903                                               target_frame);
00904     lbl_img.at<uchar>(img_idx.y, img_idx.x) = id;
00905   }
00906 }
00907 
00908 cv::Point PointCloudSegmentation::projectPointIntoImage(Eigen::Vector3f cur_point_eig,
00909                                                         std::string point_frame,
00910                                                         std::string target_frame)
00911 {
00912   geometry_msgs::PointStamped cur_point;
00913   cur_point.header.frame_id = point_frame;
00914   cur_point.point.x = cur_point_eig[0];
00915   cur_point.point.y = cur_point_eig[1];
00916   cur_point.point.z = cur_point_eig[2];
00917   return projectPointIntoImage(cur_point, target_frame);
00918 }
00919 
00920 cv::Point PointCloudSegmentation::projectPointIntoImage(PointXYZ cur_point_pcl,
00921                                                         std::string point_frame,
00922                                                         std::string target_frame)
00923 {
00924   geometry_msgs::PointStamped cur_point;
00925   cur_point.header.frame_id = point_frame;
00926   cur_point.point.x = cur_point_pcl.x;
00927   cur_point.point.y = cur_point_pcl.y;
00928   cur_point.point.z = cur_point_pcl.z;
00929   return projectPointIntoImage(cur_point, target_frame);
00930 }
00931 
00932 void PointCloudSegmentation::projectPointCloudIntoImage(XYZPointCloud& cloud,
00933                                                         cv::Mat& lbl_img)
00934 {
00935   for (unsigned int i = 0; i < cloud.size(); ++i)
00936   {
00937     cv::Point img_idx = projectPointIntoImage(cloud.at(i),
00938                                               cloud.header.frame_id,
00939                                               cur_camera_header_.frame_id);
00940     lbl_img.at<uchar>(img_idx.y, img_idx.x) = 1;
00941   }
00942 }
00943 
00944 cv::Point PointCloudSegmentation::projectPointIntoImage(
00945     geometry_msgs::PointStamped cur_point)
00946 {
00947   return projectPointIntoImage(cur_point, cur_camera_header_.frame_id);
00948 }
00949 
00950 cv::Point PointCloudSegmentation::projectPointIntoImage(
00951     geometry_msgs::PointStamped cur_point, std::string target_frame)
00952 {
00953   cv::Point img_loc;
00954   try
00955   {
00956     
00957     geometry_msgs::PointStamped image_frame_loc_m;
00958     tf_->transformPoint(target_frame, cur_point, image_frame_loc_m);
00959 
00960     
00961     img_loc.x = static_cast<int>((cam_info_.K[0]*image_frame_loc_m.point.x +
00962                                   cam_info_.K[2]*image_frame_loc_m.point.z) /
00963                                  image_frame_loc_m.point.z);
00964     img_loc.y = static_cast<int>((cam_info_.K[4]*image_frame_loc_m.point.y +
00965                                   cam_info_.K[5]*image_frame_loc_m.point.z) /
00966                                  image_frame_loc_m.point.z);
00967 
00968     
00969     for (int i = 0; i < num_downsamples_; ++i)
00970     {
00971       img_loc.x /= 2;
00972       img_loc.y /= 2;
00973     }
00974   }
00975   catch (tf::TransformException e)
00976   {
00977     ROS_ERROR_STREAM("Error projecting 3D point into image plane.");
00978     
00979     ROS_ERROR_STREAM("cur point header is: " << cur_point.header.frame_id);
00980     ROS_ERROR_STREAM("target frame is: " << target_frame);
00981   }
00982   return img_loc;
00983 }
00984 
00985 };