|
1 | 1 | #include <ros/ros.h>
|
2 | 2 |
|
3 |
| -#include <std_msgs/String.h> |
| 3 | +#include <boost/lexical_cast.hpp> |
4 | 4 |
|
5 | 5 | #include <pcl/point_types.h>
|
6 | 6 | #include <pcl_ros/point_cloud.h>
|
7 | 7 | #include <pcl/io/pcd_io.h>
|
8 |
| -#include <pcl/filters/voxel_grid.h> |
9 | 8 | #include <pcl/common/centroid.h>
|
10 | 9 |
|
11 | 10 | class PointCloudToWebgl {
|
12 | 11 |
|
13 |
| -// ROS properties |
14 |
| -ros::NodeHandle nh_; |
15 |
| -ros::NodeHandle nh_private_; |
16 |
| - |
17 |
| -std::string pcd_filename_; |
18 |
| -double max_ascii_file_size_; |
19 |
| -int pcd_type_; |
20 |
| - |
21 | 12 | public:
|
22 | 13 |
|
23 | 14 | /**
|
24 | 15 | * Class constructor
|
25 | 16 | */
|
26 |
| - PointCloudToWebgl() : nh_private_("~") |
| 17 | + PointCloudToWebgl(const std::string& input_cloud, const int& cloud_format, |
| 18 | + const std::string& output_cloud) : |
| 19 | + input_cloud_(input_cloud), cloud_format_(cloud_format), output_cloud_(output_cloud) |
| 20 | + {} |
| 21 | + |
| 22 | + /** |
| 23 | + * Convert the cloud |
| 24 | + */ |
| 25 | + void convert() |
27 | 26 | {
|
28 |
| - // Read the parameters from the parameter server (set defaults) |
29 |
| - nh_private_.param("pcd_filename", pcd_filename_, std::string("pointcloud_file.pcd")); |
30 |
| - nh_private_.param("max_ascii_file_size", max_ascii_file_size_, 4.0); // In MBytes |
31 |
| - nh_private_.param("pcd_type", pcd_type_, 0); // 0 -> XYZ | 1 -> XYZRGB |
| 27 | + ROS_INFO_STREAM("[PointCloudToWebgl:] Opening file " << input_cloud_); |
32 | 28 |
|
33 |
| - ROS_INFO_STREAM("[PointCloudToWebgl:] Opening file " << pcd_filename_); |
| 29 | + // Init the cloud |
| 30 | + pcl::PointCloud<pcl::PointXYZRGB> cloud; |
34 | 31 |
|
35 | 32 | // Read point cloud
|
36 |
| - if (pcd_type_ == 0) |
| 33 | + if (cloud_format_ == 0) |
37 | 34 | {
|
38 | 35 | // NO RGB
|
39 |
| - pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr (new pcl::PointCloud<pcl::PointXYZ>); |
40 |
| - if (pcl::io::loadPCDFile<pcl::PointXYZ> (pcd_filename_, *cloud_ptr) == -1) //* load the file |
41 |
| - { |
42 |
| - ROS_ERROR_STREAM("[PointCloudToWebgl:] Couldn't read file " << pcd_filename_); |
43 |
| - } |
44 |
| - else |
| 36 | + pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz (new pcl::PointCloud<pcl::PointXYZ>); |
| 37 | + if (pcl::io::loadPCDFile<pcl::PointXYZ> (input_cloud_, *cloud_xyz) == -1) //* load the file |
45 | 38 | {
|
46 |
| - // Convert the cloud |
47 |
| - pcl::PointCloud<pcl::PointXYZ> cloud = *cloud_ptr; |
48 |
| - int file_point_size = 27; |
49 |
| - int max_bytes = (int)round(max_ascii_file_size_ * 1024 * 1024); |
50 |
| - int desired_points = max_bytes / file_point_size; |
51 |
| - double voxel_size = 0.001; |
52 |
| - double offset = 0.0002; |
53 |
| - while ((int)cloud.size() > desired_points) |
54 |
| - { |
55 |
| - pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_downsampled = filter(cloud.makeShared(), voxel_size); |
56 |
| - cloud = *cloud_downsampled; |
57 |
| - voxel_size = voxel_size + offset; |
58 |
| - } |
59 |
| - |
60 |
| - // Compute the cloud centroid |
61 |
| - Eigen::Vector4f centroid; |
62 |
| - pcl::compute3DCentroid(cloud, centroid); |
63 |
| - |
64 |
| - // Save int file |
65 |
| - int lastindex = pcd_filename_.find_last_of("."); |
66 |
| - std::string filename = pcd_filename_.substr(0, lastindex); |
67 |
| - filename = filename + ".txt"; |
68 |
| - ROS_INFO_STREAM("[PointCloudToWebgl:] Saving webgl file to " << filename); |
69 |
| - std::fstream f_webgl(filename.c_str(), std::ios::out); |
70 |
| - for (unsigned int i=0; i<cloud.size(); i++) |
71 |
| - { |
72 |
| - f_webgl << cloud[i].x - centroid[0] << "," << |
73 |
| - cloud[i].y - centroid[1] << "," << |
74 |
| - cloud[i].z - centroid[2] << "," << |
75 |
| - (int)(224) << "," << |
76 |
| - (int)(224) << "," << |
77 |
| - (int)(224) << std::endl; |
78 |
| - } |
79 |
| - f_webgl.close(); |
80 |
| - ROS_INFO("[PointCloudToWebgl:] Saved!"); |
| 39 | + ROS_ERROR_STREAM("[PointCloudToWebgl:] Couldn't read file " << input_cloud_); |
| 40 | + return; |
81 | 41 | }
|
| 42 | + copyPointCloud(*cloud_xyz, cloud); |
82 | 43 | }
|
83 |
| - else |
| 44 | + else if (cloud_format_ == 1) |
84 | 45 | {
|
85 | 46 | // RGB
|
86 |
| - pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_ptr (new pcl::PointCloud<pcl::PointXYZRGB>); |
87 |
| - if (pcl::io::loadPCDFile<pcl::PointXYZRGB> (pcd_filename_, *cloud_ptr) == -1) //* load the file |
88 |
| - { |
89 |
| - ROS_ERROR_STREAM("[PointCloudToWebgl:] Couldn't read file " << pcd_filename_); |
90 |
| - } |
91 |
| - else |
| 47 | + pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_xyzrgb (new pcl::PointCloud<pcl::PointXYZRGB>); |
| 48 | + if (pcl::io::loadPCDFile<pcl::PointXYZRGB> (input_cloud_, *cloud_xyzrgb) == -1) //* load the file |
92 | 49 | {
|
93 |
| - // Convert the cloud |
94 |
| - pcl::PointCloud<pcl::PointXYZRGB> cloud = *cloud_ptr; |
95 |
| - int file_point_size = 37; |
96 |
| - int max_bytes = (int)round(max_ascii_file_size_ * 1024 * 1024); |
97 |
| - int desired_points = max_bytes / file_point_size; |
98 |
| - double voxel_size = 0.001; |
99 |
| - double offset = 0.0002; |
100 |
| - while ((int)cloud.size() > desired_points) |
101 |
| - { |
102 |
| - pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_downsampled = filter(cloud.makeShared(), voxel_size); |
103 |
| - cloud = *cloud_downsampled; |
104 |
| - voxel_size = voxel_size + offset; |
105 |
| - } |
106 |
| - |
107 |
| - // Compute the cloud centroid |
108 |
| - Eigen::Vector4f centroid; |
109 |
| - pcl::compute3DCentroid(cloud, centroid); |
110 |
| - |
111 |
| - // Save int file |
112 |
| - int lastindex = pcd_filename_.find_last_of("."); |
113 |
| - std::string filename = pcd_filename_.substr(0, lastindex); |
114 |
| - filename = filename + ".txt"; |
115 |
| - ROS_INFO_STREAM("[PointCloudToWebgl:] Saving webgl file to " << filename); |
116 |
| - std::fstream f_webgl(filename.c_str(), std::ios::out); |
117 |
| - for (unsigned int i=0; i<cloud.size(); i++) |
118 |
| - { |
119 |
| - f_webgl << cloud[i].x - centroid[0] << "," << |
120 |
| - cloud[i].y - centroid[1] << "," << |
121 |
| - cloud[i].z - centroid[2] << "," << |
122 |
| - (int)cloud[i].r << "," << |
123 |
| - (int)cloud[i].g << "," << |
124 |
| - (int)cloud[i].b << std::endl; |
125 |
| - } |
126 |
| - f_webgl.close(); |
127 |
| - ROS_INFO("[PointCloudToWebgl:] Saved!"); |
| 50 | + ROS_ERROR_STREAM("[PointCloudToWebgl:] Couldn't read file " << input_cloud_); |
| 51 | + return; |
128 | 52 | }
|
| 53 | + copyPointCloud(*cloud_xyzrgb, cloud); |
129 | 54 | }
|
130 |
| - } |
131 | 55 |
|
132 |
| - pcl::PointCloud<pcl::PointXYZ>::Ptr filter(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, double voxel_size) |
133 |
| - { |
134 |
| - // Downsampling using voxel grid |
135 |
| - pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered_ptr(new pcl::PointCloud<pcl::PointXYZ>); |
136 |
| - pcl::VoxelGrid<pcl::PointXYZ> grid_; |
137 |
| - pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_downsampled_ptr(new pcl::PointCloud<pcl::PointXYZ>); |
138 |
| - grid_.setLeafSize(voxel_size, |
139 |
| - voxel_size, |
140 |
| - voxel_size); |
141 |
| - grid_.setDownsampleAllData(true); |
142 |
| - grid_.setInputCloud(cloud); |
143 |
| - grid_.filter(*cloud_downsampled_ptr); |
144 |
| - return cloud_downsampled_ptr; |
145 |
| - } |
| 56 | + // Compute the cloud centroid |
| 57 | + Eigen::Vector4f centroid; |
| 58 | + pcl::compute3DCentroid(cloud, centroid); |
146 | 59 |
|
147 |
| - pcl::PointCloud<pcl::PointXYZRGB>::Ptr filter(pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud, double voxel_size) |
148 |
| - { |
149 |
| - // Downsampling using voxel grid |
150 |
| - pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered_ptr(new pcl::PointCloud<pcl::PointXYZRGB>); |
151 |
| - pcl::VoxelGrid<pcl::PointXYZRGB> grid_; |
152 |
| - pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_downsampled_ptr(new pcl::PointCloud<pcl::PointXYZRGB>); |
153 |
| - |
154 |
| - grid_.setLeafSize(voxel_size, |
155 |
| - voxel_size, |
156 |
| - voxel_size); |
157 |
| - grid_.setDownsampleAllData(true); |
158 |
| - grid_.setInputCloud(cloud); |
159 |
| - grid_.filter(*cloud_downsampled_ptr); |
160 |
| - return cloud_downsampled_ptr; |
| 60 | + // Save int file |
| 61 | + ROS_INFO_STREAM("[PointCloudToWebgl:] Saving webgl file to " << output_cloud_); |
| 62 | + std::fstream f_webgl(output_cloud_.c_str(), std::ios::out); |
| 63 | + for (unsigned int i=0; i<cloud.size(); i++) |
| 64 | + { |
| 65 | + int r = 224; |
| 66 | + int g = 224; |
| 67 | + int b = 224; |
| 68 | + if (cloud_format_ == 1) |
| 69 | + { |
| 70 | + r = (int)cloud[i].r; |
| 71 | + g = (int)cloud[i].g; |
| 72 | + b = (int)cloud[i].b; |
| 73 | + } |
| 74 | + f_webgl << cloud[i].x - centroid[0] << "," << |
| 75 | + cloud[i].y - centroid[1] << "," << |
| 76 | + cloud[i].z - centroid[2] << "," << |
| 77 | + r << "," << |
| 78 | + g << "," << |
| 79 | + b << std::endl; |
| 80 | + |
| 81 | + } |
| 82 | + f_webgl.close(); |
| 83 | + ROS_INFO("[PointCloudToWebgl:] Saved!"); |
161 | 84 | }
|
162 | 85 |
|
| 86 | + private: |
| 87 | + std::string input_cloud_; |
| 88 | + std::string output_cloud_; |
| 89 | + int cloud_format_; |
163 | 90 | };
|
164 | 91 |
|
165 | 92 | /**
|
166 | 93 | * Main entry point of the code
|
167 | 94 | */
|
168 | 95 | int main(int argc, char **argv)
|
169 | 96 | {
|
170 |
| - ros::init(argc, argv, "pointcloud_to_webgl"); |
171 |
| - PointCloudToWebgl node; |
172 |
| - ros::spin(); |
| 97 | + if (argc < 4) |
| 98 | + { |
| 99 | + std::cout << "Usage: " << argv[0] << " INPUT_PCD FORMAT OUTPUT_CSV" << std::endl; |
| 100 | + std::cout << " Example: " << argv[0] << " input_cloud.pcd 0 output_cloud.csv" << std::endl; |
| 101 | + return 0; |
| 102 | + } |
| 103 | + |
| 104 | + // Read inputs |
| 105 | + std::string input_cloud(argv[1]); |
| 106 | + std::string output_cloud(argv[3]); |
| 107 | + int cloud_format = boost::lexical_cast<int>(argv[2]); |
| 108 | + |
| 109 | + // Convert |
| 110 | + PointCloudToWebgl converter(input_cloud, cloud_format, output_cloud); |
| 111 | + converter.convert(); |
| 112 | + |
173 | 113 | return 0;
|
174 | 114 | }
|
175 | 115 |
|
0 commit comments