Go to the documentation of this file.00001
00031 #include <algorithm>
00032
00033 #include <boost/foreach.hpp>
00034
00035 #include <ros/ros.h>
00036
00037 #include <pcl/io/vtk_io.h>
00038 #include <pcl/point_types.h>
00039 #include <pcl/kdtree/kdtree_flann.h>
00040 #include <pcl/surface/mls.h>
00041 #include <pcl/surface/convex_hull.h>
00042
00043 #include <sensor_msgs/point_cloud_conversion.h>
00044 #include <triangulate_point_cloud/TriangulatePCL.h>
00045 #include <arm_navigation_msgs/Shape.h>
00046 #include <geometry_msgs/Point.h>
00047
00048
00049 using namespace pcl;
00050 using namespace triangulate_point_cloud;
00051
00052 void reconstructMesh(const PointCloud<PointXYZ>::ConstPtr &cloud,
00053 PointCloud<PointXYZ> &output_cloud, std::vector<Vertices> &triangles)
00054 {
00055 boost::shared_ptr<std::vector<int> > indices(new std::vector<int>);
00056 indices->resize(cloud->points.size ());
00057 for (size_t i = 0; i < indices->size (); ++i) { (*indices)[i] = i; }
00058
00059 pcl::search::KdTree<PointXYZ>::Ptr tree(new pcl::search::KdTree<PointXYZ>);
00060 tree->setInputCloud(cloud);
00061
00062 PointCloud<PointXYZ>::Ptr mls_points(new PointCloud<PointXYZ>);
00063 PointCloud<Normal>::Ptr mls_normals(new PointCloud<Normal>);
00064 MovingLeastSquares<PointXYZ, Normal> mls;
00065
00066 mls.setInputCloud(cloud);
00067 mls.setIndices(indices);
00068 mls.setPolynomialFit(true);
00069 mls.setSearchMethod(tree);
00070 mls.setSearchRadius(0.03);
00071
00072 mls.setOutputNormals (mls_normals);
00073 mls.reconstruct (*mls_points);
00074
00075 ConvexHull<PointXYZ> ch;
00076
00077 ch.setInputCloud(mls_points);
00078 ch.reconstruct(output_cloud, triangles);
00079 }
00080
00081 template<typename T>
00082 void toPoint(const T &in, geometry_msgs::Point &out)
00083 {
00084 out.x = in.x;
00085 out.y = in.y;
00086 out.z = in.z;
00087 }
00088
00089 template<typename T>
00090 void polygonMeshToShapeMsg(const PointCloud<T> &points,
00091 const std::vector<Vertices> &triangles,
00092 arm_navigation_msgs::Shape &shape)
00093 {
00094 shape.type = arm_navigation_msgs::Shape::MESH;
00095 shape.vertices.resize(points.points.size());
00096 for(size_t i=0; i<points.points.size(); i++)
00097 toPoint(points.points[i], shape.vertices[i]);
00098
00099 ROS_INFO("Found %ld polygons", triangles.size());
00100 BOOST_FOREACH(const pcl::Vertices polygon, triangles)
00101 {
00102 if(polygon.vertices.size() < 3)
00103 {
00104 ROS_WARN("Not enough points in polygon. Ignoring it.");
00105 continue;
00106 }
00107
00108 shape.triangles.push_back(polygon.vertices[0]);
00109 shape.triangles.push_back(polygon.vertices[1]);
00110 shape.triangles.push_back(polygon.vertices[2]);
00111 }
00112 }
00113
00114 bool onTriangulatePcl(TriangulatePCL::Request &req, TriangulatePCL::Response &res)
00115 {
00116 ROS_INFO("Service request received");
00117
00118 sensor_msgs::PointCloud2 cloud_raw;
00119 sensor_msgs::convertPointCloudToPointCloud2(req.points, cloud_raw);
00120 PointCloud<PointXYZ>::Ptr cloud(new PointCloud<PointXYZ>);
00121 PointCloud<PointXYZ> out_cloud;
00122 fromROSMsg(cloud_raw, *cloud);
00123
00124 std::vector<Vertices> triangles;
00125
00126 ROS_INFO("Triangulating");
00127 reconstructMesh(cloud, out_cloud, triangles);
00128 ROS_INFO("Triangulation done");
00129
00130 ROS_INFO("Converting to shape message");
00131 polygonMeshToShapeMsg(out_cloud, triangles, res.mesh);
00132
00133 ROS_INFO("Service processing done");
00134
00135 return true;
00136 }
00137
00138 int main(int argc, char *argv[])
00139 {
00140 ros::init(argc, argv, "triangulate_point_cloud");
00141 ros::NodeHandle nh("~");
00142
00143 ros::ServiceServer service = nh.advertiseService("triangulate", &onTriangulatePcl);
00144 ROS_INFO("Triangulation service running");
00145 ros::spin();
00146 return 0;
00147 }