pointcloud_to_stl_nodelet.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2015, JSK Lab
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/o2r other materials provided
16  * with the distribution.
17  * * Neither the name of the JSK Lab nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 #define BOOST_PARAMETER_MAX_ARITY 7
37 
38 #include <geometry_msgs/PoseStamped.h>
39 #include <geometry_msgs/PointStamped.h>
40 
41 #include <pcl/point_types.h>
42 #include <pcl/io/pcd_io.h>
43 #include <pcl/kdtree/kdtree_flann.h>
44 #include <pcl/features/normal_3d.h>
45 #include <pcl/surface/gp3.h>
46 #include <pcl/io/vtk_lib_io.h>
47 #include <pcl/TextureMesh.h>
48 #include <pcl/surface/texture_mapping.h>
49 #include <pcl/surface/mls.h>
50 #include <pcl/io/obj_io.h>
51 #include <pcl/filters/filter.h>
52 
54 
55 namespace jsk_pcl_ros_utils
56 {
57  void PointCloudToSTL::cloudCallback(const sensor_msgs::PointCloud2::ConstPtr& input)
58  {
59  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
60  pcl::fromROSMsg(*input, *cloud);
61  exportSTL(cloud);
62 
63 
64  visualization_msgs::Marker marker_msg;
65  marker_msg.header = input->header;
66  marker_msg.mesh_resource = latest_output_path_;
67  marker_msg.ns = "pcl_mesh_reconstrunction";
68  marker_msg.id = 0;
69  marker_msg.type = visualization_msgs::Marker::MESH_RESOURCE;
70  marker_msg.action = visualization_msgs::Marker::ADD;
71 
72  marker_msg.pose.position.x = 1;
73  marker_msg.pose.position.y = 1;
74  marker_msg.pose.position.z = 1;
75  marker_msg.pose.orientation.x = 0.0;
76  marker_msg.pose.orientation.y = 0.0;
77  marker_msg.pose.orientation.z = 0.0;
78  marker_msg.pose.orientation.w = 1.0;
79  marker_msg.scale.x = 1;
80  marker_msg.scale.y = 1;
81  marker_msg.scale.z = 1;
82  pub_mesh_.publish(marker_msg);
83 
84  }
85 
86  void PointCloudToSTL::exportSTL(const pcl::PointCloud<pcl::PointXYZRGB>::ConstPtr &input_cloud){
87 
88  pcl::PolygonMesh triangles;
89  ofm.setInputCloud (input_cloud);
90  ofm.reconstruct (triangles);
91 
92  /*
93 
94 
95  // Store the results in a temporary object
96  boost::shared_ptr<std::vector<pcl::Vertices> > temp_verts (new std::vector<pcl::Vertices>);
97  ofm.reconstruct (*temp_verts);
98 
99 
100  ROS_INFO("Got Input PointClouds");
101  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
102 
103  std::vector<int> indices;
104  pcl::removeNaNFromPointCloud(*input_cloud, *cloud, indices);
105 
106  pcl::search::KdTree<pcl::PointXYZRGB>::Ptr mls_tree (new pcl::search::KdTree<pcl::PointXYZRGB>);
107 
108  // Output has the PointNormal type in order to store the normals calculated by MLS
109  pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr mls_points(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
110 
111  // Init object (second point type is for the normals, even if unused)
112  pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal> mls;
113 
114  mls.setComputeNormals (true);
115 
116  // Set parameters
117  mls.setInputCloud (cloud);
118  mls.setPolynomialFit (true);
119  mls.setSearchMethod (mls_tree);
120  mls.setSearchRadius (0.03);
121 
122  // Reconstruct
123  mls.process (*mls_points);
124 
125  mls_points->is_dense = false;
126  pcl::removeNaNFromPointCloud(*mls_points, *mls_points, indices);
127  pcl::search::KdTree<pcl::PointXYZRGBNormal>::Ptr tree2 (new pcl::search::KdTree<pcl::PointXYZRGBNormal>);
128  tree2->setInputCloud (mls_points);//cloud_with_normals);
129 
130  // Initialize objects
131  pcl::GreedyProjectionTriangulation<pcl::PointXYZRGBNormal> gp3;
132  pcl::PolygonMesh triangles;
133 
134  // Set the maximum distance between connected points (maximum edge length)
135  gp3.setSearchRadius (search_radius_);
136 
137  // Set typical values for the parameters
138  gp3.setMu (mu_);
139  gp3.setMaximumNearestNeighbors (maximum_nearest_neighbors_);
140  gp3.setMaximumSurfaceAngle(maximum_surface_angle_); // 45 degrees
141  gp3.setMinimumAngle(minimum_angle_); // 10 degrees
142  gp3.setMaximumAngle(maximum_angle_); // 120 degrees
143  gp3.setNormalConsistency(normal_consistency_);
144 
145  // Get result
146  gp3.setInputCloud (mls_points);//cloud_with_normals);
147  gp3.setSearchMethod (tree2);
148  gp3.reconstruct (triangles);
149 
150 */
151 
152  ros::Time now_time = ros::Time::now();
153  std::stringstream ss;
154  if (file_name_.length())
155  ss << file_name_.c_str();
156  else
157  ss << "/tmp/" << now_time.toNSec() << "_pointcloud.stl";
158 
159  ROS_INFO("Writing... %s", ss.str().c_str());
160  pcl::io::savePolygonFileSTL(ss.str(),triangles);
161  latest_output_path_ = ss.str();
162 
163  /*
164  std::vector<std::string> tex_files;
165  tex_files.push_back("text4.jpg");
166 
167  // initialize texture mesh
168  pcl::TextureMesh tex_mesh;
169  tex_mesh.cloud = triangles.cloud;
170 
171  // add the 1st mesh
172  tex_mesh.tex_polygons.push_back(triangles.polygons);
173 
174  // update mesh and texture mesh
175  //gp3.updateMesh(cloud_with_normals, triangles, tex_mesh);
176  // set texture for added cloud
177  tex_files.push_back("tex8.jpg");
178  // save updated mesh
179 
180  pcl::TextureMapping<pcl::PointXYZ> tm;
181 
182  tm.setF(0.01);
183  tm.setVectorField(1, 0, 0);
184 
185  pcl::TexMaterial tex_material;
186 
187  tex_material.tex_Ka.r = 0.2f;
188  tex_material.tex_Ka.g = 0.2f;
189  tex_material.tex_Ka.b = 0.2f;
190 
191  tex_material.tex_Kd.r = 0.8f;
192  tex_material.tex_Kd.g = 0.8f;
193  tex_material.tex_Kd.b = 0.8f;
194 
195  tex_material.tex_Ks.r = 1.0f;
196  tex_material.tex_Ks.g = 1.0f;
197  tex_material.tex_Ks.b = 1.0f;
198  tex_material.tex_d = 1.0f;
199  tex_material.tex_Ns = 0.0f;
200  tex_material.tex_illum = 2;
201 
202  tm.setTextureMaterials(tex_material);
203  tm.setTextureFiles(tex_files);
204  tm.mapTexture2Mesh(tex_mesh);
205 
206  pcl::io::saveOBJFile ("/tmp/test.obj", tex_mesh);
207  */
208  }
209 
210  bool PointCloudToSTL::createSTL(jsk_recognition_msgs::SetPointCloud2::Request &req,
211  jsk_recognition_msgs::SetPointCloud2::Response &res)
212  {
213  if(req.name.length())
214  file_name_ = req.name;
215  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGB>);
216  pcl::fromROSMsg(req.cloud, *cloud);
217  exportSTL(cloud);
218  res.output = latest_output_path_;
219  }
220 
222  {
223  PCLNodelet::onInit();
224  pnh_->param("filename", file_name_ , std::string(""));
225  pnh_->param("search_radius", search_radius_ , 0.05);
226  pnh_->param("mu", mu_, 3.5);
227  pnh_->param("maximum_nearest_neighbors", maximum_nearest_neighbors_, 100);
228  pnh_->param("maximum_surface_angle", maximum_surface_angle_, 0.7853981633974483);
229  pnh_->param("minimum_angle", minimum_angle_, 0.17453292519943295);
230  pnh_->param("maximum_angle", maximum_angle_, 2.0943951023931953);
231  pnh_->param("normal_consistency", normal_consistency_, false);
232 
233  pnh_->param("triangle_pixel_size", triangle_pixel_size_, 1.0);
234  pnh_->param("max_edge_length", max_edge_length_, 4.5);
235  pnh_->param("store_shadow_faces", store_shadow_faces_, true);
236 
237  sub_input_ = pnh_->subscribe("input", 1, &PointCloudToSTL::cloudCallback, this);
239  = pnh_->advertiseService("create_stl", &PointCloudToSTL::createSTL, this);
240 
241  pub_mesh_ = pnh_->advertise<visualization_msgs::Marker>("pc_stl_mesh", 1);
242 
243  ofm.setTrianglePixelSize (triangle_pixel_size_);
244  ofm.setTriangulationType (pcl::OrganizedFastMesh<pcl::PointXYZRGB>::TRIANGLE_ADAPTIVE_CUT);
245  ofm.setMaxEdgeLength(max_edge_length_);
246  ofm.storeShadowedFaces(store_shadow_faces_);
247  }
248 }
249 
void publish(const boost::shared_ptr< M > &message) const
virtual void cloudCallback(const sensor_msgs::PointCloud2::ConstPtr &input)
void fromROSMsg(const sensor_msgs::PointCloud2 &cloud, pcl::PointCloud< T > &pcl_cloud)
PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros_utils::PointCloudToSTL, nodelet::Nodelet)
pcl::OrganizedFastMesh< pcl::PointXYZRGB > ofm
virtual void exportSTL(const pcl::PointCloud< pcl::PointXYZRGB >::ConstPtr &cloud)
boost::shared_ptr< ros::NodeHandle > pnh_
#define ROS_INFO(...)
virtual bool createSTL(jsk_recognition_msgs::SetPointCloud2::Request &req, jsk_recognition_msgs::SetPointCloud2::Response &res)
uint64_t toNSec() const
static Time now()


jsk_pcl_ros_utils
Author(s): Yohei Kakiuchi
autogenerated on Mon May 3 2021 03:03:15