Go to the documentation of this file.00001
00031 #include <algorithm>
00032
00033 #include <boost/foreach.hpp>
00034
00035 #include <ros/ros.h>
00036 #include <pcl_conversions/pcl_conversions.h>
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/impl/mls.hpp>
00042 #include <pcl/surface/convex_hull.h>
00043
00044 #include <sensor_msgs/point_cloud_conversion.h>
00045 #include <triangulate_point_cloud/TriangulatePCL.h>
00046 #include <shape_msgs/Mesh.h>
00047 #include <shape_msgs/MeshTriangle.h>
00048 #include <geometry_msgs/Point.h>
00049
00050
00051 using namespace pcl;
00052 using namespace triangulate_point_cloud;
00053
00054 void reconstructMesh(const PointCloud<PointXYZ>::ConstPtr &cloud,
00055 PointCloud<PointXYZ> &output_cloud, std::vector<Vertices> &triangles)
00056 {
00057 boost::shared_ptr<std::vector<int> > indices(new std::vector<int>);
00058 indices->resize(cloud->points.size ());
00059 for (size_t i = 0; i < indices->size (); ++i) { (*indices)[i] = i; }
00060
00061 pcl::search::KdTree<PointXYZ>::Ptr tree(new pcl::search::KdTree<PointXYZ>);
00062 tree->setInputCloud(cloud);
00063
00064 PointCloud<PointXYZ>::Ptr mls_points(new PointCloud<PointXYZ>);
00065 PointCloud<PointNormal>::Ptr mls_normals(new PointCloud<PointNormal>);
00066 MovingLeastSquares<PointXYZ, PointNormal> mls;
00067
00068 mls.setInputCloud(cloud);
00069 mls.setIndices(indices);
00070 mls.setPolynomialFit(true);
00071 mls.setSearchMethod(tree);
00072 mls.setSearchRadius(0.03);
00073
00074 mls.process(*mls_normals);
00075
00076 ConvexHull<PointXYZ> ch;
00077
00078 ch.setInputCloud(mls_points);
00079 ch.reconstruct(output_cloud, triangles);
00080 }
00081
00082 template<typename T>
00083 void toPoint(const T &in, geometry_msgs::Point &out)
00084 {
00085 out.x = in.x;
00086 out.y = in.y;
00087 out.z = in.z;
00088 }
00089
00090 template<typename T>
00091 void polygonMeshToShapeMsg(const PointCloud<T> &points,
00092 const std::vector<Vertices> &triangles,
00093 shape_msgs::Mesh &mesh)
00094 {
00095 mesh.vertices.resize(points.points.size());
00096 for(size_t i=0; i<points.points.size(); i++)
00097 toPoint(points.points[i], mesh.vertices[i]);
00098
00099 ROS_INFO("Found %ld polygons", triangles.size());
00100 BOOST_FOREACH(const 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_msgs::MeshTriangle triangle = shape_msgs::MeshTriangle();
00109 boost::array<uint32_t, 3> xyz = {{polygon.vertices[0], polygon.vertices[1], polygon.vertices[2]}};
00110 triangle.vertex_indices = xyz;
00111
00112 mesh.triangles.push_back(shape_msgs::MeshTriangle());
00113 }
00114 }
00115
00116 bool onTriangulatePcl(TriangulatePCL::Request &req, TriangulatePCL::Response &res)
00117 {
00118 ROS_INFO("Service request received");
00119
00120 sensor_msgs::PointCloud2 cloud_raw;
00121 sensor_msgs::convertPointCloudToPointCloud2(req.points, cloud_raw);
00122 PointCloud<PointXYZ>::Ptr cloud(new PointCloud<PointXYZ>);
00123 pcl::fromROSMsg(cloud_raw, *cloud);
00124
00125 PointCloud<PointXYZ> out_cloud;
00126 std::vector<Vertices> triangles;
00127
00128 ROS_INFO("Triangulating");
00129 reconstructMesh(cloud, out_cloud, triangles);
00130 ROS_INFO("Triangulation done");
00131
00132 ROS_INFO("Converting to shape message");
00133 polygonMeshToShapeMsg(out_cloud, triangles, res.mesh);
00134
00135 ROS_INFO("Service processing done");
00136
00137 return true;
00138 }
00139
00140 void test()
00141 {
00142 pcl::PointCloud<pcl::PointXYZ> pcl_cloud;
00143 pcl::PCDReader reader;
00144
00145 if (reader.read("test_data/ism_test_cat.pcd", pcl_cloud) < 0)
00146 {
00147 PCL_ERROR ("Couldn't read file test_data/ism_test_cat.pcd \n");
00148 return;
00149 }
00150
00151 sensor_msgs::PointCloud2 sensor_cloud2;
00152 pcl::toROSMsg(pcl_cloud, sensor_cloud2);
00153 sensor_msgs::PointCloud sensor_cloud1;
00154 sensor_msgs::convertPointCloud2ToPointCloud(sensor_cloud2, sensor_cloud1);
00155
00156 TriangulatePCL::Request req;
00157 req.points = sensor_cloud1;
00158 TriangulatePCL::Response res;
00159 onTriangulatePcl(req, res);
00160 }
00161
00162 int main(int argc, char *argv[])
00163 {
00164 ros::init(argc, argv, "triangulate_point_cloud");
00165 ros::NodeHandle nh("~");
00166
00167
00168
00169 ros::ServiceServer service = nh.advertiseService("triangulate", &onTriangulatePcl);
00170 ROS_INFO("Triangulation service running");
00171 ros::spin();
00172 return 0;
00173 }