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 <cmath>
31 #include <iostream>
32 #include <random>
33 #include <sstream>
34 #include <string>
35 #include <vector>
36 
37 #include <ros/ros.h>
38 
39 #include <sensor_msgs/PointCloud2.h>
40 
41 #include <pcl/filters/voxel_grid.h>
42 #include <pcl/io/vtk_lib_io.h>
43 #include <pcl/point_cloud.h>
44 #include <pcl/point_types.h>
46 
48 
49 pcl::PointXYZ operator-(const pcl::PointXYZ& a, const pcl::PointXYZ& b)
50 {
51  auto c = a;
52  c.x -= b.x;
53  c.y -= b.y;
54  c.z -= b.z;
55  return c;
56 }
57 pcl::PointXYZ operator+(const pcl::PointXYZ& a, const pcl::PointXYZ& b)
58 {
59  auto c = a;
60  c.x += b.x;
61  c.y += b.y;
62  c.z += b.z;
63  return c;
64 }
65 pcl::PointXYZ operator*(const pcl::PointXYZ& a, const float& b)
66 {
67  auto c = a;
68  c.x *= b;
69  c.y *= b;
70  c.z *= b;
71  return c;
72 }
73 
74 std::vector<std::string> split(const std::string& input, char delimiter)
75 {
76  std::istringstream stream(input);
77 
78  std::string field;
79  std::vector<std::string> result;
80  while (std::getline(stream, field, delimiter))
81  {
82  result.push_back(field);
83  }
84  return result;
85 }
86 
88 {
89 public:
91  : nh_()
92  , pnh_("~")
93  , engine_(seed_gen_())
94  {
96  pub_cloud_ = neonavigation_common::compat::advertise<sensor_msgs::PointCloud2>(
97  nh_, "mapcloud",
98  pnh_, "cloud", 1, true);
99 
100  pnh_.param("frame_id", frame_id_, std::string("map"));
101  pnh_.param("objs", file_, std::string(""));
102  if (file_.compare("") == 0)
103  {
104  ROS_ERROR("OBJ file not specified");
105  ros::shutdown();
106  return;
107  }
108  pnh_.param("points_per_meter_sq", ppmsq_, 600.0);
109  pnh_.param("downsample_grid", downsample_grid_, 0.05);
110  pnh_.param("offset_x", offset_x_, 0.0);
111  pnh_.param("offset_y", offset_y_, 0.0);
112  pnh_.param("offset_z", offset_z_, 0.0);
113  pnh_.param("scale", scale_, 1.0);
114 
115  auto pc = convertObj(split(file_, ','));
116  pub_cloud_.publish(pc);
117  }
118 
119 private:
123 
124  std::string file_;
125  std::string frame_id_;
126  double ppmsq_;
128  double offset_x_;
129  double offset_y_;
130  double offset_z_;
131  double scale_;
132 
133  std::random_device seed_gen_;
134  std::default_random_engine engine_;
135 
136  sensor_msgs::PointCloud2 convertObj(const std::vector<std::string>& files)
137  {
138  sensor_msgs::PointCloud2 pc_msg;
139  pcl::PolygonMesh::Ptr mesh(new pcl::PolygonMesh());
140  pcl::PointCloud<pcl::PointXYZ>::Ptr pc(new pcl::PointCloud<pcl::PointXYZ>());
141  pcl::PointCloud<pcl::PointXYZ>::Ptr pc_rs(new pcl::PointCloud<pcl::PointXYZ>());
142 
143  pcl::PointXYZ offset(static_cast<float>(offset_x_), static_cast<float>(offset_y_), static_cast<float>(offset_z_));
144 
145  pc_rs->points.reserve(500000);
146  for (auto& file : files)
147  {
148  auto ext = file.substr(file.find_last_of(".") + 1);
149 
150  if (ext == "pcd")
151  {
152  if (pcl::io::loadPCDFile(file, *pc) == -1)
153  {
154  ROS_ERROR("Failed to load PCD file");
155  ros::shutdown();
156  return pc_msg;
157  }
158  for (auto& p : pc->points)
159  {
160  p.x *= scale_;
161  p.y *= scale_;
162  p.z *= scale_;
163  p = p + offset;
164  pc_rs->points.push_back(p);
165  }
166  }
167  else if (ext == "obj")
168  {
169  if (pcl::io::loadPolygonFileOBJ(file, *mesh) == -1)
170  {
171  ROS_ERROR("Failed to load OBJ file");
172  ros::shutdown();
173  return pc_msg;
174  }
175 
176  pcl::fromPCLPointCloud2(mesh->cloud, *pc);
177  pc_rs->header = pc->header;
178  for (auto& p : pc->points)
179  {
180  p.x *= scale_;
181  p.y *= scale_;
182  p.z *= scale_;
183  }
184 
185  std::uniform_real_distribution<float> ud(0.0, 1.0);
186  for (auto& poly : mesh->polygons)
187  {
188  if (poly.vertices.size() != 3)
189  {
190  ROS_ERROR("Input mesh mush be triangle");
191  ros::shutdown();
192  return pc_msg;
193  }
194  auto& p0 = pc->points[poly.vertices[0]];
195  auto& p1 = pc->points[poly.vertices[1]];
196  auto& p2 = pc->points[poly.vertices[2]];
197 
198  auto a = p1 - p0;
199  auto b = p2 - p0;
200 
201  float s =
202  0.5 * std::sqrt(
203  std::pow(a.y * b.z - a.z * b.y, 2) +
204  std::pow(a.z * b.x - a.x * b.z, 2) +
205  std::pow(a.x * b.y - a.y * b.x, 2));
206  float numf = ppmsq_ * s;
207  int num = numf;
208  if (numf - num > ud(engine_))
209  num++;
210  for (int i = 0; i < num; i++)
211  {
212  float r0 = ud(engine_);
213  float r1 = ud(engine_);
214  if (r0 + r1 > 1.0)
215  {
216  r0 = 1.0 - r0;
217  r1 = 1.0 - r1;
218  }
219  pcl::PointXYZ p = p0 + (a * r0 + b * r1) + offset;
220  pc_rs->points.push_back(p);
221  }
222  }
223  }
224  }
225  pc_rs->width = pc_rs->points.size();
226  pc_rs->height = 1;
227  pc_rs->is_dense = true;
228 
229  // Down-sample
230  pcl::PointCloud<pcl::PointXYZ>::Ptr pc_ds(new pcl::PointCloud<pcl::PointXYZ>);
231  pcl::VoxelGrid<pcl::PointXYZ> ds;
232  ds.setInputCloud(pc_rs);
233  ds.setLeafSize(downsample_grid_, downsample_grid_, downsample_grid_);
234  ds.filter(*pc_ds);
235 
236  pcl::toROSMsg(*pc_ds, pc_msg);
237  pc_msg.header.frame_id = frame_id_;
238  pc_msg.header.stamp = ros::Time::now();
239  ROS_INFO("pointcloud (%d points) has been generated from %d verticles",
240  (int)pc_ds->size(),
241  (int)pc->size());
242  return pc_msg;
243  }
244 };
245 
246 int main(int argc, char** argv)
247 {
248  ros::init(argc, argv, "obj_to_pointcloud");
249 
251  ros::spin();
252 
253  return 0;
254 }
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 Wed May 12 2021 02:20:34