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
00009 #include <pcl/segmentation/extract_polygonal_prism_data.h>
00010 #include <pcl/surface/convex_hull.h>
00011
00012 #include <vtkRenderWindow.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" , int (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 for (size_t i = 0; i < cluster.points.size (); i++)
00142 {
00143 double ptp_dist = fabs (model[0] * cluster.points[i].x +
00144 model[1] * cluster.points[i].y +
00145 model[2] * cluster.points[i].z +
00146 model[3]);
00147 bool in_poly = pcl::isPointIn2DPolygon<PointT> (cluster.points[i], poly);
00148 if (in_poly && ptp_dist < 0.02)
00149 return true;
00150 }
00151 return false;
00152 }
00153
00154 bool
00155 comparePointToRegion (PointT& pt, pcl::ModelCoefficients& model, pcl::PointCloud<PointT>& poly)
00156 {
00157
00158
00159 double ptp_dist = fabs (model.values[0] * pt.x +
00160 model.values[1] * pt.y +
00161 model.values[2] * pt.z +
00162 model.values[3]);
00163 if (ptp_dist >= 0.1)
00164 return (false);
00165
00166
00167
00168
00169 Eigen::Vector3f mc (model.values[0], model.values[1], model.values[2]);
00170 Eigen::Vector3f pt_vec;
00171 pt_vec[0] = pt.x;
00172 pt_vec[1] = pt.y;
00173 pt_vec[2] = pt.z;
00174 Eigen::Vector3f projected (pt_vec - mc * float (ptp_dist));
00175 PointT projected_pt;
00176 projected_pt.x = projected[0];
00177 projected_pt.y = projected[1];
00178 projected_pt.z = projected[2];
00179
00180 PCL_INFO ("pt: %lf %lf %lf\n", projected_pt.x, projected_pt.y, projected_pt.z);
00181
00182 if (pcl::isPointIn2DPolygon (projected_pt, poly))
00183 {
00184 PCL_INFO ("inside!\n");
00185 return true;
00186 }
00187 else
00188 {
00189 PCL_INFO ("not inside!\n");
00190 return false;
00191 }
00192
00193 }
00194
00196 OrganizedSegmentationDemo::OrganizedSegmentationDemo (pcl::Grabber& grabber) : grabber_ (grabber)
00197 {
00198
00199 vis_timer_ = new QTimer (this);
00200 vis_timer_->start (5);
00201
00202 connect (vis_timer_, SIGNAL (timeout ()), this, SLOT (timeoutSlot()));
00203
00204 ui_ = new Ui::MainWindow;
00205 ui_->setupUi (this);
00206
00207 this->setWindowTitle ("PCL Organized Connected Component Segmentation Demo");
00208 vis_.reset (new pcl::visualization::PCLVisualizer ("", false));
00209 ui_->qvtk_widget->SetRenderWindow (vis_->getRenderWindow ());
00210 vis_->setupInteractor (ui_->qvtk_widget->GetInteractor (), ui_->qvtk_widget->GetRenderWindow ());
00211 vis_->getInteractorStyle ()->setKeyboardModifier (pcl::visualization::INTERACTOR_KB_MOD_SHIFT);
00212 ui_->qvtk_widget->update ();
00213
00214 boost::function<void (const CloudConstPtr&)> f = boost::bind (&OrganizedSegmentationDemo::cloud_cb, this, _1);
00215 boost::signals2::connection c = grabber_.registerCallback(f);
00216
00217 connect (ui_->captureButton, SIGNAL(clicked()), this, SLOT(toggleCapturePressed()));
00218
00219 connect (ui_->euclideanComparatorButton, SIGNAL (clicked ()), this, SLOT (useEuclideanComparatorPressed ()));
00220 connect (ui_->planeComparatorButton, SIGNAL (clicked ()), this, SLOT (usePlaneComparatorPressed ()));
00221 connect (ui_->rgbComparatorButton, SIGNAL (clicked ()), this, SLOT (useRGBComparatorPressed ()));
00222 connect (ui_->edgeAwareComparatorButton, SIGNAL (clicked ()), this, SLOT (useEdgeAwareComparatorPressed ()));
00223
00224 connect (ui_->displayCurvatureButton, SIGNAL (clicked ()), this, SLOT (displayCurvaturePressed ()));
00225 connect (ui_->displayDistanceMapButton, SIGNAL (clicked ()), this, SLOT (displayDistanceMapPressed ()));
00226 connect (ui_->displayNormalsButton, SIGNAL (clicked ()), this, SLOT (displayNormalsPressed ()));
00227
00228 connect (ui_->disableRefinementButton, SIGNAL (clicked ()), this, SLOT (disableRefinementPressed ()));
00229 connect (ui_->planarRefinementButton, SIGNAL (clicked ()), this, SLOT (usePlanarRefinementPressed ()));
00230
00231 connect (ui_->disableClusteringButton, SIGNAL (clicked ()), this, SLOT (disableClusteringPressed ()));
00232 connect (ui_->euclideanClusteringButton, SIGNAL (clicked ()), this, SLOT (useEuclideanClusteringPressed ()));
00233
00234 capture_ = false;
00235 previous_data_size_ = 0;
00236 previous_clusters_size_ = 0;
00237 data_modified_ = true;
00238
00239 display_normals_ = false;
00240 display_curvature_ = false;
00241 display_distance_map_ = false;
00242
00243 use_planar_refinement_ = true;
00244 use_clustering_ = false;
00245
00246
00247
00248
00249 ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);
00250 ne.setMaxDepthChangeFactor (0.02f);
00251 ne.setNormalSmoothingSize (20.0f);
00252
00253 plane_comparator_.reset (new pcl::PlaneCoefficientComparator<PointT, pcl::Normal> ());
00254 euclidean_comparator_.reset (new pcl::EuclideanPlaneCoefficientComparator<PointT, pcl::Normal> ());
00255 rgb_comparator_.reset (new pcl::RGBPlaneCoefficientComparator<PointT, pcl::Normal> ());
00256 edge_aware_comparator_.reset (new pcl::EdgeAwarePlaneComparator<PointT, pcl::Normal> ());
00257 euclidean_cluster_comparator_ = pcl::EuclideanClusterComparator<PointT, pcl::Normal, pcl::Label>::Ptr (new pcl::EuclideanClusterComparator<PointT, pcl::Normal, pcl::Label> ());
00258
00259
00260 mps.setMinInliers (10000);
00261 mps.setAngularThreshold (pcl::deg2rad (3.0));
00262 mps.setDistanceThreshold (0.02);
00263
00264
00265 PCL_INFO ("starting grabber\n");
00266 grabber_.start ();
00267 }
00268
00269 void
00270 OrganizedSegmentationDemo::cloud_cb (const CloudConstPtr& cloud)
00271 {
00272 if (!capture_)
00273 return;
00274 QMutexLocker locker (&mtx_);
00275 FPS_CALC ("computation");
00276
00277
00278 pcl::PointCloud<pcl::Normal>::Ptr normal_cloud (new pcl::PointCloud<pcl::Normal>);
00279 ne.setInputCloud (cloud);
00280 ne.compute (*normal_cloud);
00281 float* distance_map = ne.getDistanceMap ();
00282 boost::shared_ptr<pcl::EdgeAwarePlaneComparator<PointT,pcl::Normal> > eapc = boost::dynamic_pointer_cast<pcl::EdgeAwarePlaneComparator<PointT,pcl::Normal> >(edge_aware_comparator_);
00283 eapc->setDistanceMap (distance_map);
00284 eapc->setDistanceThreshold (0.01f, false);
00285
00286
00287 double mps_start = pcl::getTime ();
00288 std::vector<pcl::PlanarRegion<PointT>, Eigen::aligned_allocator<pcl::PlanarRegion<PointT> > > regions;
00289 std::vector<pcl::ModelCoefficients> model_coefficients;
00290 std::vector<pcl::PointIndices> inlier_indices;
00291 pcl::PointCloud<pcl::Label>::Ptr labels (new pcl::PointCloud<pcl::Label>);
00292 std::vector<pcl::PointIndices> label_indices;
00293 std::vector<pcl::PointIndices> boundary_indices;
00294 mps.setInputNormals (normal_cloud);
00295 mps.setInputCloud (cloud);
00296 if (use_planar_refinement_)
00297 {
00298 mps.segmentAndRefine (regions, model_coefficients, inlier_indices, labels, label_indices, boundary_indices);
00299 }
00300 else
00301 {
00302 mps.segment (regions);
00303 }
00304 double mps_end = pcl::getTime ();
00305 std::cout << "MPS+Refine took: " << double(mps_end - mps_start) << std::endl;
00306
00307
00308 pcl::PointCloud<PointT>::CloudVectorType clusters;
00309
00310 if (use_clustering_ && regions.size () > 0)
00311 {
00312 std::vector<bool> plane_labels;
00313 plane_labels.resize (label_indices.size (), false);
00314 for (size_t i = 0; i < label_indices.size (); i++)
00315 {
00316 if (label_indices[i].indices.size () > 10000)
00317 {
00318 plane_labels[i] = true;
00319 }
00320 }
00321
00322 euclidean_cluster_comparator_->setInputCloud (cloud);
00323 euclidean_cluster_comparator_->setLabels (labels);
00324 euclidean_cluster_comparator_->setExcludeLabels (plane_labels);
00325 euclidean_cluster_comparator_->setDistanceThreshold (0.01f, false);
00326
00327 pcl::PointCloud<pcl::Label> euclidean_labels;
00328 std::vector<pcl::PointIndices> euclidean_label_indices;
00329 pcl::OrganizedConnectedComponentSegmentation<PointT,pcl::Label> euclidean_segmentation (euclidean_cluster_comparator_);
00330 euclidean_segmentation.setInputCloud (cloud);
00331 euclidean_segmentation.segment (euclidean_labels, euclidean_label_indices);
00332
00333 for (size_t i = 0; i < euclidean_label_indices.size (); i++)
00334 {
00335 if (euclidean_label_indices[i].indices.size () > 1000)
00336 {
00337 pcl::PointCloud<PointT> cluster;
00338 pcl::copyPointCloud (*cloud,euclidean_label_indices[i].indices,cluster);
00339 clusters.push_back (cluster);
00340 }
00341 }
00342
00343 PCL_INFO ("Got %d euclidean clusters!\n", clusters.size ());
00344 }
00345
00346 {
00347 QMutexLocker vis_locker (&vis_mtx_);
00348 prev_cloud_ = *cloud;
00349 prev_normals_ = *normal_cloud;
00350 prev_regions_ = regions;
00351 prev_distance_map_ = distance_map;
00352 prev_clusters_ = clusters;
00353 data_modified_ = true;
00354 }
00355 }
00356
00357 void
00358 OrganizedSegmentationDemo::timeoutSlot ()
00359 {
00360 {
00361 QMutexLocker vis_locker (&vis_mtx_);
00362 if (capture_ && data_modified_)
00363 {
00364 removePreviousDataFromScreen (previous_data_size_, previous_clusters_size_, vis_);
00365 if (!vis_->updatePointCloud (boost::make_shared<pcl::PointCloud<PointT> >(prev_cloud_), "cloud"))
00366 {
00367 vis_->addPointCloud (boost::make_shared<pcl::PointCloud<PointT> >(prev_cloud_), "cloud");
00368 vis_->resetCameraViewpoint ("cloud");
00369 }
00370
00371 displayPlanarRegions (prev_regions_, vis_);
00372
00373 if (display_curvature_)
00374 displayCurvature (prev_cloud_, prev_normals_, vis_);
00375 else
00376 vis_->removePointCloud ("curvature");
00377
00378 if (display_distance_map_)
00379 displayDistanceMap (prev_cloud_, prev_distance_map_, vis_);
00380 else
00381 vis_->removePointCloud ("distance_map");
00382
00383 if (display_normals_)
00384 {
00385 vis_->removePointCloud ("normals");
00386 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");
00387 vis_->setPointCloudRenderingProperties (pcl::visualization::PCL_VISUALIZER_OPACITY, 0.5, "normals");
00388 }
00389 else
00390 {
00391 vis_->removePointCloud ("normals");
00392 }
00393
00394 displayEuclideanClusters (prev_clusters_,vis_);
00395
00396 previous_data_size_ = prev_regions_.size ();
00397 previous_clusters_size_ = prev_clusters_.size ();
00398 data_modified_ = false;
00399 }
00400 }
00401
00402 ui_->qvtk_widget->update();
00403 }
00404
00405 void
00406 OrganizedSegmentationDemo::useEuclideanComparatorPressed ()
00407 {
00408 QMutexLocker locker (&mtx_);
00409 PCL_INFO ("Setting Comparator to Euclidean\n");
00410 mps.setComparator (euclidean_comparator_);
00411 }
00412
00413 void
00414 OrganizedSegmentationDemo::useRGBComparatorPressed ()
00415 {
00416 QMutexLocker locker (&mtx_);
00417 PCL_INFO ("Setting Comparator to RGB\n");
00418 mps.setComparator (rgb_comparator_);
00419 }
00420
00421 void
00422 OrganizedSegmentationDemo::usePlaneComparatorPressed ()
00423 {
00424 QMutexLocker locker (&mtx_);
00425 PCL_INFO ("Setting Comparator to Plane\n");
00426 mps.setComparator (plane_comparator_);
00427 }
00428
00429 void
00430 OrganizedSegmentationDemo::useEdgeAwareComparatorPressed ()
00431 {
00432 QMutexLocker locker (&mtx_);
00433 PCL_INFO ("Setting Comparator to edge aware\n");
00434 mps.setComparator (edge_aware_comparator_);
00435 }
00436
00437 void
00438 OrganizedSegmentationDemo::displayCurvaturePressed ()
00439 {
00440 display_curvature_ = !display_curvature_;
00441 }
00442
00443 void
00444 OrganizedSegmentationDemo::displayDistanceMapPressed ()
00445 {
00446 display_distance_map_ = !display_distance_map_;
00447 }
00448
00449 void
00450 OrganizedSegmentationDemo::displayNormalsPressed ()
00451 {
00452 display_normals_ = !display_normals_;
00453 }
00454
00455 int
00456 main (int argc, char ** argv)
00457 {
00458 QApplication app(argc, argv);
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473 pcl::OpenNIGrabber grabber ("#1");
00474
00475 OrganizedSegmentationDemo seg_demo (grabber);
00476 seg_demo.show();
00477 return (app.exec ());
00478 }