obj_to_pointcloud.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014-2017, the neonavigation authors
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <ros/ros.h>
31 #include <sensor_msgs/PointCloud2.h>
32 
33 #include <pcl/point_types.h>
34 #include <pcl/point_cloud.h>
36 #include <pcl/io/vtk_lib_io.h>
37 #include <pcl/filters/voxel_grid.h>
38 
39 #include <cmath>
40 #include <random>
41 #include <string>
42 #include <iostream>
43 #include <sstream>
44 #include <vector>
45 
47 
48 pcl::PointXYZ operator-(const pcl::PointXYZ& a, const pcl::PointXYZ& b)
49 {
50  auto c = a;
51  c.x -= b.x;
52  c.y -= b.y;
53  c.z -= b.z;
54  return c;
55 }
56 pcl::PointXYZ operator+(const pcl::PointXYZ& a, const pcl::PointXYZ& b)
57 {
58  auto c = a;
59  c.x += b.x;
60  c.y += b.y;
61  c.z += b.z;
62  return c;
63 }
64 pcl::PointXYZ operator*(const pcl::PointXYZ& a, const float& b)
65 {
66  auto c = a;
67  c.x *= b;
68  c.y *= b;
69  c.z *= b;
70  return c;
71 }
72 
73 std::vector<std::string> split(const std::string& input, char delimiter)
74 {
75  std::istringstream stream(input);
76 
77  std::string field;
78  std::vector<std::string> result;
79  while (std::getline(stream, field, delimiter))
80  {
81  result.push_back(field);
82  }
83  return result;
84 }
85 
87 {
88 public:
90  : nh_()
91  , pnh_("~")
92  , engine_(seed_gen_())
93  {
95  pub_cloud_ = neonavigation_common::compat::advertise<sensor_msgs::PointCloud2>(
96  nh_, "mapcloud",
97  pnh_, "cloud", 1, true);
98 
99  pnh_.param("frame_id", frame_id_, std::string("map"));
100  pnh_.param("objs", file_, std::string(""));
101  if (file_.compare("") == 0)
102  {
103  ROS_ERROR("OBJ file not specified");
104  ros::shutdown();
105  return;
106  }
107  pnh_.param("points_per_meter_sq", ppmsq_, 600.0);
108  pnh_.param("downsample_grid", downsample_grid_, 0.05);
109  pnh_.param("offset_x", offset_x_, 0.0);
110  pnh_.param("offset_y", offset_y_, 0.0);
111  pnh_.param("offset_z", offset_z_, 0.0);
112  pnh_.param("scale", scale_, 1.0);
113 
114  auto pc = convertObj(split(file_, ','));
115  pub_cloud_.publish(pc);
116  }
117 
118 private:
122 
123  std::string file_;
124  std::string frame_id_;
125  double ppmsq_;
127  double offset_x_;
128  double offset_y_;
129  double offset_z_;
130  double scale_;
131 
132  std::random_device seed_gen_;
133  std::default_random_engine engine_;
134 
135  sensor_msgs::PointCloud2 convertObj(const std::vector<std::string>& files)
136  {
137  sensor_msgs::PointCloud2 pc_msg;
138  pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh());
139  pcl::PointCloud<pcl::PointXYZ>::Ptr pc(new pcl::PointCloud<pcl::PointXYZ>());
140  pcl::PointCloud<pcl::PointXYZ>::Ptr pc_rs(new pcl::PointCloud<pcl::PointXYZ>());
141 
142  pcl::PointXYZ offset(static_cast<float>(offset_x_), static_cast<float>(offset_y_), static_cast<float>(offset_z_));
143 
144  pc_rs->points.reserve(500000);
145  for (auto& file : files)
146  {
147  auto ext = file.substr(file.find_last_of(".") + 1);
148 
149  if (ext == "pcd")
150  {
151  if (pcl::io::loadPCDFile(file, *pc) == -1)
152  {
153  ROS_ERROR("Failed to load PCD file");
154  ros::shutdown();
155  return pc_msg;
156  }
157  for (auto& p : pc->points)
158  {
159  p.x *= scale_;
160  p.y *= scale_;
161  p.z *= scale_;
162  p = p + offset;
163  pc_rs->points.push_back(p);
164  }
165  }
166  else if (ext == "obj")
167  {
168  if (pcl::io::loadPolygonFileOBJ(file, *mesh) == -1)
169  {
170  ROS_ERROR("Failed to load OBJ file");
171  ros::shutdown();
172  return pc_msg;
173  }
174 
175  pcl::fromPCLPointCloud2(mesh->cloud, *pc);
176  pc_rs->header = pc->header;
177  for (auto& p : pc->points)
178  {
179  p.x *= scale_;
180  p.y *= scale_;
181  p.z *= scale_;
182  }
183 
184  std::uniform_real_distribution<float> ud(0.0, 1.0);
185  for (auto& poly : mesh->polygons)
186  {
187  if (poly.vertices.size() != 3)
188  {
189  ROS_ERROR("Input mesh mush be triangle");
190  ros::shutdown();
191  return pc_msg;
192  }
193  auto& p0 = pc->points[poly.vertices[0]];
194  auto& p1 = pc->points[poly.vertices[1]];
195  auto& p2 = pc->points[poly.vertices[2]];
196 
197  auto a = p1 - p0;
198  auto b = p2 - p0;
199 
200  float s = 0.5 * sqrtf(
201  powf(a.y * b.z - a.z * b.y, 2.0) +
202  powf(a.z * b.x - a.x * b.z, 2.0) +
203  powf(a.x * b.y - a.y * b.x, 2.0));
204  float numf = ppmsq_ * s;
205  int num = numf;
206  if (numf - num > ud(engine_))
207  num++;
208  for (int i = 0; i < num; i++)
209  {
210  float r0 = ud(engine_);
211  float r1 = ud(engine_);
212  if (r0 + r1 > 1.0)
213  {
214  r0 = 1.0 - r0;
215  r1 = 1.0 - r1;
216  }
217  pcl::PointXYZ p = p0 + (a * r0 + b * r1) + offset;
218  pc_rs->points.push_back(p);
219  }
220  }
221  }
222  }
223  pc_rs->width = pc_rs->points.size();
224  pc_rs->height = 1;
225  pc_rs->is_dense = true;
226 
227  // Down-sample
228  pcl::PointCloud<pcl::PointXYZ>::Ptr pc_ds(new pcl::PointCloud<pcl::PointXYZ>);
229  pcl::VoxelGrid<pcl::PointXYZ> ds;
230  ds.setInputCloud(pc_rs);
231  ds.setLeafSize(downsample_grid_, downsample_grid_, downsample_grid_);
232  ds.filter(*pc_ds);
233 
234  pcl::toROSMsg(*pc_ds, pc_msg);
235  pc_msg.header.frame_id = frame_id_;
236  pc_msg.header.stamp = ros::Time::now();
237  ROS_INFO("pointcloud (%d points) has been generated from %d verticles",
238  (int)pc_ds->size(),
239  (int)pc->size());
240  return pc_msg;
241  }
242 };
243 
244 int main(int argc, char** argv)
245 {
246  ros::init(argc, argv, "obj_to_pointcloud");
247 
249  ros::spin();
250 
251  return 0;
252 }
void publish(const boost::shared_ptr< M > &message) const
XmlRpcServer s
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
ROSCPP_DECL void spin(Spinner &spinner)
int main(int argc, char **argv)
#define ROS_INFO(...)
int loadPCDFile(const std::string &file_name, sensor_msgs::PointCloud2 &cloud)
std::random_device seed_gen_
std::default_random_engine engine_
std::vector< std::string > split(const std::string &input, char delimiter)
pcl::PointXYZ operator+(const pcl::PointXYZ &a, const pcl::PointXYZ &b)
void toROSMsg(const sensor_msgs::PointCloud2 &cloud, sensor_msgs::Image &image)
static Time now()
ROSCPP_DECL void shutdown()
pcl::PointXYZ operator-(const pcl::PointXYZ &a, const pcl::PointXYZ &b)
#define ROS_ERROR(...)
sensor_msgs::PointCloud2 convertObj(const std::vector< std::string > &files)
pcl::PointXYZ operator*(const pcl::PointXYZ &a, const float &b)


obj_to_pointcloud
Author(s): Atsushi Watanabe
autogenerated on Tue Jul 9 2019 04:59:59