00001 #include <pcl/common/angles.h>
00002 #include <pcl/apps/organized_segmentation_demo.h>
00003
00004 #include <QApplication>
00005 #include <QMutexLocker>
00006 #include <QEvent>
00007 #include <QObject>
00008 #include <boost/make_shared.hpp>
00009 #include <boost/filesystem.hpp>
00010
00011 #include <pcl/segmentation/extract_polygonal_prism_data.h>
00012 #include <pcl/surface/convex_hull.h>
00013
00014 void
00015 displayPlanarRegions (std::vector<pcl::PlanarRegion<PointT>, Eigen::aligned_allocator<pcl::PlanarRegion<PointT> > > ®ions,
00016 boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer)
00017 {
00018 char name[1024];
00019 unsigned char red [6] = {255, 0, 0, 255, 255, 0};
00020 unsigned char grn [6] = { 0, 255, 0, 255, 0, 255};
00021 unsigned char blu [6] = { 0, 0, 255, 0, 255, 255};
00022
00023 pcl::PointCloud<PointT>::Ptr contour (new pcl::PointCloud<PointT>);
00024
00025 for (size_t i = 0; i < regions.size (); i++)
00026 {
00027 Eigen::Vector3f centroid = regions[i].getCentroid ();
00028 Eigen::Vector4f model = regions[i].getCoefficients ();
00029 pcl::PointXYZ pt1 = pcl::PointXYZ (centroid[0], centroid[1], centroid[2]);
00030 pcl::PointXYZ pt2 = pcl::PointXYZ (centroid[0] + (0.5f * model[0]),
00031 centroid[1] + (0.5f * model[1]),
00032 centroid[2] + (0.5f * model[2]));
00033 sprintf (name, "normal_%d", unsigned (i));
00034 viewer->addArrow (pt2, pt1, 1.0, 0, 0, false, name);
00035
00036 contour->points = regions[i].getContour ();
00037 sprintf (name, "plane_%02d", (int)i);
00038 pcl::visualization::PointCloudColorHandlerCustom <PointT> color (contour, red[i%6], grn[i%6], blu[i%6]);
00039 if(!viewer->updatePointCloud(contour, color, name))
00040 viewer->addPointCloud (contour, color, name);
00041 viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, name);
00042 }
00043 }
00044
00045 void
00046 displayEuclideanClusters (const pcl::PointCloud<PointT>::CloudVectorType &clusters,
00047 boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer)
00048 {
00049 char name[1024];
00050 unsigned char red [6] = {255, 0, 0, 255, 255, 0};
00051 unsigned char grn [6] = { 0, 255, 0, 255, 0, 255};
00052 unsigned char blu [6] = { 0, 0, 255, 0, 255, 255};
00053
00054 for (size_t i = 0; i < clusters.size (); i++)
00055 {
00056 sprintf (name, "cluster_%d",i);
00057 pcl::visualization::PointCloudColorHandlerCustom<PointT> color0(boost::make_shared<pcl::PointCloud<PointT> >(clusters[i]),red[i%6],grn[i%6],blu[i%6]);
00058 if (!viewer->updatePointCloud (boost::make_shared<pcl::PointCloud<PointT> >(clusters[i]),color0,name))
00059 viewer->addPointCloud (boost::make_shared<pcl::PointCloud<PointT> >(clusters[i]),color0,name);
00060 viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, name);
00061 viewer->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY, 0.3, name);
00062 }
00063 }
00064
00065 void
00066 displayCurvature (pcl::PointCloud<PointT>& cloud, pcl::PointCloud<pcl::Normal>& normals, boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer)
00067 {
00068 pcl::PointCloud<pcl::PointXYZRGBA> curvature_cloud = cloud;
00069 for (size_t i = 0; i < cloud.points.size (); i++)
00070 {
00071 if (normals.points[i].curvature < 0.04)
00072 {
00073 curvature_cloud.points[i].r = 0;
00074 curvature_cloud.points[i].g = 255;
00075 curvature_cloud.points[i].b = 0;
00076 }
00077 else
00078 {
00079 curvature_cloud.points[i].r = 255;
00080 curvature_cloud.points[i].g = 0;
00081 curvature_cloud.points[i].b = 0;
00082 }
00083 }
00084
00085 if (!viewer->updatePointCloud (boost::make_shared<pcl::PointCloud<pcl::PointXYZRGBA> >(curvature_cloud), "curvature"))
00086 viewer->addPointCloud (boost::make_shared<pcl::PointCloud<pcl::PointXYZRGBA> >(curvature_cloud), "curvature");
00087
00088 }
00089
00090 void
00091 displayDistanceMap (pcl::PointCloud<PointT>& cloud, float* distance_map, boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer)
00092 {
00093 pcl::PointCloud<pcl::PointXYZRGBA> distance_map_cloud = cloud;
00094 for (size_t i = 0; i < cloud.points.size (); i++)
00095 {
00096 if (distance_map[i] < 5.0)
00097 {
00098 distance_map_cloud.points[i].r = 255;
00099 distance_map_cloud.points[i].g = 0;
00100 distance_map_cloud.points[i].b = 0;
00101 }
00102 else
00103 {
00104 distance_map_cloud.points[i].r = 0;
00105 distance_map_cloud.points[i].g = 255;
00106 distance_map_cloud.points[i].b = 0;
00107 }
00108 }
00109
00110 if (!viewer->updatePointCloud (boost::make_shared<pcl::PointCloud<pcl::PointXYZRGBA> >(distance_map_cloud), "distance_map"))
00111 viewer->addPointCloud (boost::make_shared<pcl::PointCloud<pcl::PointXYZRGBA> >(distance_map_cloud), "distance_map");
00112 }
00113
00114 void
00115 removePreviousDataFromScreen (size_t prev_models_size, size_t prev_clusters_size, boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer)
00116 {
00117 char name[1024];
00118 for (size_t i = 0; i < prev_models_size; i++)
00119 {
00120 sprintf (name, "normal_%d", unsigned (i));
00121 viewer->removeShape (name);
00122
00123 sprintf (name, "plane_%02d", int (i));
00124 viewer->removePointCloud (name);
00125 }
00126
00127 for (size_t i = 0; i < prev_clusters_size; i++)
00128 {
00129 sprintf (name, "cluster_%d", int (i));
00130 viewer->removePointCloud (name);
00131 }
00132 }
00133
00134 bool
00135 compareClusterToRegion (pcl::PlanarRegion<PointT>& region, pcl::PointCloud<PointT>& cluster)
00136 {
00137 Eigen::Vector4f model = region.getCoefficients ();
00138 pcl::PointCloud<PointT> poly;
00139 poly.points = region.getContour ();
00140
00141 bool cluster_ok = false;
00142 for (size_t i = 0; i < cluster.points.size (); i++)
00143 {
00144 double ptp_dist = fabs (model[0] * cluster.points[i].x +
00145 model[1] * cluster.points[i].y +
00146 model[2] * cluster.points[i].z +
00147 model[3]);
00148 bool in_poly = pcl::isPointIn2DPolygon<PointT> (cluster.points[i], poly);
00149 if (in_poly && ptp_dist < 0.02)
00150 return true;
00151 }
00152 return false;
00153 }
00154
00155 bool
00156 comparePointToRegion (PointT& pt, pcl::ModelCoefficients& model, pcl::PointCloud<PointT>& poly)
00157 {
00158 bool dist_ok = false;
00159 bool inside = false;
00160
00161 double ptp_dist = fabs (model.values[0] * pt.x +
00162 model.values[1] * pt.y +
00163 model.values[2] * pt.z +
00164 model.values[3]);
00165 if (ptp_dist < 0.1)
00166 {
00167 dist_ok = true;
00168 }
00169 else
00170 return false;
00171
00172
00173 Eigen::Vector3f mc (model.values[0], model.values[1], model.values[2]);
00174 Eigen::Vector3f pt_vec;
00175 pt_vec[0] = pt.x;
00176 pt_vec[1] = pt.y;
00177 pt_vec[2] = pt.z;
00178 Eigen::Vector3f projected (pt_vec - mc * ptp_dist);
00179 PointT projected_pt;
00180 projected_pt.x = projected[0];
00181 projected_pt.y = projected[1];
00182 projected_pt.z = projected[2];
00183
00184 PCL_INFO ("pt: %lf %lf %lf\n", projected_pt.x, projected_pt.y, projected_pt.z);
00185
00186 if (pcl::isPointIn2DPolygon (projected_pt, poly))
00187 {
00188 PCL_INFO ("inside!\n");
00189 return true;
00190 }
00191 else
00192 {
00193 PCL_INFO ("not inside!\n");
00194 return false;
00195 }
00196
00197 }
00198
00200 OrganizedSegmentationDemo::OrganizedSegmentationDemo (pcl::Grabber& grabber) : grabber_ (grabber)
00201 {
00202
00203 vis_timer_ = new QTimer (this);
00204 vis_timer_->start (5);
00205
00206 connect (vis_timer_, SIGNAL (timeout ()), this, SLOT (timeoutSlot()));
00207
00208 ui_ = new Ui::MainWindow;
00209 ui_->setupUi (this);
00210
00211 this->setWindowTitle ("PCL Organized Connected Component Segmentation Demo");
00212 vis_.reset (new pcl::visualization::PCLVisualizer ("", false));
00213 ui_->qvtk_widget->SetRenderWindow (vis_->getRenderWindow ());
00214 vis_->setupInteractor (ui_->qvtk_widget->GetInteractor (), ui_->qvtk_widget->GetRenderWindow ());
00215 vis_->getInteractorStyle ()->setKeyboardModifier (pcl::visualization::INTERACTOR_KB_MOD_SHIFT);
00216 ui_->qvtk_widget->update ();
00217
00218 boost::function<void (const CloudConstPtr&)> f = boost::bind (&OrganizedSegmentationDemo::cloud_cb, this, _1);
00219 boost::signals2::connection c = grabber_.registerCallback(f);
00220
00221 connect (ui_->captureButton, SIGNAL(clicked()), this, SLOT(toggleCapturePressed()));
00222
00223 connect (ui_->euclideanComparatorButton, SIGNAL (clicked ()), this, SLOT (useEuclideanComparatorPressed ()));
00224 connect (ui_->planeComparatorButton, SIGNAL (clicked ()), this, SLOT (usePlaneComparatorPressed ()));
00225 connect (ui_->rgbComparatorButton, SIGNAL (clicked ()), this, SLOT (useRGBComparatorPressed ()));
00226 connect (ui_->edgeAwareComparatorButton, SIGNAL (clicked ()), this, SLOT (useEdgeAwareComparatorPressed ()));
00227
00228 connect (ui_->displayCurvatureButton, SIGNAL (clicked ()), this, SLOT (displayCurvaturePressed ()));
00229 connect (ui_->displayDistanceMapButton, SIGNAL (clicked ()), this, SLOT (displayDistanceMapPressed ()));
00230 connect (ui_->displayNormalsButton, SIGNAL (clicked ()), this, SLOT (displayNormalsPressed ()));
00231
00232 connect (ui_->disableRefinementButton, SIGNAL (clicked ()), this, SLOT (disableRefinementPressed ()));
00233 connect (ui_->planarRefinementButton, SIGNAL (clicked ()), this, SLOT (usePlanarRefinementPressed ()));
00234
00235 connect (ui_->disableClusteringButton, SIGNAL (clicked ()), this, SLOT (disableClusteringPressed ()));
00236 connect (ui_->euclideanClusteringButton, SIGNAL (clicked ()), this, SLOT (useEuclideanClusteringPressed ()));
00237
00238 capture_ = false;
00239 previous_data_size_ = 0;
00240 previous_clusters_size_ = 0;
00241 data_modified_ = true;
00242
00243 display_normals_ = false;
00244 display_curvature_ = false;
00245 display_distance_map_ = false;
00246
00247 use_planar_refinement_ = true;
00248 use_clustering_ = false;
00249
00250
00251
00252
00253 ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);
00254 ne.setMaxDepthChangeFactor (0.02f);
00255 ne.setNormalSmoothingSize (20.0f);
00256
00257 plane_comparator_.reset (new pcl::PlaneCoefficientComparator<PointT, pcl::Normal> ());
00258 euclidean_comparator_.reset (new pcl::EuclideanPlaneCoefficientComparator<PointT, pcl::Normal> ());
00259 rgb_comparator_.reset (new pcl::RGBPlaneCoefficientComparator<PointT, pcl::Normal> ());
00260 edge_aware_comparator_.reset (new pcl::EdgeAwarePlaneComparator<PointT, pcl::Normal> ());
00261 euclidean_cluster_comparator_ = pcl::EuclideanClusterComparator<PointT, pcl::Normal, pcl::Label>::Ptr (new pcl::EuclideanClusterComparator<PointT, pcl::Normal, pcl::Label> ());
00262
00263
00264 mps.setMinInliers (10000);
00265 mps.setAngularThreshold (pcl::deg2rad (3.0));
00266 mps.setDistanceThreshold (0.02);
00267
00268
00269 PCL_INFO ("starting grabber\n");
00270 grabber_.start ();
00271 }
00272
00273 void
00274 OrganizedSegmentationDemo::cloud_cb (const CloudConstPtr& cloud)
00275 {
00276 if (!capture_)
00277 return;
00278 QMutexLocker locker (&mtx_);
00279 FPS_CALC ("computation");
00280
00281
00282 pcl::PointCloud<pcl::Normal>::Ptr normal_cloud (new pcl::PointCloud<pcl::Normal>);
00283 ne.setInputCloud (cloud);
00284 ne.compute (*normal_cloud);
00285 float* distance_map = ne.getDistanceMap ();
00286 boost::shared_ptr<pcl::EdgeAwarePlaneComparator<PointT,pcl::Normal> > eapc = boost::dynamic_pointer_cast<pcl::EdgeAwarePlaneComparator<PointT,pcl::Normal> >(edge_aware_comparator_);
00287 eapc->setDistanceMap (distance_map);
00288 eapc->setDistanceThreshold (0.01f, false);
00289
00290
00291 double mps_start = pcl::getTime ();
00292 std::vector<pcl::PlanarRegion<PointT>, Eigen::aligned_allocator<pcl::PlanarRegion<PointT> > > regions;
00293 std::vector<pcl::ModelCoefficients> model_coefficients;
00294 std::vector<pcl::PointIndices> inlier_indices;
00295 pcl::PointCloud<pcl::Label>::Ptr labels (new pcl::PointCloud<pcl::Label>);
00296 std::vector<pcl::PointIndices> label_indices;
00297 std::vector<pcl::PointIndices> boundary_indices;
00298 mps.setInputNormals (normal_cloud);
00299 mps.setInputCloud (cloud);
00300 if (use_planar_refinement_)
00301 {
00302 mps.segmentAndRefine (regions, model_coefficients, inlier_indices, labels, label_indices, boundary_indices);
00303 }
00304 else
00305 {
00306 mps.segment (regions);
00307 }
00308 double mps_end = pcl::getTime ();
00309 std::cout << "MPS+Refine took: " << double(mps_end - mps_start) << std::endl;
00310
00311
00312 pcl::PointCloud<PointT>::CloudVectorType clusters;
00313
00314 if (use_clustering_ && regions.size () > 0)
00315 {
00316 std::vector<bool> plane_labels;
00317 plane_labels.resize (label_indices.size (), false);
00318 for (size_t i = 0; i < label_indices.size (); i++)
00319 {
00320 if (label_indices[i].indices.size () > 10000)
00321 {
00322 plane_labels[i] = true;
00323 }
00324 }
00325
00326 euclidean_cluster_comparator_->setInputCloud (cloud);
00327 euclidean_cluster_comparator_->setLabels (labels);
00328 euclidean_cluster_comparator_->setExcludeLabels (plane_labels);
00329 euclidean_cluster_comparator_->setDistanceThreshold (0.01f, false);
00330
00331 pcl::PointCloud<pcl::Label> euclidean_labels;
00332 std::vector<pcl::PointIndices> euclidean_label_indices;
00333 pcl::OrganizedConnectedComponentSegmentation<PointT,pcl::Label> euclidean_segmentation (euclidean_cluster_comparator_);
00334 euclidean_segmentation.setInputCloud (cloud);
00335 euclidean_segmentation.segment (euclidean_labels, euclidean_label_indices);
00336
00337 for (size_t i = 0; i < euclidean_label_indices.size (); i++)
00338 {
00339 if (euclidean_label_indices[i].indices.size () > 1000)
00340 {
00341 pcl::PointCloud<PointT> cluster;
00342 pcl::copyPointCloud (*cloud,euclidean_label_indices[i].indices,cluster);
00343 clusters.push_back (cluster);
00344 }
00345 }
00346
00347 PCL_INFO ("Got %d euclidean clusters!\n", clusters.size ());
00348 }
00349
00350 {
00351 QMutexLocker vis_locker (&vis_mtx_);
00352 prev_cloud_ = *cloud;
00353 prev_normals_ = *normal_cloud;
00354 prev_regions_ = regions;
00355 prev_distance_map_ = distance_map;
00356 prev_clusters_ = clusters;
00357 data_modified_ = true;
00358 }
00359 }
00360
00361 void
00362 OrganizedSegmentationDemo::timeoutSlot ()
00363 {
00364 {
00365 QMutexLocker vis_locker (&vis_mtx_);
00366 if (capture_ && data_modified_)
00367 {
00368 removePreviousDataFromScreen (previous_data_size_, previous_clusters_size_, vis_);
00369 if (!vis_->updatePointCloud (boost::make_shared<pcl::PointCloud<PointT> >(prev_cloud_), "cloud"))
00370 {
00371 vis_->addPointCloud (boost::make_shared<pcl::PointCloud<PointT> >(prev_cloud_), "cloud");
00372 vis_->resetCameraViewpoint ("cloud");
00373 }
00374
00375 displayPlanarRegions (prev_regions_, vis_);
00376
00377 if (display_curvature_)
00378 displayCurvature (prev_cloud_, prev_normals_, vis_);
00379 else
00380 vis_->removePointCloud ("curvature");
00381
00382 if (display_distance_map_)
00383 displayDistanceMap (prev_cloud_, prev_distance_map_, vis_);
00384 else
00385 vis_->removePointCloud ("distance_map");
00386
00387 if (display_normals_)
00388 {
00389 vis_->removePointCloud ("normals");
00390 vis_->addPointCloudNormals<PointT,pcl::Normal>(boost::make_shared<pcl::PointCloud<PointT> >(prev_cloud_), boost::make_shared<pcl::PointCloud<pcl::Normal> >(prev_normals_), 10, 0.05f, "normals");
00391 vis_->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY, 0.5, "normals");
00392 }
00393 else
00394 {
00395 vis_->removePointCloud ("normals");
00396 }
00397
00398 displayEuclideanClusters (prev_clusters_,vis_);
00399
00400 previous_data_size_ = prev_regions_.size ();
00401 previous_clusters_size_ = prev_clusters_.size ();
00402 data_modified_ = false;
00403 }
00404 }
00405
00406 ui_->qvtk_widget->update();
00407 }
00408
00409 void
00410 OrganizedSegmentationDemo::useEuclideanComparatorPressed ()
00411 {
00412 QMutexLocker locker (&mtx_);
00413 PCL_INFO ("Setting Comparator to Euclidean\n");
00414 mps.setComparator (euclidean_comparator_);
00415 }
00416
00417 void
00418 OrganizedSegmentationDemo::useRGBComparatorPressed ()
00419 {
00420 QMutexLocker locker (&mtx_);
00421 PCL_INFO ("Setting Comparator to RGB\n");
00422 mps.setComparator (rgb_comparator_);
00423 }
00424
00425 void
00426 OrganizedSegmentationDemo::usePlaneComparatorPressed ()
00427 {
00428 QMutexLocker locker (&mtx_);
00429 PCL_INFO ("Setting Comparator to Plane\n");
00430 mps.setComparator (plane_comparator_);
00431 }
00432
00433 void
00434 OrganizedSegmentationDemo::useEdgeAwareComparatorPressed ()
00435 {
00436 QMutexLocker locker (&mtx_);
00437 PCL_INFO ("Setting Comparator to edge aware\n");
00438 mps.setComparator (edge_aware_comparator_);
00439 }
00440
00441 void
00442 OrganizedSegmentationDemo::displayCurvaturePressed ()
00443 {
00444 display_curvature_ = !display_curvature_;
00445 }
00446
00447 void
00448 OrganizedSegmentationDemo::displayDistanceMapPressed ()
00449 {
00450 display_distance_map_ = !display_distance_map_;
00451 }
00452
00453 void
00454 OrganizedSegmentationDemo::displayNormalsPressed ()
00455 {
00456 display_normals_ = !display_normals_;
00457 }
00458
00459 int
00460 main (int argc, char ** argv)
00461 {
00462 QApplication app(argc, argv);
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 pcl::OpenNIGrabber grabber ("#1");
00478
00479 OrganizedSegmentationDemo seg_demo (grabber);
00480 seg_demo.show();
00481 return (app.exec ());
00482 }