00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <ros/ros.h>
00035
00036
00037 #include <tf/transform_datatypes.h>
00038
00039
00040 #include <opencv2/highgui/highgui.hpp>
00041
00042
00043 #include <pcl16/common/common.h>
00044 #include <pcl16/common/eigen.h>
00045 #include <pcl16/common/centroid.h>
00046 #include <pcl16/ModelCoefficients.h>
00047 #include <pcl16/sample_consensus/method_types.h>
00048 #include <pcl16/sample_consensus/model_types.h>
00049 #include <pcl16/segmentation/sac_segmentation.h>
00050 #include <pcl16/segmentation/extract_clusters.h>
00051 #include <pcl16/segmentation/segment_differences.h>
00052 #include <pcl16/segmentation/organized_multi_plane_segmentation.h>
00053 #include <pcl16/search/search.h>
00054 #include <pcl16/search/kdtree.h>
00055 #include <pcl16/filters/voxel_grid.h>
00056 #include <pcl16/filters/passthrough.h>
00057 #include <pcl16/filters/extract_indices.h>
00058 #include <pcl16/surface/concave_hull.h>
00059 #include <pcl16/registration/icp.h>
00060 #include <pcl16/registration/icp_nl.h>
00061 #include <pcl16/features/integral_image_normal.h>
00062 #include <pcl16/features/normal_3d.h>
00063
00064
00065 #include <sstream>
00066
00067 #include <tabletop_pushing/point_cloud_segmentation.h>
00068 #include <tabletop_pushing/extern/Timer.hpp>
00069
00070
00071
00072
00073
00074
00075
00076 #define randf() static_cast<float>(rand())/RAND_MAX
00077
00078 typedef pcl16::search::KdTree<pcl16::PointXYZ>::Ptr KdTreePtr;
00079 typedef pcl16::search::KdTree<pcl16::PointXYZ>::KdTreeFLANNPtr KdTreeFLANNPtr;
00080 using pcl16::PointXYZ;
00081
00082 namespace tabletop_pushing
00083 {
00084
00085 PointCloudSegmentation::PointCloudSegmentation(boost::shared_ptr<tf::TransformListener> tf) : tf_(tf)
00086 {
00087 for (int i = 0; i < 200; ++i)
00088 {
00089 cv::Vec3f rand_color;
00090 rand_color[0] = randf();
00091 rand_color[1] = randf();
00092 rand_color[2] = randf();
00093 colors_.push_back(rand_color);
00094 }
00095 }
00096
00097 void PointCloudSegmentation::getTablePlane(XYZPointCloud& cloud, XYZPointCloud& objs_cloud, XYZPointCloud& plane_cloud,
00098 Eigen::Vector4f& table_centroid, bool find_hull, bool find_centroid)
00099 {
00100 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00101 long long get_table_plane_start_time = Timer::nanoTime();
00102 #endif
00103
00104 XYZPointCloud cloud_downsampled;
00105 if (use_voxel_down_)
00106 {
00107 pcl16::VoxelGrid<PointXYZ> downsample;
00108 downsample.setInputCloud(cloud.makeShared());
00109 downsample.setLeafSize(voxel_down_res_, voxel_down_res_, voxel_down_res_);
00110 downsample.filter(cloud_downsampled);
00111 }
00112 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00113 double downsample_elapsed_time = (((double)(Timer::nanoTime() - get_table_plane_start_time)) /
00114 Timer::NANOSECONDS_PER_SECOND);
00115 long long filter_cloud_z_start_time = Timer::nanoTime();
00116 #endif
00117
00118 XYZPointCloud cloud_z_filtered, cloud_filtered;
00119 pcl16::PassThrough<PointXYZ> z_pass;
00120 if (use_voxel_down_)
00121 {
00122 z_pass.setInputCloud(cloud_downsampled.makeShared());
00123 }
00124 else
00125 {
00126 z_pass.setInputCloud(cloud.makeShared());
00127 }
00128 z_pass.setFilterFieldName("z");
00129 z_pass.setFilterLimits(min_table_z_, max_table_z_);
00130 z_pass.filter(cloud_z_filtered);
00131 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00132 double filter_cloud_z_elapsed_time = (((double)(Timer::nanoTime() - filter_cloud_z_start_time)) /
00133 Timer::NANOSECONDS_PER_SECOND);
00134 long long filter_cloud_x_start_time = Timer::nanoTime();
00135 #endif
00136
00137 pcl16::PassThrough<PointXYZ> x_pass;
00138 x_pass.setInputCloud(cloud_z_filtered.makeShared());
00139 x_pass.setFilterFieldName("x");
00140 x_pass.setFilterLimits(min_workspace_x_, max_workspace_x_);
00141 x_pass.filter(cloud_filtered);
00142 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00143 double filter_cloud_x_elapsed_time = (((double)(Timer::nanoTime() - filter_cloud_x_start_time)) /
00144 Timer::NANOSECONDS_PER_SECOND);
00145 long long RANSAC_start_time = Timer::nanoTime();
00146 #endif
00147
00148 pcl16::ModelCoefficients coefficients;
00149 pcl16::PointIndices plane_inliers;
00150
00151
00152 pcl16::SACSegmentation<PointXYZ> plane_seg;
00153 plane_seg.setOptimizeCoefficients(true);
00154
00155 plane_seg.setModelType(pcl16::SACMODEL_PERPENDICULAR_PLANE);
00156 plane_seg.setMethodType(pcl16::SAC_RANSAC);
00157 plane_seg.setDistanceThreshold(table_ransac_thresh_);
00158 plane_seg.setInputCloud(cloud_filtered.makeShared());
00159 Eigen::Vector3f z_axis(0.0, 0.0, 1.0);
00160 plane_seg.setAxis(z_axis);
00161
00162 plane_seg.segment(plane_inliers, coefficients);
00163 pcl16::copyPointCloud(cloud_filtered, plane_inliers, plane_cloud);
00164
00165
00166 pcl16::ExtractIndices<PointXYZ> extract;
00167 extract.setInputCloud(cloud_filtered.makeShared());
00168 extract.setIndices(boost::make_shared<pcl16::PointIndices>(plane_inliers));
00169 extract.setNegative(true);
00170 extract.filter(objs_cloud);
00171 objs_cloud.header = cloud.header;
00172 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00173 double RANSAC_elapsed_time = (((double)(Timer::nanoTime() - RANSAC_start_time)) / Timer::NANOSECONDS_PER_SECOND);
00174 long long find_centroid_start_time = Timer::nanoTime();
00175 #endif
00176
00177 if (find_hull)
00178 {
00179 ROS_INFO_STREAM("finding concave hull. Plane size: " <<
00180 plane_cloud.size());
00181 XYZPointCloud hull_cloud;
00182 pcl16::ConcaveHull<PointXYZ> hull;
00183 hull.setInputCloud(plane_cloud.makeShared());
00184 hull.setAlpha(hull_alpha_);
00185 hull.reconstruct(hull_cloud);
00186 ROS_INFO_STREAM("hull_cloud.size() " << hull_cloud.size());
00187
00188
00189 }
00190
00191
00192 if (find_centroid)
00193 {
00194 pcl16::compute3DCentroid(plane_cloud, table_centroid);
00195 min_workspace_z_ = table_centroid[2];
00196 }
00197
00198
00199
00200
00201
00202 #ifdef PROFILE_TABLE_SEGMENTATION_TIME
00203 double get_table_plane_elapsed_time = (((double)(Timer::nanoTime() - get_table_plane_start_time)) /
00204 Timer::NANOSECONDS_PER_SECOND);
00205 double find_centroid_elapsed_time = (((double)(Timer::nanoTime() - find_centroid_start_time)) /
00206 Timer::NANOSECONDS_PER_SECOND);
00207 ROS_INFO_STREAM("\t get Table Plane Elapsed Time " << get_table_plane_elapsed_time);
00208 ROS_INFO_STREAM("\t\t downsample Elapsed Time " << downsample_elapsed_time);
00209 ROS_INFO_STREAM("\t\t filter Z Elapsed Time " << filter_cloud_z_elapsed_time);
00210 ROS_INFO_STREAM("\t\t filter X Elapsed Time " << filter_cloud_x_elapsed_time);
00211 ROS_INFO_STREAM("\t\t RANSAC Elapsed Time " << RANSAC_elapsed_time);
00212 ROS_INFO_STREAM("\t\t find Centroid Elapsed Time " << find_centroid_elapsed_time);
00213 #endif
00214
00215 }
00216
00217 void PointCloudSegmentation::getTablePlaneMPS(XYZPointCloud& input_cloud, XYZPointCloud& objs_cloud,
00218 XYZPointCloud& plane_cloud, Eigen::Vector4f& center,
00219 bool find_hull, bool find_centroid)
00220 {
00221 pcl16::IntegralImageNormalEstimation<PointXYZ, pcl16::Normal> ne;
00222 ne.setNormalEstimationMethod (ne.COVARIANCE_MATRIX);
00223 ne.setMaxDepthChangeFactor(0.03f);
00224 ne.setNormalSmoothingSize(20.0f);
00225 pcl16::PointCloud<pcl16::Normal>::Ptr normal_cloud(new pcl16::PointCloud<pcl16::Normal>);
00226 ne.setInputCloud(input_cloud.makeShared());
00227 ne.compute(*normal_cloud);
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 pcl16::OrganizedMultiPlaneSegmentation<PointXYZ, pcl16::Normal, pcl16::Label> mps;
00243 mps.setMinInliers(mps_min_inliers_);
00244 mps.setAngularThreshold(mps_min_angle_thresh_*M_PI/180.);
00245 mps.setDistanceThreshold(mps_min_dist_thresh_);
00246 mps.setInputNormals(normal_cloud);
00247 mps.setInputCloud(input_cloud.makeShared());
00248 std::vector<pcl16::PlanarRegion<PointXYZ>,
00249 Eigen::aligned_allocator<pcl16::PlanarRegion<PointXYZ> > > regions;
00250 regions.clear();
00251 std::vector<pcl16::ModelCoefficients> coefficients;
00252 std::vector<pcl16::PointIndices> point_indices;
00253 pcl16::PointCloud<pcl16::Label>::Ptr labels(new pcl16::PointCloud<pcl16::Label>());
00254 std::vector<pcl16::PointIndices> label_indices;
00255 std::vector<pcl16::PointIndices> boundary_indices;
00256 point_indices.clear();
00257 label_indices.clear();
00258 boundary_indices.clear();
00259 mps.segmentAndRefine(regions, coefficients, point_indices, labels, label_indices, boundary_indices);
00260
00261
00262
00263
00264 if (regions.size() > 0)
00265 {
00266 pcl16::copyPointCloud(input_cloud, point_indices[0], plane_cloud);
00267 center[0] = regions[0].getCentroid()[0];
00268 center[1] = regions[0].getCentroid()[1];
00269 center[2] = regions[0].getCentroid()[2];
00270 center[3] = 1.0;
00271
00272
00273 pcl16::ExtractIndices<PointXYZ> extract;
00274 extract.setInputCloud(input_cloud.makeShared());
00275 extract.setIndices(boost::make_shared<pcl16::PointIndices>(point_indices[0]));
00276 extract.setNegative(true);
00277 extract.filter(objs_cloud);
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290 }
00291
00292
00301 void PointCloudSegmentation::findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs, bool use_mps)
00302 {
00303 XYZPointCloud objs_cloud;
00304 findTabletopObjects(input_cloud, objs, objs_cloud, use_mps);
00305 }
00306
00316 void PointCloudSegmentation::findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs,
00317 XYZPointCloud& objs_cloud, bool use_mps)
00318 {
00319 XYZPointCloud table_cloud;
00320 findTabletopObjects(input_cloud, objs, objs_cloud, table_cloud, use_mps);
00321 }
00322
00333 void PointCloudSegmentation::findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs,
00334 XYZPointCloud& objs_cloud,
00335 XYZPointCloud& plane_cloud, bool use_mps)
00336 {
00337 #ifdef PROFILE_OBJECT_SEGMENTATION_TIME
00338 long long find_tabletop_objects_start_time = Timer::nanoTime();
00339 #endif
00340
00341
00342 if (use_mps)
00343 {
00344 getTablePlaneMPS(input_cloud, objs_cloud, plane_cloud, table_centroid_, false);
00345 }
00346 else
00347 {
00348 getTablePlane(input_cloud, objs_cloud, plane_cloud, table_centroid_, false);
00349 }
00350
00351 #ifdef PROFILE_OBJECT_SEGMENTATION_TIME
00352 double segment_table_elapsed_time = (((double)(Timer::nanoTime() - find_tabletop_objects_start_time)) /
00353 Timer::NANOSECONDS_PER_SECOND);
00354 long long cluster_objects_start_time = Timer::nanoTime();
00355 #endif
00356
00357
00358
00359
00360 XYZPointCloud objects_cloud_down;
00361 downsampleCloud(objs_cloud, objects_cloud_down);
00362
00363 if (objects_cloud_down.size() > 0)
00364 {
00365 clusterProtoObjects(objects_cloud_down, objs);
00366 }
00367
00368 #ifdef PROFILE_OBJECT_SEGMENTATION_TIME
00369 double find_tabletop_objects_elapsed_time = (((double)(Timer::nanoTime() - find_tabletop_objects_start_time)) /
00370 Timer::NANOSECONDS_PER_SECOND);
00371 double cluster_objects_elapsed_time = (((double)(Timer::nanoTime() - cluster_objects_start_time)) /
00372 Timer::NANOSECONDS_PER_SECOND);
00373 ROS_INFO_STREAM("find_tabletop_objects_elapsed_time " << find_tabletop_objects_elapsed_time);
00374 if (use_mps)
00375 {
00376 ROS_INFO_STREAM("\t segment Table MPS Time " << segment_table_elapsed_time);
00377 }
00378 else
00379 {
00380 ROS_INFO_STREAM("\t segment table RANSAC Time " << segment_table_elapsed_time);
00381 }
00382 ROS_INFO_STREAM("\t cluster_objects_elapsed_time " << cluster_objects_elapsed_time << "\n");
00383 #endif
00384
00385 }
00386
00393 void PointCloudSegmentation::clusterProtoObjects(XYZPointCloud& objects_cloud, ProtoObjects& objs)
00394 {
00395 #ifdef PROFILE_OBJECT_CLUSTER_TIME
00396 long long cluster_objects_start_time = Timer::nanoTime();
00397 #endif
00398 std::vector<pcl16::PointIndices> clusters;
00399 pcl16::EuclideanClusterExtraction<PointXYZ> pcl_cluster;
00400 const KdTreePtr clusters_tree(new pcl16::search::KdTree<PointXYZ>);
00401 clusters_tree->setInputCloud(objects_cloud.makeShared());
00402
00403 pcl_cluster.setClusterTolerance(cluster_tolerance_);
00404 pcl_cluster.setMinClusterSize(min_cluster_size_);
00405 pcl_cluster.setMaxClusterSize(max_cluster_size_);
00406 pcl_cluster.setSearchMethod(clusters_tree);
00407 pcl_cluster.setInputCloud(objects_cloud.makeShared());
00408 pcl_cluster.extract(clusters);
00409 ROS_DEBUG_STREAM("Number of clusters found matching the given constraints: "
00410 << clusters.size());
00411 #ifdef PROFILE_OBJECT_CLUSTER_TIME
00412 double pcl_cluster_elapsed_time = (((double)(Timer::nanoTime() - cluster_objects_start_time)) /
00413 Timer::NANOSECONDS_PER_SECOND);
00414 long long proto_object_start_time = Timer::nanoTime();
00415 #endif
00416
00417 for (unsigned int i = 0; i < clusters.size(); ++i)
00418 {
00419
00420 ProtoObject po;
00421 po.push_history.clear();
00422 po.boundary_angle_dist.clear();
00423 pcl16::copyPointCloud(objects_cloud, clusters[i], po.cloud);
00424 pcl16::compute3DCentroid(po.cloud, po.centroid);
00425 po.id = i;
00426 po.moved = false;
00427 po.transform = Eigen::Matrix4f::Identity();
00428 po.singulated = false;
00429 objs.push_back(po);
00430 }
00431 #ifdef PROFILE_OBJECT_CLUSTER_TIME
00432 double cluster_objects_elapsed_time = (((double)(Timer::nanoTime() - cluster_objects_start_time)) /
00433 Timer::NANOSECONDS_PER_SECOND);
00434 double proto_object_elapsed_time = (((double)(Timer::nanoTime() - proto_object_start_time)) /
00435 Timer::NANOSECONDS_PER_SECOND);
00436 ROS_INFO_STREAM("\t cluster_objects_elapsed_time " << cluster_objects_elapsed_time);
00437 ROS_INFO_STREAM("\t\t pcl_cluster_elapsed_time " << pcl_cluster_elapsed_time);
00438 ROS_INFO_STREAM("\t\t proto_object_elapsed_time " << proto_object_elapsed_time);
00439 #endif
00440
00441 }
00442
00451 double PointCloudSegmentation::ICPProtoObjects(ProtoObject& a, ProtoObject& b,
00452 Eigen::Matrix4f& transform)
00453 {
00454
00455
00456 pcl16::IterativeClosestPoint<PointXYZ, PointXYZ> icp;
00457 icp.setMaximumIterations(icp_max_iters_);
00458 icp.setTransformationEpsilon(icp_transform_eps_);
00459 icp.setMaxCorrespondenceDistance(icp_max_cor_dist_);
00460 icp.setRANSACOutlierRejectionThreshold(icp_ransac_thresh_);
00461 icp.setInputCloud(boost::make_shared<XYZPointCloud>(a.cloud));
00462 icp.setInputTarget(boost::make_shared<XYZPointCloud>(b.cloud));
00463 XYZPointCloud aligned;
00464 icp.align(aligned);
00465 double score = icp.getFitnessScore();
00466 transform = icp.getFinalTransformation();
00467 return score;
00468 }
00469
00479 double PointCloudSegmentation::ICPBoundarySamples(XYZPointCloud& hull_t_0, XYZPointCloud& hull_t_1,
00480 Eigen::Matrix4f& transform, XYZPointCloud& aligned)
00481 {
00482
00483 pcl16::IterativeClosestPointNonLinear<PointXYZ, PointXYZ> icp;
00484
00485 icp.setMaximumIterations(icp_max_iters_);
00486 icp.setTransformationEpsilon(icp_transform_eps_);
00487 icp.setMaxCorrespondenceDistance(icp_max_cor_dist_);
00488 icp.setRANSACOutlierRejectionThreshold(icp_ransac_thresh_);
00489 icp.setInputCloud(boost::make_shared<XYZPointCloud>(hull_t_0));
00490 icp.setInputTarget(boost::make_shared<XYZPointCloud>(hull_t_1));
00491 icp.align(aligned);
00492 double score = icp.getFitnessScore();
00493 transform = icp.getFinalTransformation();
00494 return score;
00495 }
00496
00505 void PointCloudSegmentation::getMovedRegions(XYZPointCloud& prev_cloud, XYZPointCloud& cur_cloud,
00506 ProtoObjects& moved, std::string suf)
00507 {
00508
00509 pcl16::SegmentDifferences<PointXYZ> pcl_diff;
00510 pcl_diff.setDistanceThreshold(cloud_diff_thresh_);
00511 pcl_diff.setInputCloud(prev_cloud.makeShared());
00512 pcl_diff.setTargetCloud(cur_cloud.makeShared());
00513 XYZPointCloud cloud_out;
00514 pcl_diff.segment(cloud_out);
00515 if (cloud_out.size() < 1)
00516 {
00517 ROS_INFO_STREAM("Returning nothing moved as there are no points.");
00518 return;
00519 }
00520
00521 clusterProtoObjects(cloud_out, moved);
00522
00523 #ifdef DISPLAY_CLOUD_DIFF
00524 cv::Size img_size(320, 240);
00525 cv::Mat moved_img = projectProtoObjectsIntoImage(moved, img_size, prev_cloud.header.frame_id);
00526 std::stringstream cluster_title;
00527 cluster_title << "moved clusters" << suf;
00528 displayObjectImage(moved_img, cluster_title.str());
00529 #endif // DISPLAY_CLOUD_DIFF
00530 }
00531
00539 void PointCloudSegmentation::matchMovedRegions(ProtoObjects& objs,
00540 ProtoObjects& moved_regions)
00541 {
00542
00543 for (unsigned int i = 0; i < moved_regions.size(); ++i)
00544 {
00545 for (unsigned int j = 0; j < objs.size(); ++j)
00546 {
00547 if(cloudsIntersect(objs[j].cloud, moved_regions[i].cloud))
00548 {
00549 if (!objs[j].moved)
00550 {
00551 objs[j].moved = true;
00552 }
00553 }
00554 }
00555 }
00556 }
00557
00565 void PointCloudSegmentation::fitCylinderRANSAC(ProtoObject& obj, XYZPointCloud& cylinder_cloud,
00566 pcl16::ModelCoefficients& coefficients)
00567 {
00568 pcl16::NormalEstimation<PointXYZ, pcl16::Normal> ne;
00569 ne.setInputCloud(obj.cloud.makeShared());
00570 pcl16::search::KdTree<PointXYZ>::Ptr tree (new pcl16::search::KdTree<PointXYZ> ());
00571 ne.setSearchMethod (tree);
00572 ne.setRadiusSearch (0.03);
00573 ne.compute(obj.normals);
00574
00575
00576 Eigen::Vector3f z_axis(0.0,0.0,1.0);
00577 pcl16::PointIndices cylinder_inliers;
00578 pcl16::SACSegmentationFromNormals<PointXYZ,pcl16::Normal> cylinder_seg;
00579 cylinder_seg.setOptimizeCoefficients(optimize_cylinder_coefficients_);
00580 cylinder_seg.setModelType(pcl16::SACMODEL_CYLINDER);
00581 cylinder_seg.setMethodType(pcl16::SAC_RANSAC);
00582 cylinder_seg.setDistanceThreshold(cylinder_ransac_thresh_);
00583 cylinder_seg.setAxis(z_axis);
00584
00585 cylinder_seg.setInputCloud(obj.cloud.makeShared());
00586 cylinder_seg.setInputNormals(obj.normals.makeShared());
00587 cylinder_seg.segment(cylinder_inliers, coefficients);
00588
00589 pcl16::copyPointCloud(obj.cloud, cylinder_inliers, cylinder_cloud);
00590 }
00591
00599 void PointCloudSegmentation::fitSphereRANSAC(ProtoObject& obj, XYZPointCloud& sphere_cloud,
00600 pcl16::ModelCoefficients& coefficients)
00601 {
00602
00603 pcl16::PointIndices sphere_inliers;
00604 pcl16::SACSegmentation<PointXYZ> sphere_seg;
00605 sphere_seg.setOptimizeCoefficients(true);
00606 sphere_seg.setModelType(pcl16::SACMODEL_SPHERE);
00607 sphere_seg.setMethodType(pcl16::SAC_RANSAC);
00608 sphere_seg.setDistanceThreshold(sphere_ransac_thresh_);
00609 sphere_seg.setInputCloud(obj.cloud.makeShared());
00610 sphere_seg.segment(sphere_inliers, coefficients);
00611
00612 pcl16::copyPointCloud(obj.cloud, sphere_inliers, sphere_cloud);
00613 }
00614
00625 bool PointCloudSegmentation::cloudsIntersect(XYZPointCloud cloud0, XYZPointCloud cloud1)
00626 {
00627 int moved_count = 0;
00628 for (unsigned int i = 0; i < cloud0.size(); ++i)
00629 {
00630 const PointXYZ pt0 = cloud0.at(i);
00631 for (unsigned int j = 0; j < cloud1.size(); ++j)
00632 {
00633 const PointXYZ pt1 = cloud1.at(j);
00634 if (dist(pt0, pt1) < cloud_intersect_thresh_)
00635 {
00636 moved_count++;
00637 }
00638 if (moved_count > moved_count_thresh_)
00639 {
00640 return true;
00641 }
00642 }
00643 }
00644 return false;
00645 }
00646
00647 bool PointCloudSegmentation::cloudsIntersect(XYZPointCloud cloud0, XYZPointCloud cloud1, double thresh)
00648 {
00649 for (unsigned int i = 0; i < cloud0.size(); ++i)
00650 {
00651 const PointXYZ pt0 = cloud0.at(i);
00652 for (unsigned int j = 0; j < cloud1.size(); ++j)
00653 {
00654 const PointXYZ pt1 = cloud1.at(j);
00655 if (dist(pt0, pt1) < thresh) return true;
00656 }
00657 }
00658 return false;
00659 }
00660
00661 bool PointCloudSegmentation::pointIntersectsCloud(XYZPointCloud cloud, geometry_msgs::Point pt, double thresh)
00662 {
00663 for (unsigned int i = 0; i < cloud.size(); ++i)
00664 {
00665 const PointXYZ pt_c = cloud.at(i);
00666 if (dist(pt_c, pt) < thresh) return true;
00667 }
00668 return false;
00669 }
00670
00671 float PointCloudSegmentation::pointLineXYDist(PointXYZ p, Eigen::Vector3f vec, Eigen::Vector4f base)
00672 {
00673 Eigen::Vector3f x0(p.x,p.y,0.0);
00674 Eigen::Vector3f x1(base[0],base[1],0.0);
00675 Eigen::Vector3f x2 = x1+vec;
00676 Eigen::Vector3f num = (x0 - x1);
00677 num = num.cross(x0 - x2);
00678 Eigen::Vector3f den = x2 - x1;
00679 float d = num.norm()/den.norm();
00680 return d;
00681 }
00682
00683 void PointCloudSegmentation::lineCloudIntersection(XYZPointCloud& cloud, Eigen::Vector3f vec,
00684 Eigen::Vector4f base, XYZPointCloud& line_cloud)
00685 {
00686
00687
00688
00689 pcl16::PointIndices line_inliers;
00690 for (unsigned int i = 0; i < cloud.size(); ++i)
00691 {
00692 const PointXYZ pt = cloud.at(i);
00693 if (pointLineXYDist(pt, vec, base) < cloud_intersect_thresh_)
00694 {
00695 line_inliers.indices.push_back(i);
00696 }
00697 }
00698
00699
00700 pcl16::ExtractIndices<PointXYZ> extract;
00701 extract.setInputCloud(cloud.makeShared());
00702 extract.setIndices(boost::make_shared<pcl16::PointIndices>(line_inliers));
00703 extract.filter(line_cloud);
00704 }
00705
00706 void PointCloudSegmentation::lineCloudIntersectionEndPoints(XYZPointCloud& cloud, Eigen::Vector3f vec,
00707 Eigen::Vector4f base, std::vector<PointXYZ>& points)
00708 {
00709 XYZPointCloud intersection;
00710 lineCloudIntersection(cloud, vec, base, intersection);
00711 unsigned int min_y_idx = intersection.size();
00712 unsigned int max_y_idx = intersection.size();
00713 unsigned int min_x_idx = intersection.size();
00714 unsigned int max_x_idx = intersection.size();
00715 float min_y = FLT_MAX;
00716 float max_y = -FLT_MAX;
00717 float min_x = FLT_MAX;
00718 float max_x = -FLT_MAX;
00719 for (unsigned int i = 0; i < intersection.size(); ++i)
00720 {
00721 if (intersection.at(i).y < min_y)
00722 {
00723 min_y = intersection.at(i).y;
00724 min_y_idx = i;
00725 }
00726 if (intersection.at(i).y > max_y)
00727 {
00728 max_y = intersection.at(i).y;
00729 max_y_idx = i;
00730 }
00731 if (intersection.at(i).x < min_x)
00732 {
00733 min_x = intersection.at(i).x;
00734 min_x_idx = i;
00735 }
00736 if (intersection.at(i).x > max_x)
00737 {
00738 max_x = intersection.at(i).x;
00739 max_x_idx = i;
00740 }
00741 }
00742 const double y_dist_obs = max_y - min_y;
00743 const double x_dist_obs = max_x - min_x;
00744 int start_idx = min_x_idx;
00745 int end_idx = max_x_idx;
00746
00747 if (x_dist_obs > y_dist_obs)
00748 {
00749
00750 if (vec[0] > 0)
00751 {
00752
00753 start_idx = min_x_idx;
00754 end_idx = max_x_idx;
00755 }
00756 else
00757 {
00758
00759 start_idx = max_x_idx;
00760 end_idx = min_x_idx;
00761 }
00762 }
00763 else
00764 {
00765
00766 if (vec[1] > 0)
00767 {
00768
00769 start_idx = min_y_idx;
00770 end_idx = max_y_idx;
00771 }
00772 else
00773 {
00774
00775 start_idx = max_y_idx;
00776 end_idx = min_y_idx;
00777 }
00778 }
00779 PointXYZ start_point, end_point;
00780 start_point.x = intersection.at(start_idx).x;
00781 start_point.y = intersection.at(start_idx).y;
00782 start_point.z = intersection.at(start_idx).z;
00783 end_point.x = intersection.at(end_idx).x;
00784 end_point.y = intersection.at(end_idx).y;
00785 end_point.z = intersection.at(end_idx).z;
00786 points.push_back(start_point);
00787 points.push_back(end_point);
00788 }
00789
00798 void PointCloudSegmentation::downsampleCloud(XYZPointCloud& cloud_in, XYZPointCloud& cloud_down)
00799 {
00800 XYZPointCloud cloud_z_filtered, cloud_x_filtered;
00801 pcl16::PassThrough<PointXYZ> z_pass;
00802 z_pass.setFilterFieldName("z");
00803 ROS_DEBUG_STREAM("Number of points in cloud_in is: " <<
00804 cloud_in.size());
00805 z_pass.setInputCloud(cloud_in.makeShared());
00806 z_pass.setFilterLimits(min_workspace_z_, max_workspace_z_);
00807 z_pass.filter(cloud_z_filtered);
00808 ROS_DEBUG_STREAM("Number of points in cloud_z_filtered is: " <<
00809 cloud_z_filtered.size());
00810
00811 pcl16::PassThrough<PointXYZ> x_pass;
00812 x_pass.setInputCloud(cloud_z_filtered.makeShared());
00813 x_pass.setFilterFieldName("x");
00814 x_pass.setFilterLimits(min_workspace_x_, max_workspace_x_);
00815 x_pass.filter(cloud_x_filtered);
00816
00817 pcl16::VoxelGrid<PointXYZ> downsample_outliers;
00818 downsample_outliers.setInputCloud(cloud_x_filtered.makeShared());
00819 downsample_outliers.setLeafSize(voxel_down_res_, voxel_down_res_,
00820 voxel_down_res_);
00821 downsample_outliers.filter(cloud_down);
00822 ROS_DEBUG_STREAM("Number of points in objs_downsampled: " <<
00823 cloud_down.size());
00824 }
00825
00835 cv::Mat PointCloudSegmentation::projectProtoObjectsIntoImage(ProtoObjects& objs, cv::Size img_size,
00836 std::string target_frame)
00837 {
00838 cv::Mat obj_img(img_size, CV_8UC1, cv::Scalar(0));
00839 for (unsigned int i = 0; i < objs.size(); ++i)
00840 {
00841 projectPointCloudIntoImage(objs[i].cloud, obj_img,
00842 cur_camera_header_.frame_id, i+1);
00843 }
00844
00845 return obj_img;
00846 }
00847
00857 cv::Mat PointCloudSegmentation::projectProtoObjectIntoImage(ProtoObject& obj, cv::Size img_size,
00858 std::string target_frame)
00859 {
00860 cv::Mat obj_img(img_size, CV_8UC1, cv::Scalar(0));
00861 projectPointCloudIntoImage(obj.cloud, obj_img, cur_camera_header_.frame_id, 1);
00862 return obj_img;
00863 }
00864
00871 cv::Mat PointCloudSegmentation::displayObjectImage(cv::Mat& obj_img,
00872 std::string win_name,
00873 bool use_display)
00874 {
00875 cv::Mat obj_disp_img(obj_img.size(), CV_32FC3, cv::Scalar(0.0,0.0,0.0));
00876 for (int r = 0; r < obj_img.rows; ++r)
00877 {
00878 for (int c = 0; c < obj_img.cols; ++c)
00879 {
00880 unsigned int id = obj_img.at<uchar>(r,c);
00881 if (id > 0)
00882 {
00883 obj_disp_img.at<cv::Vec3f>(r,c) = colors_[id-1];
00884 }
00885 }
00886 }
00887 if (use_display)
00888 {
00889 cv::imshow(win_name, obj_disp_img);
00890 }
00891 return obj_disp_img;
00892 }
00893
00894 void PointCloudSegmentation::projectPointCloudIntoImage(XYZPointCloud& cloud,
00895 cv::Mat& lbl_img,
00896 std::string target_frame,
00897 unsigned int id)
00898 {
00899 for (unsigned int i = 0; i < cloud.size(); ++i)
00900 {
00901 cv::Point img_idx = projectPointIntoImage(cloud.at(i),
00902 cloud.header.frame_id,
00903 target_frame);
00904 lbl_img.at<uchar>(img_idx.y, img_idx.x) = id;
00905 }
00906 }
00907
00908 cv::Point PointCloudSegmentation::projectPointIntoImage(Eigen::Vector3f cur_point_eig,
00909 std::string point_frame,
00910 std::string target_frame)
00911 {
00912 geometry_msgs::PointStamped cur_point;
00913 cur_point.header.frame_id = point_frame;
00914 cur_point.point.x = cur_point_eig[0];
00915 cur_point.point.y = cur_point_eig[1];
00916 cur_point.point.z = cur_point_eig[2];
00917 return projectPointIntoImage(cur_point, target_frame);
00918 }
00919
00920 cv::Point PointCloudSegmentation::projectPointIntoImage(PointXYZ cur_point_pcl,
00921 std::string point_frame,
00922 std::string target_frame)
00923 {
00924 geometry_msgs::PointStamped cur_point;
00925 cur_point.header.frame_id = point_frame;
00926 cur_point.point.x = cur_point_pcl.x;
00927 cur_point.point.y = cur_point_pcl.y;
00928 cur_point.point.z = cur_point_pcl.z;
00929 return projectPointIntoImage(cur_point, target_frame);
00930 }
00931
00932 void PointCloudSegmentation::projectPointCloudIntoImage(XYZPointCloud& cloud,
00933 cv::Mat& lbl_img)
00934 {
00935 for (unsigned int i = 0; i < cloud.size(); ++i)
00936 {
00937 cv::Point img_idx = projectPointIntoImage(cloud.at(i),
00938 cloud.header.frame_id,
00939 cur_camera_header_.frame_id);
00940 lbl_img.at<uchar>(img_idx.y, img_idx.x) = 1;
00941 }
00942 }
00943
00944 cv::Point PointCloudSegmentation::projectPointIntoImage(
00945 geometry_msgs::PointStamped cur_point)
00946 {
00947 return projectPointIntoImage(cur_point, cur_camera_header_.frame_id);
00948 }
00949
00950 cv::Point PointCloudSegmentation::projectPointIntoImage(
00951 geometry_msgs::PointStamped cur_point, std::string target_frame)
00952 {
00953 cv::Point img_loc;
00954 try
00955 {
00956
00957 geometry_msgs::PointStamped image_frame_loc_m;
00958 tf_->transformPoint(target_frame, cur_point, image_frame_loc_m);
00959
00960
00961 img_loc.x = static_cast<int>((cam_info_.K[0]*image_frame_loc_m.point.x +
00962 cam_info_.K[2]*image_frame_loc_m.point.z) /
00963 image_frame_loc_m.point.z);
00964 img_loc.y = static_cast<int>((cam_info_.K[4]*image_frame_loc_m.point.y +
00965 cam_info_.K[5]*image_frame_loc_m.point.z) /
00966 image_frame_loc_m.point.z);
00967
00968
00969 for (int i = 0; i < num_downsamples_; ++i)
00970 {
00971 img_loc.x /= 2;
00972 img_loc.y /= 2;
00973 }
00974 }
00975 catch (tf::TransformException e)
00976 {
00977 ROS_ERROR_STREAM("Error projecting 3D point into image plane.");
00978
00979 ROS_ERROR_STREAM("cur point header is: " << cur_point.header.frame_id);
00980 ROS_ERROR_STREAM("target frame is: " << target_frame);
00981 }
00982 return img_loc;
00983 }
00984
00985 };