00001
00063 #include <sstream>
00064 #include <ros/ros.h>
00065 #include <pluginlib/class_list_macros.h>
00066 #include <eigen_conversions/eigen_msg.h>
00067 #include <pcl/common/transforms.h>
00068 #include <pcl/filters/extract_indices.h>
00069 #include <pcl/surface/organized_fast_mesh.h>
00070 #include <pcl/PolygonMesh.h>
00071 #include <pcl/io/ply_io.h>
00072 #include <pcl/io/vtk_io.h>
00073 #include <pcl/io/pcd_io.h>
00074 #include <pcl_conversions/pcl_conversions.h>
00075 #include <opencv2/opencv.hpp>
00076
00077 #include <cob_3d_mapping_msgs/ShapeArray.h>
00078 #include <cob_3d_mapping_common/stop_watch.h>
00079 #include <cob_3d_mapping_common/ros_msg_conversions.h>
00080 #include "cob_3d_segmentation/simple_segmentation_nodelet.h"
00081 #include "cob_3d_mapping_filters/downsample_filter.h"
00082
00083 void
00084 cob_3d_segmentation::SimpleSegmentationNodelet::onInit()
00085 {
00086
00087 nh_ = getNodeHandle();
00088 config_server_.reset(
00089 new dynamic_reconfigure::Server<segmentation_nodeletConfig>(
00090 getPrivateNodeHandle()));
00091 config_server_->setCallback(
00092 boost::bind(&SimpleSegmentationNodelet::configCallback, this, _1, _2));
00093
00094 one_.setOutputLabels(labels_);
00095 one_.setPixelSearchRadius(8,2,2);
00096 one_.setSkipDistantPointThreshold(8);
00097
00098 seg_.setNormalCloudIn(normals_);
00099 seg_.setLabelCloudInOut(labels_);
00100 seg_.setSeedMethod(SEED_RANDOM);
00101
00102 pub_segmented_ = nh_.advertise<PointCloud>("segmented_cloud", 1);
00103 pub_classified_ = nh_.advertise<PointCloud>("classified_cloud", 1);
00104 pub_shape_array_ = nh_.advertise<cob_3d_mapping_msgs::ShapeArray>("shape_array",1);
00105 as_ = new actionlib::SimpleActionServer<cob_3d_mapping_msgs::TriggerAction>(
00106 nh_, "segmentation/trigger",
00107 boost::bind(&SimpleSegmentationNodelet::actionCallback, this, _1), false);
00108 as_->start();
00109 }
00110
00111
00112 void
00113 cob_3d_segmentation::SimpleSegmentationNodelet::configCallback(
00114 cob_3d_segmentation::segmentation_nodeletConfig& config,
00115 uint32_t level)
00116 {
00117 NODELET_INFO("[segmentation]: received new parameters");
00118 centroid_passthrough_ = config.centroid_passthrough;
00119 filter_ = config.filter;
00120 min_cluster_size_ = config.min_cluster_size;
00121 downsample_ = config.downsample;
00122 colorize_ = config.colorize;
00123 enable_action_mode_ = config.enable_action_mode;
00124 if(!is_running_ && !enable_action_mode_)
00125 {
00126 ROS_INFO("Starting segmentation...");
00127 sub_points_ = nh_.subscribe("point_cloud", 1, &SimpleSegmentationNodelet::topicCallback, this);
00128 is_running_ = true;
00129 }
00130 }
00131
00132 void
00133 cob_3d_segmentation::SimpleSegmentationNodelet::actionCallback(
00134 const cob_3d_mapping_msgs::TriggerGoalConstPtr& goal)
00135 {
00136
00137 cob_3d_mapping_msgs::TriggerResult result;
00138 if(goal->start && !is_running_)
00139 {
00140 ROS_INFO("Starting segmentation...");
00141 sub_points_ = nh_.subscribe("point_cloud", 1, &SimpleSegmentationNodelet::topicCallback, this);
00142 is_running_ = true;
00143 }
00144 else if(!goal->start && is_running_)
00145 {
00146 ROS_INFO("Stopping segmentation...");
00147 sub_points_.shutdown();
00148 is_running_ = false;
00149 }
00150
00151 as_->setSucceeded(result);
00152 }
00153
00154 void
00155 cob_3d_segmentation::SimpleSegmentationNodelet::topicCallback(
00156 const PointCloud::ConstPtr& cloud)
00157 {
00158
00159 PrecisionStopWatch t;
00160 NODELET_INFO("Received PointCloud. Start downsampling .... ");
00161
00162
00163 if(downsample_)
00164 {
00165 cob_3d_mapping_filters::DownsampleFilter<pcl::PointXYZRGB> down;
00166 down_->header = cloud->header;
00167 down.setInputCloud(cloud);
00168 down.filter(*down_);
00169 *segmented_ = *down_;
00170 }
00171 else
00172 {
00173 *segmented_ = *down_ = *cloud;
00174 }
00175
00176 computeAndPublish();
00177 }
00178
00179 void
00180 cob_3d_segmentation::SimpleSegmentationNodelet::computeAndPublish()
00181 {
00182 PrecisionStopWatch t, t2;
00183 t2.precisionStart();
00184 NODELET_INFO("Start with segmentation .... ");
00185 one_.setInputCloud(down_);
00186 one_.compute(*normals_);
00187
00188 seg_.setInputCloud(down_);
00189
00190 seg_.compute();
00191
00192 seg_.mapSegmentColor(segmented_);
00193
00194 pub_segmented_.publish(segmented_);
00195
00196
00197 PointCloud::Ptr hull(new PointCloud);
00198 cob_3d_mapping_msgs::ShapeArray sa;
00199 pcl_conversions::fromPCL(down_->header, sa.header);
00200
00201
00202
00203 for (ClusterPtr c = seg_.clusters()->begin(); c != seg_.clusters()->end(); ++c)
00204 {
00205 if(c->size() < min_cluster_size_) {continue;}
00206 if(c->getCentroid()(2) > centroid_passthrough_) {continue;}
00207 if(c->border_points.size() > ceil(0.9f * (float)c->size())) {continue;}
00208
00209 seg_.clusters()->computeClusterComponents(c);
00210 if(filter_ && !c->is_planar_) {continue;}
00211
00212 cob_3d_mapping::Polygon::Ptr p;
00213
00214 conv_.setColor(colorize_);
00215 conv_.setInputCloud(down_);
00216 if(!conv_.clusterToPolygon(c, p)) continue;
00217
00218 sa.shapes.push_back(cob_3d_mapping_msgs::Shape());
00219 cob_3d_mapping_msgs::Shape* s = &sa.shapes.back();
00220 pcl_conversions::fromPCL(down_->header, s->header);
00221
00222
00223
00224 cob_3d_mapping::toROSMsg(*p, *s);
00225
00226 }
00227
00228 pub_shape_array_.publish(sa);
00229 publishClassifiedCloud();
00230 std::cout << "total nodelet time: " << t2.precisionStop() << std::endl;
00231 }
00232
00233
00234 void
00235 cob_3d_segmentation::SimpleSegmentationNodelet::publishClassifiedCloud()
00236 {
00237 seg_.clusters()->mapTypeColor(down_);
00238 seg_.clusters()->mapClusterBorders(down_);
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278 pub_classified_.publish(down_);
00279 }
00280
00281 void
00282 cob_3d_segmentation::SimpleSegmentationNodelet::computeTexture(
00283 ClusterPtr &c, Eigen::Affine3f &trf, unsigned int id)
00284 {
00285 pcl::ExtractIndices<pcl::PointXYZRGB> ei;
00286 ei.setInputCloud(down_);
00287 pcl::IndicesPtr ind_ptr(new std::vector<int>);
00288 for(unsigned int i=0; i<c->indices_.size(); i++)
00289 ind_ptr->push_back(c->indices_[i]);
00290 ei.setIndices(ind_ptr);
00291 PointCloud::Ptr segment(new PointCloud);
00292 ei.filter(*segment);
00293 PointCloud::Ptr segment_tr(new PointCloud);
00294 pcl::transformPointCloud(*segment, *segment_tr, trf.inverse());
00295 std::stringstream ss;
00296 ss << "/tmp/seg_" << id << ".pcd";
00297 pcl::io::savePCDFileBinary(ss.str(), *segment_tr);
00298 double mToPx = 500;
00299 int min_u = std::numeric_limits<int>::max(), max_u = std::numeric_limits<int>::min(), min_v = std::numeric_limits<int>::max(), max_v = std::numeric_limits<int>::min();
00300 for (unsigned int i=0; i<segment_tr->size(); i++)
00301 {
00302 int u = round(segment_tr->points[i].x * mToPx);
00303 int v = round(segment_tr->points[i].y * mToPx);
00304 if(u < min_u) min_u = u;
00305 if(u > max_u) max_u = u;
00306 if(v < min_v) min_v = v;
00307 if(v > max_v) max_v = v;
00308
00309 }
00310
00311
00312 cv::Mat img(abs(max_u - min_u) +1 , abs(max_v - min_v) + 1, CV_8UC3, cv::Scalar(-1));
00313
00314 for (unsigned int i=0; i<segment_tr->size(); i++)
00315 {
00316
00317 int u = round(segment_tr->points[i].x * mToPx) - min_u;
00318 int v = round(segment_tr->points[i].y * mToPx) - min_v;
00319
00320 img.at<cv::Vec3b>(u,v)[2] = segment_tr->points[i].r;
00321 img.at<cv::Vec3b>(u,v)[1] = segment_tr->points[i].g;
00322 img.at<cv::Vec3b>(u,v)[0] = segment_tr->points[i].b;
00323 }
00324 std::stringstream ss1;
00325 ss1 << "/tmp/seg_" << id << ".png";
00326 cv::imwrite(ss1.str(), img);
00327
00328 cv::Mat img_dil(abs(max_u - min_u) +1 , abs(max_v - min_v) + 1, CV_8UC3);
00329 cv::dilate(img, img_dil, cv::Mat(), cv::Point(-1,-1), 2);
00330 std::stringstream ss2;
00331 ss2 << "/tmp/seg_" << id << "_dil.png";
00332 cv::imwrite(ss2.str(), img_dil);
00333
00334 PointCloud::Ptr segm(new PointCloud);
00335
00336 pcl::ExtractIndices<pcl::PointXYZRGB> ei2;
00337 ei2.setInputCloud(down_);
00338 ei2.setIndices(ind_ptr);
00339 ei2.setKeepOrganized(true);
00340 ei2.filter(*segm);
00341
00342 pcl::OrganizedFastMesh<pcl::PointXYZRGB> ofm;
00343 pcl::PolygonMesh pcl_mesh;
00344 ofm.setInputCloud(segm);
00345
00346 ofm.setTriangulationType(pcl::OrganizedFastMesh<pcl::PointXYZRGB>::TRIANGLE_ADAPTIVE_CUT);
00347 ofm.reconstruct(pcl_mesh);
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361 }
00362
00363 PLUGINLIB_DECLARE_CLASS(cob_3d_segmentation, SimpleSegmentationNodelet,
00364 cob_3d_segmentation::SimpleSegmentationNodelet,
00365 nodelet::Nodelet);