surface_segmentation.cpp
Go to the documentation of this file.
00001 #include <numeric>
00002 #include <ros/ros.h>
00003 #include <algorithm>
00004 
00005 #include "sensor_msgs/PointCloud2.h"
00006 #include <pcl/features/normal_3d.h>
00007 #include <pcl/kdtree/kdtree_flann.h>
00008 #include <pcl/point_types.h>
00009 #include <pcl_ros/point_cloud.h>
00010 #include <pcl/point_cloud.h>
00011 #include <pcl/features/principal_curvatures.h>
00012 #include <pcl/segmentation/extract_clusters.h>
00013 #include <pcl/filters/passthrough.h>
00014 #include <pcl/sample_consensus/method_types.h>
00015 #include <pcl/sample_consensus/model_types.h>
00016 #include <pcl/segmentation/sac_segmentation.h>
00017 #include <pcl/surface/mls.h>
00018 #include <pcl/surface/convex_hull.h>
00019 #include <pcl/filters/project_inliers.h>
00020 #include <pcl/filters/voxel_grid.h>
00021 
00022 #include <tf/transform_listener.h>
00023 #include "pcl_ros/transforms.h"
00024 #include <boost/make_shared.hpp>
00025 #include <boost/thread/mutex.hpp>
00026 #include <cv_bridge/cv_bridge.h>
00027 #include <opencv/cv.h>
00028 #include <opencv2/imgproc/imgproc.hpp>
00029 #include <opencv2/highgui/highgui.hpp>
00030 #include <image_transport/image_transport.h>
00031 #include <sensor_msgs/image_encodings.h>
00032 #include <geometry_msgs/PoseArray.h>
00033 #include <geometry_msgs/PolygonStamped.h>
00034 #include <geometry_msgs/Point.h>
00035 #include <visualization_msgs/Marker.h>
00036 #include <hrl_table_detect/DetectTableStart.h>
00037 #include <hrl_table_detect/DetectTableStop.h>
00038 #include <hrl_table_detect/DetectTableInst.h>
00039 #include <hrl_table_detect/SegmentSurfaces.h>
00040 #include <LinearMath/btMatrix3x3.h>
00041 #include <LinearMath/btQuaternion.h>
00042 #include <std_srvs/Empty.h>
00043 
00044 using namespace sensor_msgs;
00045 using namespace std;
00046 namespace enc = sensor_msgs::image_encodings;
00047 namespace hrl_table_detect {
00048     
00049     typedef pcl::PointXYZRGB PRGB;
00050     typedef pcl::PointXYZRGBNormal PRGBN;
00051 
00052     class SurfaceSegmentation {
00053         public:
00054             ros::Subscriber pc_sub, cam_sub;
00055             ros::NodeHandle nh;
00056             ros::Publisher pc_pub, pc_pub2, pc_pub3, poly_pub;
00057             ros::ServiceServer get_pc_srv, get_table_srv;
00058             tf::TransformListener tf_listener;
00059             pcl::PointCloud<PRGB> accum_pc;
00060             geometry_msgs::PoseArray grasp_points;
00061             bool pc_captured, do_capture;
00062 
00063             SurfaceSegmentation();
00064             void onInit();
00065             void pcCallback(sensor_msgs::PointCloud2::ConstPtr pc_msg);
00066             bool captureCallback(std_srvs::EmptyRequest& req, std_srvs::EmptyResponse& resp);
00067             bool surfSegCallback(hrl_table_detect::SegmentSurfaces::Request& req, 
00068                                  hrl_table_detect::SegmentSurfaces::Response& resp);
00069     };
00070 
00071     SurfaceSegmentation::SurfaceSegmentation() {
00072     }
00073 
00074     void SurfaceSegmentation::onInit() {
00075         pc_pub = nh.advertise<pcl::PointCloud<PRGB> >("normal_vis", 1);
00076         pc_pub2 = nh.advertise<pcl::PointCloud<PRGB> >("normal_vis2", 1);
00077         pc_pub3 = nh.advertise<pcl::PointCloud<PRGB> >("normal_vis3", 1);
00078         poly_pub = nh.advertise<visualization_msgs::Marker>("table_hull", 1);
00079         pc_sub = nh.subscribe("/kinect_head/rgb/points", 1, &SurfaceSegmentation::pcCallback, this);
00080         get_pc_srv = nh.advertiseService("surf_seg_capture_pc", &SurfaceSegmentation::captureCallback, this);
00081         get_table_srv = nh.advertiseService("segment_surfaces", &SurfaceSegmentation::surfSegCallback, this);
00082         pc_captured = false; do_capture = false;
00083         ros::Duration(1.0).sleep();
00084     }
00085 
00086     bool SurfaceSegmentation::captureCallback(std_srvs::EmptyRequest& req, std_srvs::EmptyResponse& resp) {
00087         pc_captured = false; do_capture = true;
00088         ros::Rate r(100);
00089         double start_time = ros::Time::now().toSec();
00090         while(ros::ok() && !pc_captured && ros::Time::now().toSec() - start_time < 1) {
00091             ros::spinOnce();
00092             r.sleep();
00093         }
00094         do_capture = false;
00095         return true;
00096     }
00097 
00098     void SurfaceSegmentation::pcCallback(sensor_msgs::PointCloud2::ConstPtr pc_msg) {
00099         if(!(do_capture && !pc_captured))
00100             return;
00101         pcl::PointCloud<PRGB>::Ptr pc_full_ptr(new pcl::PointCloud<PRGB>());
00102         pcl::fromROSMsg(*pc_msg, *pc_full_ptr);
00103         if(accum_pc.points.size() == 0)
00104             accum_pc = *pc_full_ptr;
00105         else
00106             accum_pc += *pc_full_ptr;
00107         pc_captured = true;
00108     }
00109 
00110     bool SurfaceSegmentation::surfSegCallback(
00111                      hrl_table_detect::SegmentSurfaces::Request& req, 
00112                      hrl_table_detect::SegmentSurfaces::Response& resp) {
00113         double min_z_val = 0.5, max_z_val = 1.5;
00114         double norm_ang_thresh = 0.7;
00115         //double surf_clust_dist = 0.03, surf_clust_min_size = 50;
00116         double surf_clust_dist = 0.05, surf_clust_min_size = 600;
00117 
00118         pcl::PointCloud<PRGB>::Ptr pc_full_frame_ptr(new pcl::PointCloud<PRGB>());
00119         string base_frame("/base_link");
00120         ros::Time now = ros::Time::now();
00121         accum_pc.header.stamp = now;
00122 
00123         // Transform PC to base frame
00124         tf_listener.waitForTransform(accum_pc.header.frame_id, base_frame, now, ros::Duration(3.0));
00125         pcl_ros::transformPointCloud(base_frame, accum_pc, *pc_full_frame_ptr, tf_listener);
00126 
00127         sensor_msgs::PointCloud2::Ptr pc2_full_frame_ptr(new sensor_msgs::PointCloud2());
00128         sensor_msgs::PointCloud2::Ptr pc2_downsampled_ptr(new sensor_msgs::PointCloud2());
00129         pcl::toROSMsg(*pc_full_frame_ptr, *pc2_full_frame_ptr);
00130         pcl::PointCloud<PRGB>::Ptr pc_downsampled_ptr(new pcl::PointCloud<PRGB>());
00131         pcl::VoxelGrid<sensor_msgs::PointCloud2> vox_grid;
00132         vox_grid.setInputCloud(pc2_full_frame_ptr);
00133         vox_grid.setLeafSize(0.01, 0.01, 0.01);
00134         vox_grid.filter(*pc2_downsampled_ptr);
00135         pcl::fromROSMsg(*pc2_downsampled_ptr, *pc_downsampled_ptr);
00136         pc_pub.publish(*pc2_downsampled_ptr);
00137 
00138         // Filter floor and ceiling
00139         pcl::PointCloud<PRGB>::Ptr pc_filtered_ptr(new pcl::PointCloud<PRGB>());
00140         pcl::PassThrough<PRGB> z_filt;
00141         z_filt.setFilterFieldName("z");
00142         z_filt.setFilterLimits(min_z_val, max_z_val);
00143         //z_filt.setInputCloud(pc_full_frame_ptr);
00144         z_filt.setInputCloud(pc_downsampled_ptr);
00145         z_filt.filter(*pc_filtered_ptr);
00146 
00147         if(pc_filtered_ptr->size() < 20)
00148             return false;
00149 
00150         // Compute normals
00151         pcl::PointCloud<pcl::Normal>::Ptr cloud_normals_ptr(new pcl::PointCloud<pcl::Normal>());
00152         pcl::KdTree<PRGB>::Ptr normals_tree (new pcl::KdTreeFLANN<PRGB> ());
00153         pcl::PointCloud<PRGB> mls_points;
00154         pcl::MovingLeastSquares<PRGB, pcl::Normal> mls;
00155         normals_tree->setInputCloud(pc_filtered_ptr);
00156         mls.setOutputNormals(cloud_normals_ptr);
00157         mls.setInputCloud(pc_filtered_ptr);
00158         mls.setPolynomialFit(true);
00159         mls.setSearchMethod(normals_tree);
00160         mls.setSearchRadius(0.05);
00161         mls.reconstruct(mls_points);
00162         
00163         /*pcl::NormalEstimation<PRGB, pcl::Normal> norm_est;
00164         norm_est.setKSearch(15);
00165         norm_est.setSearchMethod(normals_tree);
00166         norm_est.setInputCloud(pc_filtered_ptr);
00167         norm_est.compute(*cloud_normals_ptr);
00168         */
00169         
00170         pcl::PointIndices::Ptr flat_inds_ptr (new pcl::PointIndices());
00171         double ang;
00172         int i = 0;
00173         BOOST_FOREACH(const pcl::Normal& pt, cloud_normals_ptr->points) {
00174             ang = fabs((acos(pt.normal[2]) - CV_PI/2)/CV_PI*2);
00175             if(ang > norm_ang_thresh)
00176                 flat_inds_ptr->indices.push_back(i);
00177             i++;
00178         }
00179 
00180         if(flat_inds_ptr->indices.size() < 20)
00181             return false;
00182 
00183         // Cluster into distinct surfaces
00184         pcl::EuclideanClusterExtraction<PRGB> surf_clust;
00185         pcl::KdTree<PRGB>::Ptr clust_tree (new pcl::KdTreeFLANN<PRGB> ());
00186         surf_clust.setClusterTolerance(surf_clust_dist);
00187         surf_clust.setMinClusterSize(surf_clust_min_size);
00188         surf_clust.setIndices(flat_inds_ptr);
00189         surf_clust.setInputCloud(pc_filtered_ptr);
00190         surf_clust.setSearchMethod(clust_tree);
00191         std::vector<pcl::PointIndices> surf_clust_list;
00192         surf_clust.extract(surf_clust_list);
00193 
00194         // Fit planes to all of the surfaces
00195         std::vector<pcl::ModelCoefficients> surf_models;
00196         pcl::SACSegmentationFromNormals<PRGB, pcl::Normal> sac_seg;
00197         sac_seg.setModelType(pcl::SACMODEL_NORMAL_PLANE);
00198         sac_seg.setMethodType(pcl::SAC_MSAC);
00199         sac_seg.setDistanceThreshold(0.03);
00200         sac_seg.setMaxIterations(10000);
00201         sac_seg.setNormalDistanceWeight(0.1);
00202         sac_seg.setOptimizeCoefficients(true);
00203         sac_seg.setProbability(0.99);
00204 
00205         for(uint32_t i =0;i<surf_clust_list.size();i++) {
00206             sac_seg.setInputNormals(cloud_normals_ptr);
00207             sac_seg.setInputCloud(pc_filtered_ptr);
00208             pcl::PointIndices::Ptr surf_clust_list_ptr (new pcl::PointIndices());
00209             surf_clust_list_ptr->indices = surf_clust_list[i].indices;
00210             //std::copy(surf_clust_list[i].indices.begin(), surf_clust_list[i].indices.end(), surf_clust_list_ptr->indices.begin());
00211             surf_clust_list_ptr->header = surf_clust_list[i].header;
00212             sac_seg.setIndices(surf_clust_list_ptr);
00213             pcl::PointIndices surf_inliers;
00214             pcl::ModelCoefficients surf_coeffs;
00215             sac_seg.segment(surf_inliers, surf_coeffs);
00216             surf_models.push_back(surf_coeffs);
00217             uint32_t cur_color = 0xFF000000 | (rand() % 0x01000000);
00218             for(uint32_t j=0;j<surf_inliers.indices.size();j++)
00219                 ((uint32_t*) &pc_filtered_ptr->points[surf_inliers.indices[j]].rgb)[0] = cur_color;
00220             cout << surf_clust_list[i].indices.size() << endl;
00221 
00222             for(uint32_t j=0;j<surf_coeffs.values.size();j++)
00223                 cout << i << " " << j << " " << surf_coeffs.values[j] << endl;
00224         }
00225         pc_filtered_ptr->header.stamp = ros::Time::now();
00226         pc_filtered_ptr->header.frame_id = base_frame;
00227         pc_pub2.publish(pc_filtered_ptr);
00228 
00229         if(surf_models.size() == 0)
00230             return false;
00231 
00232         pcl::PointCloud<PRGB> flat_pc;
00233         BOOST_FOREACH(const PRGB& pt, pc_full_frame_ptr->points) {
00234             if(pt.x != pt.x || pt.y != pt.y || pt.z != pt.z)
00235                 continue;
00236             PRGB n_pt;
00237             n_pt.x = pt.x; n_pt.y = pt.y; n_pt.z = pt.z; 
00238             double a = surf_models[0].values[0], b = surf_models[0].values[1];
00239             double c = surf_models[0].values[2], d = surf_models[0].values[3];
00240             double dist = (a*pt.x + b*pt.y + c*pt.z + d) / sqrt(a*a+b*b+c*c);
00241             
00242             if(fabs(dist) < 0.02) {
00243                 uint32_t green = 0xFF00FF00;
00244                 ((uint32_t*) &n_pt.rgb)[0] = green;
00245             } else if (dist > 0) {
00246                 uint32_t blue = 0xFF0000FF;
00247                 ((uint32_t*) &n_pt.rgb)[0] = blue;
00248             } else {
00249                 uint32_t red = 0xFFFF0000;
00250                 ((uint32_t*) &n_pt.rgb)[0] = red;
00251             }
00252             flat_pc.push_back(n_pt);
00253         }
00254         flat_pc.header.stamp = ros::Time::now();
00255         flat_pc.header.frame_id = pc_full_frame_ptr->header.frame_id;
00256         pc_pub3.publish(flat_pc);
00257 
00258         // project table inliers onto plane model found
00259         pcl::PointCloud<PRGB>::Ptr table_proj (new pcl::PointCloud<pcl::PointXYZRGB>);
00260         pcl::ProjectInliers<PRGB> proj_ins;
00261         proj_ins.setInputCloud(pc_filtered_ptr);
00262         proj_ins.setIndices(boost::make_shared<pcl::PointIndices>(surf_clust_list[0]));
00263         proj_ins.setModelType(pcl::SACMODEL_PLANE);
00264         proj_ins.setModelCoefficients(boost::make_shared<pcl::ModelCoefficients>(surf_models[0]));
00265         proj_ins.filter(*table_proj);
00266 
00267         // convex hull of largest surface
00268         pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZRGB>);
00269         pcl::ConvexHull<pcl::PointXYZRGB> convex_hull;
00270         convex_hull.setInputCloud(table_proj);
00271         //convex_hull.setIndices(boost::make_shared<pcl::PointIndices>(surf_clust_list[0]));
00272         convex_hull.reconstruct(*cloud_hull);
00273 
00274         // publish table hull polygon
00275         visualization_msgs::Marker hull_poly;
00276         hull_poly.type = visualization_msgs::Marker::LINE_STRIP;
00277         hull_poly.action = visualization_msgs::Marker::ADD;
00278         hull_poly.ns = "table_hull";
00279         hull_poly.header.frame_id = pc_filtered_ptr->header.frame_id;
00280         hull_poly.header.stamp = now;
00281         hull_poly.pose.orientation.w = 1;
00282         hull_poly.scale.x = 0.01; hull_poly.scale.y = 0.01; hull_poly.scale.z = 0.01; 
00283         hull_poly.color.g = 1; hull_poly.color.a = 1;
00284         for(uint32_t j=0;j<cloud_hull->points.size();j++) {
00285             geometry_msgs::Point n_pt;
00286             n_pt.x = cloud_hull->points[j].x; 
00287             n_pt.y = cloud_hull->points[j].y; 
00288             n_pt.z = cloud_hull->points[j].z; 
00289             hull_poly.points.push_back(n_pt);
00290         }
00291         hull_poly.points.push_back(hull_poly.points[0]);
00292         poly_pub.publish(hull_poly);
00293         accum_pc.points.clear();
00294         resp.surfaces.push_back(hull_poly);
00295         return true;
00296     }
00297 
00298 };
00299 
00300 using namespace hrl_table_detect;
00301 
00302 int main(int argc, char **argv)
00303 {
00304     ros::init(argc, argv, "surface_segmentation");
00305     SurfaceSegmentation ta;
00306     ta.onInit();
00307     ros::spin();
00308     return 0;
00309 }
00310 
00311 
00312 


hrl_table_detect
Author(s): kelsey
autogenerated on Wed Nov 27 2013 12:15:26