SphereSegmentation.cpp
Go to the documentation of this file.
00001 /*
00002  * SphereSegmentation.cpp
00003  *
00004  *  Created on: Sep 19, 2012
00005  *      Author: jnicho
00006  */
00007 
00008 #include <perception_tools/segmentation/SphereSegmentation.h>
00009 #include <tf_conversions/tf_eigen.h>
00010 #include <sensor_msgs/PointCloud2.h>
00011 #include <sensor_msgs/point_cloud_conversion.h>
00012 #include <boost/assign.hpp>
00013 #include <boost/shared_ptr.hpp>
00014 #include <boost/make_shared.hpp>
00015 #include <pcl/common/transforms.h> // allows conversions between ros msgs and pcl types
00016 #include <pcl/surface/convex_hull.h>
00017 #include <pcl/segmentation/extract_clusters.h>
00018 #include <pcl/filters/passthrough.h>
00019 #include <pcl/filters/project_inliers.h>
00020 #include <pcl/filters/extract_indices.h>
00021 #include <pcl/segmentation/extract_polygonal_prism_data.h>
00022 #include <cmath>
00023 
00024 
00025 SphereSegmentation::SphereSegmentation()
00026 :_Parameters(),
00027  _LastSphereSegCluster(),
00028  _LastCoefficients(),
00029  _LastIndices(),
00030  _LastSphereSegSuccess(false)
00031 {
00032         // TODO Auto-generated constructor stub
00033 
00034 }
00035 
00036 SphereSegmentation::~SphereSegmentation() {
00037         // TODO Auto-generated destructor stub
00038 }
00039 
00040 void SphereSegmentation::setParameters(const SphereSegmentation::Parameters &parameters)
00041 {
00042         _Parameters = parameters;
00043 }
00044 
00045 SphereSegmentation::Parameters SphereSegmentation::getParameters()
00046 {
00047         return _Parameters;
00048 }
00049 
00050 void SphereSegmentation::fetchParameters(std::string nameSpace)
00051 {
00052         _Parameters.fetchParameters(nameSpace);
00053 }
00054 
00055 bool SphereSegmentation::segment(const sensor_msgs::PointCloud &cloudMsg,arm_navigation_msgs::CollisionObject &obj)
00056 {
00057         // declaring cloud objs and messages
00058         sensor_msgs::PointCloud2 intermediateCloudMsg;
00059         sensor_msgs::convertPointCloudToPointCloud2(cloudMsg,intermediateCloudMsg);
00060         return segment(intermediateCloudMsg,obj);
00061 }
00062 
00063 void SphereSegmentation::getSphereCluster(sensor_msgs::PointCloud &cluster)
00064 {
00065         if(_LastSphereSegSuccess)
00066         {
00067                 cluster.points.clear();
00068                 sensor_msgs::PointCloud2 tempCloud;
00069                 pcl::toROSMsg(_LastSphereSegCluster,tempCloud);
00070                 sensor_msgs::convertPointCloud2ToPointCloud(tempCloud,cluster);
00071         }
00072 }
00073 
00074 bool SphereSegmentation::segment(const sensor_msgs::PointCloud2 &cloudMsg,arm_navigation_msgs::CollisionObject &obj)
00075 {
00076         // cloud objs
00077         Cloud3D cluster = Cloud3D();
00078 
00079         // converting cloud msg to pcl cloud
00080         pcl::fromROSMsg(cloudMsg,cluster);
00081 
00082         return segment(cluster,obj);
00083 }
00084 
00085 bool SphereSegmentation::segment(const std::vector<sensor_msgs::PointCloud> &clusters, arm_navigation_msgs::CollisionObject &obj,
00086                 int &bestClusterIndex)
00087 {
00088         // find best fitting cloud
00089         double score = 0.0f;
00090         bool success = false;
00091         arm_navigation_msgs::CollisionObject currentObj;
00092         Cloud3D bestCluster;
00093         pcl::PointIndices bestIndices;
00094         pcl::ModelCoefficients bestCoefficients;
00095         bool bestSeg;
00096 
00097         for(unsigned int i = 0; i < clusters.size(); i++)
00098         {
00099                 success = segment(clusters[i],currentObj);
00100                 if(success)
00101                 {
00102                         if(_LastSegmentationScore > score)
00103                         {
00104                                 bestClusterIndex = i;
00105                                 obj.header.frame_id = currentObj.header.frame_id;
00106                                 obj.id = currentObj.id;
00107                                 obj.poses = currentObj.poses;
00108                                 obj.padding = currentObj.padding;
00109                                 obj.shapes = currentObj.shapes;
00110                                 bestCluster = _LastSphereSegCluster;
00111                                 bestIndices = _LastIndices;
00112                                 bestCoefficients = _LastCoefficients;
00113                                 score = _LastSegmentationScore;
00114 
00115                         }
00116                 }
00117         }
00118 
00119         // saving best cluster found
00120         _LastSphereSegCluster = bestCluster;
00121         _LastIndices = bestIndices;
00122         _LastCoefficients = bestCoefficients;
00123         _LastSphereSegSuccess = success;
00124 
00125         return success;
00126 }
00127 
00128 bool SphereSegmentation::segment(const Cloud3D &cluster,arm_navigation_msgs::CollisionObject &obj)
00129 {
00130         std::string nodeName = ros::this_node::getName() + "/segmentation";
00131 
00132         // cloud objs
00133         Cloud3D cloud = Cloud3D();
00134         pcl::copyPointCloud(cluster,cloud);
00135 
00136         // will perform recognition in world coordinates so cloud points need to be transformed;
00137         tf::StampedTransform clusterInWorld; clusterInWorld.setIdentity();
00138         std::string clusterFrameId = cloud.header.frame_id;
00139 
00140         try
00141         {
00142                 _TfListener.lookupTransform(_Parameters.WorldFrameId,clusterFrameId,ros::Time(0),clusterInWorld);
00143         }
00144         catch(tf::TransformException ex)
00145         {
00146                 ROS_ERROR("%s",std::string(nodeName + " , failed to resolve transform from " +
00147                                 _Parameters.WorldFrameId + " to " + clusterFrameId + " \n\t\t" + " tf error msg: " +  ex.what()).c_str());
00148                 ROS_WARN("%s",std::string(nodeName + ": Will use Identity as cluster transform").c_str());
00149         }
00150 
00151         // transforming cloud points to world coordinates
00152         Eigen::Affine3d tfEigen;
00153         tf::TransformTFToEigen(clusterInWorld,tfEigen);
00154         pcl::transformPointCloud(cloud,cloud,Eigen::Affine3f(tfEigen));
00155 
00156         // filtering bounds
00157         //filterBounds(cloud);
00158 
00159         // finding top centroid point
00160         bool centroidFound = false;
00161         pcl::PointXYZ topCentroid;
00162         centroidFound = findTopCentroid(cloud,topCentroid);
00163 
00164         // filtering prism
00165         if(centroidFound)
00166         {
00167                 filterWithPolygonalPrism(cloud,topCentroid,20,_Parameters.MaxRadius,1.5f*_Parameters.MaxRadius,0.0f);
00168                 ROS_INFO_STREAM(nodeName<<": Polygonal prism extraction found "<< cloud.points.size()<<" points");
00169         }
00170         else
00171         {
00172                 ROS_WARN_STREAM(nodeName<<": did not find top centroid, skipping polygonal prism extraction");
00173         }
00174 
00175         // declaring sphere segmentation objs
00176         pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());// x, y, z, R are the values returned in that order
00177         pcl::PointIndices::Ptr inliers(new pcl::PointIndices());
00178 
00179         if(!performSphereSegmentation(cloud,coefficients,inliers))
00180         {
00181 
00182                 // resetting results
00183                 _LastIndices = pcl::PointIndices();
00184                 _LastCoefficients = pcl::ModelCoefficients();
00185                 _LastSphereSegCluster.clear();
00186                 _LastSphereSegSuccess = false;
00187 
00188                 ROS_ERROR_STREAM(nodeName<<": insufficient inliers found "<<inliers->indices.size()<<", exiting segmentation");
00189 
00190                 return false;
00191         }
00192         else
00193         {
00194                 ROS_INFO_STREAM(nodeName<<": found "<<inliers->indices.size()<<" total inliers");
00195 
00196                 // storing segmented sphere cluster
00197                 pcl::ExtractIndices<pcl::PointXYZ> extract;
00198                 extract.setIndices(inliers);
00199                 extract.setInputCloud(boost::make_shared<Cloud3D>(cloud));
00200                 extract.setNegative(false);
00201                 _LastSphereSegCluster.clear();
00202                 extract.filter(_LastSphereSegCluster);
00203                 _LastSphereSegCluster.header = cloud.header;
00204 
00205                 // storing results
00206                 _LastIndices = *inliers;
00207                 _LastCoefficients = *coefficients;
00208                 _LastSphereSegSuccess = true;
00209         }
00210 
00211         if(_Parameters.AlignToTopCentroid && centroidFound)
00212         {
00213                 coefficients->values[0] = topCentroid.x;
00214                 coefficients->values[1] = topCentroid.y;
00215                 coefficients->values[2] = topCentroid.z - coefficients->values[3]; // top z - radius
00216                 ROS_INFO_STREAM(nodeName<<": Aligned to top centroid");
00217         }
00218         else
00219         {
00220                 ROS_WARN_STREAM(nodeName<<": did not find top centroid");
00221         }
00222 
00223         ROS_INFO_STREAM(nodeName<<": segmentation succeeded");
00224         createObject(*coefficients,obj);
00225 
00226         return true;
00227 }
00228 
00229 bool SphereSegmentation::performSphereSegmentation(const Cloud3D &cloud,pcl::ModelCoefficients::Ptr coefficients,
00230                 pcl::PointIndices::Ptr inliers)
00231 {
00232         using namespace pcl;
00233 
00234         // pcl objects
00235         NormalEstimation<PointXYZ,Normal> normalEstm;
00236         SACSegmentationFromNormals<PointXYZ,Normal> seg;
00237         ExtractIndices<PointXYZ> extractPoints;
00238         ExtractIndices<Normal> extractNormals;
00239         pcl::search::KdTree<PointXYZ>::Ptr searchTree = boost::make_shared< pcl::search::KdTree<PointXYZ> >();
00240 
00241         // pcl dataholders
00242         PointCloud<Normal>::Ptr cloudNormals(new PointCloud<Normal>());
00243         Cloud3D::Ptr cloudPtr = boost::make_shared<Cloud3D>(cloud);
00244 
00245         // normal estimation
00246         normalEstm.setSearchMethod(searchTree);
00247         normalEstm.setInputCloud(cloudPtr);
00248         normalEstm.setKSearch(_Parameters.KNearestNeighbors);
00249         normalEstm.compute(*cloudNormals);
00250 
00251         // sphere segmentation
00252         seg.setOptimizeCoefficients(true);
00253         seg.setModelType(SACMODEL_SPHERE);
00254         seg.setMethodType(SAC_RANSAC);
00255         seg.setNormalDistanceWeight(_Parameters.NormalDistanceWeight);
00256         seg.setMaxIterations(_Parameters.MaxIterations);
00257         seg.setDistanceThreshold(_Parameters.DistanceThreshold);
00258         seg.setRadiusLimits(0.0f,_Parameters.MaxRadius);
00259         seg.setInputCloud(cloudPtr);
00260         seg.setInputNormals(cloudNormals);
00261         seg.segment(*inliers,*coefficients);
00262 
00263         // computing score
00264         //_LastSegmentationScore = ((double)inliers->indices.size())/((double)cloud.points.size());
00265         _LastSegmentationScore = (double)inliers->indices.size(); // using number of inliers as score
00266 
00267         if(inliers->indices.size() == 0 || _LastSegmentationScore < _Parameters.MinFitnessScore)
00268         {
00269                 //_LastSegmentationScore = 0.0f;
00270                 return false;
00271         }
00272         else
00273         {
00274                 return true;
00275         }
00276 }
00277 
00278 bool SphereSegmentation::findSphereUsingTopPoint(const Cloud3D &cloud,pcl::ModelCoefficients::Ptr coefficients,
00279                 pcl::PointIndices::Ptr inliers)
00280 {
00281         std::string nodeName = ros::this_node::getName() + "/segmentation";
00282         std::stringstream stdOut;
00283 
00284         pcl::PointXYZ centroid;
00285         if(!findTopCentroid(cloud,centroid))
00286         {
00287                 return false;
00288         }
00289 
00290         // filling sphere coefficients, the sphere center is assumed to be located below the centroid by a distance equal to the radius
00291         coefficients->values.clear();
00292         coefficients->values.push_back(centroid.x);// x
00293         coefficients->values.push_back(centroid.y);// y
00294         coefficients->values.push_back(centroid.z - _Parameters.MaxRadius);// z, uses max radius as the sphere radius
00295         coefficients->values.push_back(_Parameters.MaxRadius);// R
00296 
00297         stdOut << nodeName << ": Found sphere center at: x = " << coefficients->values[0] <<
00298                         ", y = " << coefficients->values[1] << ", z = " << coefficients->values[2];
00299         ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00300 
00301         return true;
00302 
00303 }
00304 
00305 bool SphereSegmentation::findTopCentroid(const Cloud3D &cloud,pcl::PointXYZ &topCentroid)
00306 {
00307         std::string nodeName = ros::this_node::getName() + "/segmentation";
00308         std::stringstream stdOut;
00309 
00310         // finding bounding box
00311         pcl::PointXYZ pointMax, pointMin;
00312         pcl::getMinMax3D(cloud,pointMin,pointMax);
00313 
00314         // extracting highest point from bounding box
00315         double maxZ = pointMax.z;
00316         ROS_INFO_STREAM(nodeName << ": Found Min Point at x: "<<pointMin.x<<", y: "<<pointMin.y<<", z: " << pointMin.z);
00317         ROS_INFO_STREAM(nodeName<< ": Found Max Point at x: "<<pointMax.x<<", y: "<<pointMax.y<<", z: " << maxZ);
00318 
00319         // ---------------------------------------------------------------------------------------------------------------
00320         // finding points near or on top plane
00321         Cloud3D::Ptr planeCloud  = boost::make_shared<Cloud3D>();
00322         pcl::PassThrough<pcl::PointXYZ> passFilter;
00323         passFilter.setInputCloud(boost::make_shared<Cloud3D>(cloud));
00324         passFilter.setFilterFieldName("z");
00325         passFilter.setFilterLimits(maxZ - std::abs(_Parameters.DistanceThreshold),
00326                         maxZ + std::abs(_Parameters.DistanceThreshold));
00327         passFilter.filter(*planeCloud);
00328         if(planeCloud->size() > 0)
00329         {
00330                 stdOut << nodeName << ": Found " << planeCloud->size()<<" points at a proximity of "
00331                                 <<_Parameters.DistanceThreshold << " to top plane";
00332                 ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00333 
00334         }
00335         else
00336         {
00337                 stdOut<<nodeName<< ": Found no points on top plane, canceling segmentation";
00338                 ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00339                 return false;
00340         }
00341 
00342         // ---------------------------------------------------------------------------------------------------------------
00343         // projecting filtered points onto top plane
00344         // defining plane coefficients
00345         tf::Vector3 normal = tf::Vector3(0.0f,0.0f,1.0f);
00346         double offset = -normal.dot(tf::Vector3(0.0f,0.0f,maxZ));
00347         pcl::ModelCoefficients::Ptr planeCoeffs = boost::make_shared<pcl::ModelCoefficients>();
00348         planeCoeffs->values.resize(4);
00349         planeCoeffs->values[0] = normal.getX();
00350         planeCoeffs->values[1] = normal.getY();
00351         planeCoeffs->values[2] = normal.getZ();
00352         planeCoeffs->values[3] = offset;
00353         stdOut << nodeName << ": Created Top Plane with planeCoeffs: " << planeCoeffs->values[0]
00354                    << ", "      << planeCoeffs->values[1] << ", " << planeCoeffs->values[2] << ", " << planeCoeffs->values[3];
00355         ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00356 
00357         // projecting points
00358         Cloud3D::Ptr projectedCloud = boost::make_shared<Cloud3D>();
00359         pcl::ProjectInliers<pcl::PointXYZ> projectObj;
00360         projectObj.setModelType(pcl::SACMODEL_PLANE);
00361         projectObj.setInputCloud(planeCloud);
00362         projectObj.setModelCoefficients(planeCoeffs);
00363         projectObj.filter(*projectedCloud);
00364 
00365 
00366         // finding all points within a search radius
00367         /*      This search attempts to find points that belong to the same object while removing those that are not part
00368          * of the object of interest but were found to be close enough to the plane.
00369         */
00370         if(_Parameters.MaxRadius > 0) // skip if search radius <= 0 and use all points instead
00371         {
00372                 bool continueSearch = true;
00373                 unsigned int index = 0;
00374                 pcl::search::KdTree<pcl::PointXYZ>::Ptr searchTree = boost::make_shared<pcl::search::KdTree<pcl::PointXYZ> >();
00375                 std::vector<int> indices;
00376                 std::vector<float> sqDistances;
00377                 searchTree->setInputCloud(projectedCloud);
00378 
00379                 while(continueSearch)
00380                 {
00381                         int found = searchTree->radiusSearch(projectedCloud->points[index],
00382                                         _Parameters.MaxRadius,indices,sqDistances);
00383 
00384                         if(found > 0)
00385                         {
00386                                 continueSearch = false;
00387                         }
00388                         else
00389                         {
00390                                 index++;        std::string nodeName = ros::this_node::getName();
00391                                 std::stringstream stdOut;
00392 
00393                                 // finding bounding box
00394                                 pcl::PointXYZ pointMax, pointMin;
00395                                 pcl::getMinMax3D(cloud,pointMin,pointMax);
00396 
00397                                 // extracting highest point from bounding box
00398                                 double maxZ = pointMax.z;
00399                                 ROS_INFO_STREAM(nodeName << ": Found Min Point at x: "<<pointMin.x<<", y: "<<pointMin.y<<", z: " << pointMin.z);
00400                                 ROS_INFO_STREAM(nodeName<< ": Found Max Point at x: "<<pointMax.x<<", y: "<<pointMax.y<<", z: " << maxZ);
00401 
00402                                 // ---------------------------------------------------------------------------------------------------------------
00403                                 // finding points near or on top plane
00404                                 Cloud3D::Ptr planeCloud  = boost::make_shared<Cloud3D>();
00405                                 pcl::PassThrough<pcl::PointXYZ> passFilter;
00406                                 passFilter.setInputCloud(boost::make_shared<Cloud3D>(cloud));
00407                                 passFilter.setFilterFieldName("z");
00408                                 passFilter.setFilterLimits(maxZ - std::abs(_Parameters.DistanceThreshold),
00409                                                 maxZ + std::abs(_Parameters.DistanceThreshold));
00410                                 passFilter.filter(*planeCloud);
00411                                 if(planeCloud->size() > 0)
00412                                 {
00413                                         stdOut << nodeName << ": Found " << planeCloud->size()<<" points at a proximity of "
00414                                                         <<_Parameters.DistanceThreshold << " to top plane";
00415                                         ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00416 
00417                                 }
00418                                 else
00419                                 {
00420                                         stdOut<<nodeName<< ": Found no points on top plane, canceling segmentation";
00421                                         ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00422                                         return false;
00423                                 }
00424 
00425                                 // ---------------------------------------------------------------------------------------------------------------
00426                                 // projecting filtered points onto top plane
00427                                 // defining plane coefficients
00428                                 tf::Vector3 normal = tf::Vector3(0.0f,0.0f,1.0f);
00429                                 double offset = -normal.dot(tf::Vector3(0.0f,0.0f,maxZ));
00430                                 pcl::ModelCoefficients::Ptr planeCoeffs = boost::make_shared<pcl::ModelCoefficients>();
00431                                 planeCoeffs->values.resize(4);
00432                                 planeCoeffs->values[0] = normal.getX();
00433                                 planeCoeffs->values[1] = normal.getY();
00434                                 planeCoeffs->values[2] = normal.getZ();
00435                                 planeCoeffs->values[3] = offset;
00436                                 stdOut << nodeName << ": Created Top Plane with planeCoeffs: " << planeCoeffs->values[0]
00437                                            << ", "      << planeCoeffs->values[1] << ", " << planeCoeffs->values[2] << ", " << planeCoeffs->values[3];
00438                                 ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00439 
00440                                 // projecting points
00441                                 Cloud3D::Ptr projectedCloud = boost::make_shared<Cloud3D>();
00442                                 pcl::ProjectInliers<pcl::PointXYZ> projectObj;
00443                                 projectObj.setModelType(pcl::SACMODEL_PLANE);
00444                                 projectObj.setInputCloud(planeCloud);
00445                                 projectObj.setModelCoefficients(planeCoeffs);
00446                                 projectObj.filter(*projectedCloud);
00447 
00448 
00449                                 // finding all points within a search radius
00450                                 /*      This search attempts to find points that belong to the same object while removing those that are not part
00451                                  * of the object of interest but were found to be close enough to the plane.
00452                                 */
00453                                 if(_Parameters.MaxRadius > 0) // skip if search radius <= 0 and use all points instead
00454                                 {
00455                                         bool continueSearch = true;
00456                                         unsigned int index = 0;
00457                                         pcl::search::KdTree<pcl::PointXYZ>::Ptr searchTree = boost::make_shared<pcl::search::KdTree<pcl::PointXYZ> >();
00458                                         std::vector<int> indices;
00459                                         std::vector<float> sqDistances;
00460                                         searchTree->setInputCloud(projectedCloud);
00461 
00462                                         while(continueSearch)
00463                                         {
00464                                                 int found = searchTree->radiusSearch(projectedCloud->points[index],
00465                                                                 _Parameters.MaxRadius,indices,sqDistances);
00466 
00467                                                 if(found > 0)
00468                                                 {
00469                                                         continueSearch = false;
00470                                                 }
00471                                                 else
00472                                                 {
00473                                                         index++;
00474                                                         if(index == projectedCloud->points.size())
00475                                                         {
00476                                                                 ROS_ERROR_STREAM(nodeName << ": Did not find points within search radius: " <<
00477                                                                                 _Parameters.MaxRadius <<",  exiting");
00478                                                                 return false;
00479                                                         }
00480                                                 }
00481                                         }
00482 
00483                                         // extracting points
00484                                         pcl::PointIndices::Ptr inliers = boost::make_shared<pcl::PointIndices>();
00485                                         inliers->indices = indices;
00486                                         pcl::ExtractIndices<pcl::PointXYZ> extractObj;
00487                                         extractObj.setInputCloud(projectedCloud);
00488                                         extractObj.setIndices(inliers);
00489                                         extractObj.setNegative(false);
00490                                         extractObj.filter(*projectedCloud);
00491 
00492                                         stdOut << nodeName << ": Found " << projectedCloud->size() << " points within search radius: " <<
00493                                                         _Parameters.MaxRadius;
00494                                         ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00495                                 }
00496                                 else
00497                                 {
00498                                         ROS_INFO_STREAM(nodeName<<": search radius <= 0, skipping search and using all points found instead");
00499                                 }
00500 
00501                                 // finding centroid of projected point cloud (should work well for objects with relative degree of symmetry)
00502                                 Eigen::Vector4f centroid;
00503                                 pcl::compute3DCentroid(*projectedCloud,centroid);
00504                                 if(index == projectedCloud->points.size())
00505                                 {
00506                                         ROS_ERROR_STREAM(nodeName << ": Did not find points within search radius: " <<
00507                                                         _Parameters.MaxRadius <<",  exiting");
00508                                         return false;
00509                                 }
00510                         }
00511                 }
00512 
00513                 // extracting points
00514                 pcl::PointIndices::Ptr inliers = boost::make_shared<pcl::PointIndices>();
00515                 inliers->indices = indices;
00516                 pcl::ExtractIndices<pcl::PointXYZ> extractObj;
00517                 extractObj.setInputCloud(projectedCloud);
00518                 extractObj.setIndices(inliers);
00519                 extractObj.setNegative(false);
00520                 extractObj.filter(*projectedCloud);
00521 
00522                 stdOut << nodeName << ": Found " << projectedCloud->size() << " points within search radius: " <<
00523                                 _Parameters.MaxRadius;
00524                 ROS_INFO("%s",stdOut.str().c_str());stdOut.str("");
00525         }
00526         else
00527         {
00528                 ROS_INFO_STREAM(nodeName<<": search radius <= 0, skipping search and using all points found instead");
00529         }
00530 
00531         // finding centroid of projected point cloud (should work well for objects with relative degree of symmetry)
00532         Eigen::Vector4f centroid;
00533         pcl::compute3DCentroid(*projectedCloud,centroid);
00534 
00535         topCentroid.x = centroid[0];
00536         topCentroid.y = centroid[1];
00537         topCentroid.z = centroid[2];
00538 
00539         return true;
00540 }
00541 
00542 void SphereSegmentation::filterBounds(Cloud3D &cloud)
00543 {
00544 
00545         std::vector<std::string> filterFields;
00546         filterFields.push_back("x"),filterFields.push_back("y"),filterFields.push_back("z");
00547         std::vector<double> filterMins;
00548         filterMins.push_back(_Parameters.Xmin) ,filterMins.push_back(_Parameters.Ymin),filterMins.push_back(_Parameters.Zmin);
00549         std::vector<double> filterMaxs;
00550         filterMaxs.push_back(_Parameters.Xmax),filterMaxs.push_back(_Parameters.Ymax),filterMaxs.push_back(_Parameters.Zmax);
00551 
00552         pcl::PassThrough<pcl::PointXYZ> passFilter;
00553         passFilter.setInputCloud(boost::make_shared<Cloud3D>(cloud));
00554 
00555         for(unsigned int i = 0; i < filterFields.size(); i++)
00556         {
00557                 std::string fieldName = filterFields[i];
00558                 double max, min;
00559                 max = filterMaxs[i];
00560                 min = filterMins[i];
00561 
00562                 passFilter.setFilterFieldName(fieldName);
00563                 passFilter.setFilterLimits(min,max);
00564                 passFilter.filter(cloud);
00565         }
00566 
00567 }
00568 
00569 void SphereSegmentation::filterWithPolygonalPrism(Cloud3D &cloud,pcl::PointXYZ &point,int nSides,double radius,double heightMax,double heightMin)
00570 {
00571         Cloud3D::Ptr polygonCloudPtr(new Cloud3D());
00572         Cloud3D::Ptr cloudPtr = boost::make_shared<Cloud3D>(cloud);
00573 
00574         // iterating n times to produce polygon points
00575         double maxAngle = 2*M_PI;
00576         radius = 1.20f * radius; // increasing the radius by 20%
00577         for(int i = 0; i < nSides; i++)
00578         {
00579                 pcl::PointXYZ vertex;
00580                 vertex.x = radius * cos((i*maxAngle)/((double)nSides)) + point.x;
00581                 vertex.y = radius * sin((i*maxAngle)/((double)nSides)) + point.y;
00582                 vertex.z = point.z;
00583 
00584                 polygonCloudPtr->push_back(vertex);
00585         }
00586 
00587         // creating extractor
00588         pcl::ExtractPolygonalPrismData<pcl::PointXYZ> extractor;
00589         pcl::PointIndices::Ptr indicesPtr(new pcl::PointIndices());
00590         extractor.setInputCloud(cloudPtr);
00591         extractor.setInputPlanarHull(polygonCloudPtr);
00592         extractor.setHeightLimits(heightMin,heightMax);
00593         extractor.segment(*indicesPtr);
00594 
00595         // remove points outside prism
00596         pcl::ExtractIndices<pcl::PointXYZ> indexExtractor;
00597         indexExtractor.setInputCloud(cloudPtr);
00598         indexExtractor.setIndices(indicesPtr);
00599         indexExtractor.setNegative(false);
00600         indexExtractor.filter(cloud);
00601 
00602 }
00603 
00604 void SphereSegmentation::concatenateClouds(const std::vector<sensor_msgs::PointCloud> &clusters,Cloud3D &cluster)
00605 {
00606         // clearing cloud
00607         cluster.clear();
00608         cluster.header.frame_id = clusters.begin()->header.frame_id;
00609 
00610         // concatenating all clouds first
00611         sensor_msgs::PointCloud2 tempCloudMsg;
00612         Cloud3D tempCloud = Cloud3D();
00613 
00614         BOOST_FOREACH(sensor_msgs::PointCloud clusterMsg,clusters)
00615         {
00616                 sensor_msgs::convertPointCloudToPointCloud2(clusterMsg,tempCloudMsg);
00617 
00618                 // converting cloud msg to pcl cloud
00619                 pcl::fromROSMsg(tempCloudMsg,tempCloud);
00620 
00621                 // concatenating
00622                 cluster += tempCloud;
00623         }
00624 }
00625 
00626 void SphereSegmentation::createObject(const pcl::ModelCoefficients &coeffs,arm_navigation_msgs::CollisionObject &obj)
00627 {
00628         const std::string nodeName = ros::this_node::getName() + "/segmentation";
00629 
00630         std::string name = "sphere_object";
00631         obj.id = name;
00632         obj.header.frame_id = _Parameters.WorldFrameId;
00633         obj.padding = 0.0f;
00634         obj.shapes = std::vector<arm_navigation_msgs::Shape>();
00635         obj.poses = std::vector<geometry_msgs::Pose>();
00636 
00637         // creating shape
00638         ROS_INFO_STREAM(nodeName<<": creating sphere shape");
00639         arm_navigation_msgs::Shape shape;
00640         shape.type = arm_navigation_msgs::Shape::SPHERE;
00641         shape.dimensions.push_back(coeffs.values[3]); // radius;
00642 
00643         // creating pose (in world coordinates)
00644         ROS_INFO_STREAM(nodeName<<": creating sphere pose");
00645         geometry_msgs::Pose pose;
00646         tf::poseTFToMsg(tf::Transform(tf::Quaternion::getIdentity(),tf::Vector3(coeffs.values[0],
00647                         coeffs.values[1], coeffs.values[2])),pose);
00648 
00649         // storing objs
00650         obj.shapes.push_back(shape);
00651         obj.poses.push_back(pose);
00652 
00653 }


perception_tools
Author(s): Jnicho
autogenerated on Mon Oct 6 2014 01:01:21