ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
FilePTS.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include <FileSystem.h>
9 #include <Helper.h>
10 #include <Logging.h>
11 #include <ProgressReporters.h>
12 
13 #include <cstdio>
14 
18 
19 namespace cloudViewer {
20 namespace t {
21 namespace io {
22 
23 bool ReadPointCloudFromPTS(const std::string &filename,
24  geometry::PointCloud &pointcloud,
26  try {
27  // Pointcloud is empty if the file is not read successfully.
28  pointcloud.Clear();
29 
30  // Get num_points.
32  if (!file.Open(filename, "rb")) {
33  utility::LogWarning("Read PTS failed: unable to open file: {}",
34  filename);
35  return false;
36  }
37 
38  int64_t num_points = 0;
39  const char *line_buffer;
40  if ((line_buffer = file.ReadLine())) {
41  const char *format;
42  if (std::is_same<int64_t, long>::value) {
43  format = "%ld";
44  } else {
45  format = "%lld";
46  }
47  sscanf(line_buffer, format, &num_points);
48  }
49  if (num_points < 0) {
51  "Read PTS failed: number of points must be >= 0.");
52  return false;
53  } else if (num_points == 0) {
54  pointcloud.SetPointPositions(core::Tensor({0, 3}, core::Float32));
55  return true;
56  }
57  utility::CountingProgressReporter reporter(params.update_progress);
58  reporter.SetTotal(num_points);
59 
60  // Store data start position.
61  int64_t start_pos = ftell(file.GetFILE());
62 
63  float *points_ptr = nullptr;
64  float *intensities_ptr = nullptr;
65  uint8_t *colors_ptr = nullptr;
66  size_t num_fields = 0;
67 
68  if ((line_buffer = file.ReadLine())) {
69  num_fields = utility::SplitString(line_buffer, " ").size();
70 
71  // X Y Z I R G B.
72  if (num_fields == 7) {
73  pointcloud.SetPointPositions(
74  core::Tensor({num_points, 3}, core::Float32));
75  points_ptr = pointcloud.GetPointPositions().GetDataPtr<float>();
76  pointcloud.SetPointAttr(
77  "intensities",
78  core::Tensor({num_points, 1}, core::Float32));
79  intensities_ptr = pointcloud.GetPointAttr("intensities")
80  .GetDataPtr<float>();
81  pointcloud.SetPointColors(
82  core::Tensor({num_points, 3}, core::UInt8));
83  colors_ptr = pointcloud.GetPointColors().GetDataPtr<uint8_t>();
84  }
85  // X Y Z R G B.
86  else if (num_fields == 6) {
87  pointcloud.SetPointPositions(
88  core::Tensor({num_points, 3}, core::Float32));
89  points_ptr = pointcloud.GetPointPositions().GetDataPtr<float>();
90  pointcloud.SetPointColors(
91  core::Tensor({num_points, 3}, core::UInt8));
92  colors_ptr = pointcloud.GetPointColors().GetDataPtr<uint8_t>();
93  }
94  // X Y Z I.
95  else if (num_fields == 4) {
96  pointcloud.SetPointPositions(
97  core::Tensor({num_points, 3}, core::Float32));
98  points_ptr = pointcloud.GetPointPositions().GetDataPtr<float>();
99  pointcloud.SetPointAttr(
100  "intensities",
101  core::Tensor({num_points, 1}, core::Float32));
102  intensities_ptr = pointcloud.GetPointAttr("intensities")
103  .GetDataPtr<float>();
104  }
105  // X Y Z.
106  else if (num_fields == 3) {
107  pointcloud.SetPointPositions(
108  core::Tensor({num_points, 3}, core::Float32));
109  points_ptr = pointcloud.GetPointPositions().GetDataPtr<float>();
110  } else {
111  utility::LogWarning("Read PTS failed: unknown pts format: {}",
112  line_buffer);
113  return false;
114  }
115  }
116 
117  // Go to data start position.
118  fseek(file.GetFILE(), start_pos, 0);
119 
120  int64_t idx = 0;
121  while (idx < num_points && (line_buffer = file.ReadLine())) {
122  float x, y, z, i;
123  int r, g, b;
124  // X Y Z I R G B.
125  if (num_fields == 7 && (sscanf(line_buffer, "%f %f %f %f %d %d %d",
126  &x, &y, &z, &i, &r, &g, &b) == 7)) {
127  points_ptr[3 * idx + 0] = x;
128  points_ptr[3 * idx + 1] = y;
129  points_ptr[3 * idx + 2] = z;
130  intensities_ptr[idx] = i;
131  colors_ptr[3 * idx + 0] = r;
132  colors_ptr[3 * idx + 1] = g;
133  colors_ptr[3 * idx + 2] = b;
134  }
135  // X Y Z R G B.
136  else if (num_fields == 6 &&
137  (sscanf(line_buffer, "%f %f %f %d %d %d", &x, &y, &z, &r,
138  &g, &b) == 6)) {
139  points_ptr[3 * idx + 0] = x;
140  points_ptr[3 * idx + 1] = y;
141  points_ptr[3 * idx + 2] = z;
142  colors_ptr[3 * idx + 0] = r;
143  colors_ptr[3 * idx + 1] = g;
144  colors_ptr[3 * idx + 2] = b;
145  }
146  // X Y Z I.
147  else if (num_fields == 4 && (sscanf(line_buffer, "%f %f %f %f", &x,
148  &y, &z, &i) == 4)) {
149  points_ptr[3 * idx + 0] = x;
150  points_ptr[3 * idx + 1] = y;
151  points_ptr[3 * idx + 2] = z;
152  intensities_ptr[idx] = i;
153  }
154  // X Y Z.
155  else if (num_fields == 3 &&
156  sscanf(line_buffer, "%f %f %f", &x, &y, &z) == 3) {
157  points_ptr[3 * idx + 0] = x;
158  points_ptr[3 * idx + 1] = y;
159  points_ptr[3 * idx + 2] = z;
160  } else {
161  utility::LogWarning("Read PTS failed at line: {}", line_buffer);
162  return false;
163  }
164  idx++;
165  if (idx % 1000 == 0) {
166  reporter.Update(idx);
167  }
168  }
169 
170  reporter.Finish();
171  return true;
172  } catch (const std::exception &e) {
173  utility::LogWarning("Read PTS failed with exception: {}", e.what());
174  return false;
175  }
176 }
177 
179  core::Tensor color_values;
180  if (color_in.GetDtype() == core::Float32 ||
181  color_in.GetDtype() == core::Float64) {
182  color_values = color_in.Clip(0, 1).Mul(255).Round();
183  } else if (color_in.GetDtype() == core::Bool) {
184  color_values = color_in.To(core::UInt8) * 255;
185  } else {
186  color_values = color_in;
187  }
188  return color_values.To(core::UInt8);
189 }
190 
191 bool WritePointCloudToPTS(const std::string &filename,
192  const geometry::PointCloud &pointcloud,
193  const WritePointCloudOption &params) {
194  try {
196  if (!file.Open(filename, "w")) {
197  utility::LogWarning("Write PTS failed: unable to open file: {}",
198  filename);
199  return false;
200  }
201 
202  utility::CountingProgressReporter reporter(params.update_progress);
203  int64_t num_points = 0;
204 
205  if (!pointcloud.IsEmpty()) {
206  num_points = pointcloud.GetPointPositions().GetLength();
207  }
208 
209  // Assert attribute shapes.
210  if (pointcloud.HasPointPositions()) {
212  {num_points, 3});
213  }
214  if (pointcloud.HasPointColors()) {
216  {num_points, 3});
217  }
218  if (pointcloud.HasPointAttr("intensities")) {
219  core::AssertTensorShape(pointcloud.GetPointAttr("intensities"),
220  {num_points, 1});
221  }
222 
223  reporter.SetTotal(num_points);
224 
225  if (fprintf(file.GetFILE(), "%zu\r\n", (size_t)num_points) < 0) {
226  utility::LogWarning("Write PTS failed: unable to write file: {}",
227  filename);
228  return false;
229  }
230 
231  const float *points_ptr = nullptr;
232  const float *intensities_ptr = nullptr;
233  const uint8_t *colors_ptr = nullptr;
235 
236  if (num_points > 0) {
237  points_ptr = pointcloud.GetPointPositions()
238  .To(core::Float32)
239  .GetDataPtr<float>();
240  }
241 
242  // X Y Z I R G B.
243  if (pointcloud.HasPointColors() &&
244  pointcloud.HasPointAttr("intensities")) {
246  colors_ptr = colors.GetDataPtr<uint8_t>();
247  intensities_ptr = pointcloud.GetPointAttr("intensities")
248  .To(core::Float32)
249  .GetDataPtr<float>();
250  for (int i = 0; i < num_points; i++) {
251  if (fprintf(file.GetFILE(),
252  "%.10f %.10f %.10f %.10f %d %d %d\r\n",
253  points_ptr[3 * i + 0], points_ptr[3 * i + 1],
254  points_ptr[3 * i + 2], intensities_ptr[i],
255  colors_ptr[3 * i + 0], colors_ptr[3 * i + 1],
256  colors_ptr[3 * i + 2]) < 0) {
258  "Write PTS failed: unable to write file: {}",
259  filename);
260  return false;
261  }
262 
263  if (i % 1000 == 0) {
264  reporter.Update(i);
265  }
266  }
267  }
268  // X Y Z R G B.
269  else if (pointcloud.HasPointColors()) {
271  colors_ptr = colors.GetDataPtr<uint8_t>();
272  for (int i = 0; i < num_points; i++) {
273  if (fprintf(file.GetFILE(), "%.10f %.10f %.10f %d %d %d\r\n",
274  points_ptr[3 * i + 0], points_ptr[3 * i + 1],
275  points_ptr[3 * i + 2], colors_ptr[3 * i + 0],
276  colors_ptr[3 * i + 1], colors_ptr[3 * i + 2]) < 0) {
278  "Write PTS failed: unable to write file: {}",
279  filename);
280  return false;
281  }
282 
283  if (i % 1000 == 0) {
284  reporter.Update(i);
285  }
286  }
287  }
288  // X Y Z I.
289  else if (pointcloud.HasPointAttr("intensities")) {
290  intensities_ptr = pointcloud.GetPointAttr("intensities")
291  .To(core::Float32)
292  .GetDataPtr<float>();
293  for (int i = 0; i < num_points; i++) {
294  if (fprintf(file.GetFILE(), "%.10f %.10f %.10f %.10f\r\n",
295  points_ptr[3 * i + 0], points_ptr[3 * i + 1],
296  points_ptr[3 * i + 2], intensities_ptr[i]) < 0) {
298  "Write PTS failed: unable to write file: {}",
299  filename);
300  return false;
301  }
302 
303  if (i % 1000 == 0) {
304  reporter.Update(i);
305  }
306  }
307  }
308  // X Y Z.
309  else {
310  for (int i = 0; i < num_points; i++) {
311  if (fprintf(file.GetFILE(), "%.10f %.10f %.10f\r\n",
312  points_ptr[3 * i + 0], points_ptr[3 * i + 1],
313  points_ptr[3 * i + 2]) < 0) {
315  "Write PTS failed: unable to write file: {}",
316  filename);
317  return false;
318  }
319 
320  if (i % 1000 == 0) {
321  reporter.Update(i);
322  }
323  }
324  }
325 
326  reporter.Finish();
327  return true;
328  } catch (const std::exception &e) {
329  utility::LogWarning("Write PTS failed with exception: {}", e.what());
330  return false;
331  }
332  return true;
333 }
334 
335 } // namespace io
336 } // namespace t
337 } // namespace cloudViewer
std::string filename
filament::Texture::InternalFormat format
cmdLineReadable * params[]
#define AssertTensorShape(tensor,...)
Definition: TensorCheck.h:61
int64_t GetLength() const
Definition: Tensor.h:1125
Tensor Round() const
Element-wise round value of a tensor, returning a new tensor.
Definition: Tensor.cpp:1423
Dtype GetDtype() const
Definition: Tensor.h:1164
Tensor Clip(Scalar min_val, Scalar max_val) const
Definition: Tensor.cpp:1392
Tensor Mul(const Tensor &value) const
Multiplies a tensor and returns the resulting tensor.
Definition: Tensor.cpp:1169
Tensor To(Dtype dtype, bool copy=false) const
Definition: Tensor.cpp:739
A point cloud contains a list of 3D points.
Definition: PointCloud.h:82
void SetPointColors(const core::Tensor &value)
Set the value of the "colors" attribute. Convenience function.
Definition: PointCloud.h:192
bool HasPointAttr(const std::string &key) const
Definition: PointCloud.h:207
void SetPointPositions(const core::Tensor &value)
Set the value of the "positions" attribute. Convenience function.
Definition: PointCloud.h:186
core::Tensor & GetPointPositions()
Get the value of the "positions" attribute. Convenience function.
Definition: PointCloud.h:124
bool IsEmpty() const override
Returns !HasPointPositions().
Definition: PointCloud.h:257
const TensorMap & GetPointAttr() const
Getter for point_attr_ TensorMap. Used in Pybind.
Definition: PointCloud.h:111
PointCloud & Clear() override
Clear all data in the point cloud.
Definition: PointCloud.h:251
void SetPointAttr(const std::string &key, const core::Tensor &value)
Definition: PointCloud.h:177
core::Tensor & GetPointColors()
Get the value of the "colors" attribute. Convenience function.
Definition: PointCloud.h:127
bool Open(const std::string &filename, const std::string &mode)
Open a file.
Definition: FileSystem.cpp:739
FILE * GetFILE()
Returns the underlying C FILE pointer.
Definition: FileSystem.h:264
double colors[3]
#define LogWarning(...)
Definition: Logging.h:72
Helper functions for the ml ops.
const Dtype Bool
Definition: Dtype.cpp:52
const Dtype UInt8
Definition: Dtype.cpp:48
const Dtype Float64
Definition: Dtype.cpp:43
const Dtype Float32
Definition: Dtype.cpp:42
bool ReadPointCloudFromPTS(const std::string &filename, geometry::PointCloud &pointcloud, const ReadPointCloudOption &params)
Definition: FilePTS.cpp:23
bool WritePointCloudToPTS(const std::string &filename, const geometry::PointCloud &pointcloud, const WritePointCloudOption &params)
Definition: FilePTS.cpp:191
core::Tensor ConvertColorTensorToUint8(const core::Tensor &color_in)
Definition: FilePTS.cpp:178
void SplitString(std::vector< std::string > &tokens, const std::string &str, const std::string &delimiters=" ", bool trim_empty_str=true)
Definition: Helper.cpp:197
Generic file read and write utility for python interface.
Optional parameters to ReadPointCloud.
Definition: FileIO.h:39
Optional parameters to WritePointCloud.
Definition: FileIO.h:77