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
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
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
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
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
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
00164
00165
00166
00167
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
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
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
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
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
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
00272 convex_hull.reconstruct(*cloud_hull);
00273
00274
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