ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
PcdFilter.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 "PcdFilter.h"
9 
10 #include <liblzf/lzf.h>
11 
12 // Dialog
13 #include <ui_PCDOutputFormatDlg.h>
14 #include <ui_savePCDFileDlg.h>
15 
16 // PclUtils
17 #include <PCLConv.h>
18 #include <cc2sm.h>
19 #include <sm2cc.h>
20 
21 // CV_CORE_LIB
22 #include <CVTools.h>
23 #include <FileSystem.h>
24 #include <Helper.h>
25 #include <ProgressReporters.h>
26 
27 // CV_DB_LIB
28 #include <ecvGBLSensor.h>
29 #include <ecvHObjectCaster.h>
30 #include <ecvPointCloud.h>
31 #include <ecvScalarField.h>
32 
33 // Qt
34 #include <QDialog>
35 #include <QFileInfo>
36 #include <QPushButton>
37 #include <QSettings>
38 
39 // System
40 #include <iostream>
41 
42 // pcl
43 #include <pcl/filters/passthrough.h>
44 #include <pcl/io/pcd_io.h>
45 
46 using namespace cloudViewer;
47 namespace {
48 
49 enum PCDDataType {
50  PCD_DATA_ASCII = 0,
51  PCD_DATA_BINARY = 1,
52  PCD_DATA_BINARY_COMPRESSED = 2
53 };
54 
55 struct PCLPointField {
56 public:
57  std::string name;
58  int size;
59  char type;
60  int count;
61  // helper variable
62  int count_offset;
63  int offset;
64 };
65 
66 struct PCDHeader {
67 public:
68  std::string version;
69  std::vector<PCLPointField> fields;
70  int width;
71  int height;
72  int points;
74  std::string viewpoint;
75  // helper variables
76  int elementnum;
77  int pointsize;
78  bool has_points;
79  bool has_normals;
80  bool has_colors;
81  bool has_ring;
82  bool has_intensity;
83  bool has_timestamp;
84 };
85 
86 bool CheckHeader(PCDHeader& header) {
87  if (header.points <= 0 || header.pointsize <= 0) {
88  CVLog::Warning(QString("[CheckHeader] PCD has no data."));
89  return false;
90  }
91  if (header.fields.size() == 0 || header.pointsize <= 0) {
92  CVLog::Warning(QString("[CheckHeader] PCD has no fields."));
93  return false;
94  }
95  header.has_points = false;
96  header.has_normals = false;
97  header.has_colors = false;
98  header.has_ring = false;
99  header.has_intensity = false;
100  header.has_timestamp = false;
101  bool has_x = false;
102  bool has_y = false;
103  bool has_z = false;
104  bool has_normal_x = false;
105  bool has_normal_y = false;
106  bool has_normal_z = false;
107  bool has_rgb = false;
108  bool has_rgba = false;
109  bool has_ring = false;
110  bool has_intensity = false;
111  bool has_timestamp = false;
112  for (const auto& field : header.fields) {
113  if (field.name == "x") {
114  has_x = true;
115  } else if (field.name == "y") {
116  has_y = true;
117  } else if (field.name == "z") {
118  has_z = true;
119  } else if (field.name == "normal_x") {
120  has_normal_x = true;
121  } else if (field.name == "normal_y") {
122  has_normal_y = true;
123  } else if (field.name == "normal_z") {
124  has_normal_z = true;
125  } else if (field.name == "rgb") {
126  has_rgb = true;
127  } else if (field.name == "rgba") {
128  has_rgba = true;
129  } else if (field.name == "intensity") {
130  has_intensity = true;
131  } else if (field.name == "timestamp") {
132  has_timestamp = true;
133  } else if (field.name == "ring") {
134  has_ring = true;
135  }
136  }
137  header.has_points = (has_x && has_y && has_z);
138  header.has_normals = (has_normal_x && has_normal_y && has_normal_z);
139  header.has_colors = (has_rgb || has_rgba);
140  header.has_intensity = has_intensity;
141  header.has_timestamp = has_timestamp;
142  header.has_ring = has_ring;
143  if (header.has_points == false) {
144  CVLog::Warning(QString(
145  "[CheckHeader] Fields for point data are not complete."));
146  return false;
147  }
148  return true;
149 }
150 
151 bool ReadPCDHeader(FILE* file, PCDHeader& header) {
152  char line_buffer[DEFAULT_IO_BUFFER_SIZE];
153  size_t specified_channel_count = 0;
154 
155  while (fgets(line_buffer, DEFAULT_IO_BUFFER_SIZE, file)) {
156  std::string line(line_buffer);
157  if (line == "") {
158  continue;
159  }
160  std::vector<std::string> st;
161  utility::SplitString(st, line, "\t\r\n ");
162  std::stringstream sstream(line);
163  sstream.imbue(std::locale::classic());
164  std::string line_type;
165  sstream >> line_type;
166  if (line_type.substr(0, 1) == "#") {
167  } else if (line_type.substr(0, 7) == "VERSION") {
168  if (st.size() >= 2) {
169  header.version = st[1];
170  }
171  } else if (line_type.substr(0, 6) == "FIELDS" ||
172  line_type.substr(0, 7) == "COLUMNS") {
173  specified_channel_count = st.size() - 1;
174  if (specified_channel_count == 0) {
175  CVLog::Warning(QString("[ReadPCDHeader] Bad PCD file format."));
176  return false;
177  }
178  header.fields.resize(specified_channel_count);
179  int count_offset = 0, offset = 0;
180  for (size_t i = 0; i < specified_channel_count;
181  i++, count_offset += 1, offset += 4) {
182  header.fields[i].name = st[i + 1];
183  header.fields[i].size = 4;
184  header.fields[i].type = 'F';
185  header.fields[i].count = 1;
186  header.fields[i].count_offset = count_offset;
187  header.fields[i].offset = offset;
188  }
189  header.elementnum = count_offset;
190  header.pointsize = offset;
191  } else if (line_type.substr(0, 4) == "SIZE") {
192  if (specified_channel_count != st.size() - 1) {
193  CVLog::Warning(QString("[ReadPCDHeader] Bad PCD file format."));
194  return false;
195  }
196  int offset = 0, col_type = 0;
197  for (size_t i = 0; i < specified_channel_count;
198  i++, offset += col_type) {
199  sstream >> col_type;
200  header.fields[i].size = col_type;
201  header.fields[i].offset = offset;
202  }
203  header.pointsize = offset;
204  } else if (line_type.substr(0, 4) == "TYPE") {
205  if (specified_channel_count != st.size() - 1) {
206  CVLog::Warning(QString("[ReadPCDHeader] Bad PCD file format."));
207  return false;
208  }
209  for (size_t i = 0; i < specified_channel_count; i++) {
210  header.fields[i].type = st[i + 1].c_str()[0];
211  }
212  } else if (line_type.substr(0, 5) == "COUNT") {
213  if (specified_channel_count != st.size() - 1) {
214  CVLog::Warning(QString("[ReadPCDHeader] Bad PCD file format."));
215  return false;
216  }
217  int count_offset = 0, offset = 0, col_count = 0;
218  for (size_t i = 0; i < specified_channel_count; i++) {
219  sstream >> col_count;
220  header.fields[i].count = col_count;
221  header.fields[i].count_offset = count_offset;
222  header.fields[i].offset = offset;
223  count_offset += col_count;
224  offset += col_count * header.fields[i].size;
225  }
226  header.elementnum = count_offset;
227  header.pointsize = offset;
228  } else if (line_type.substr(0, 5) == "WIDTH") {
229  sstream >> header.width;
230  } else if (line_type.substr(0, 6) == "HEIGHT") {
231  sstream >> header.height;
232  header.points = header.width * header.height;
233  } else if (line_type.substr(0, 9) == "VIEWPOINT") {
234  if (st.size() >= 2) {
235  header.viewpoint = st[1];
236  }
237  } else if (line_type.substr(0, 6) == "POINTS") {
238  sstream >> header.points;
239  } else if (line_type.substr(0, 4) == "DATA") {
240  header.datatype = PCD_DATA_ASCII;
241  if (st.size() >= 2) {
242  if (st[1].substr(0, 17) == "binary_compressed") {
243  header.datatype = PCD_DATA_BINARY_COMPRESSED;
244  } else if (st[1].substr(0, 6) == "binary") {
245  header.datatype = PCD_DATA_BINARY;
246  }
247  }
248  break;
249  }
250  }
251  if (CheckHeader(header) == false) {
252  return false;
253  }
254  return true;
255 }
256 
257 PointCoordinateType UnpackBinaryPCDElement(const char* data_ptr,
258  const char type,
259  const int size) {
260  if (type == 'I') {
261  if (size == 1) {
262  std::int8_t data;
263  memcpy(&data, data_ptr, sizeof(data));
264  return static_cast<PointCoordinateType>(data);
265  } else if (size == 2) {
266  std::int16_t data;
267  memcpy(&data, data_ptr, sizeof(data));
268  return static_cast<PointCoordinateType>(data);
269  } else if (size == 4) {
270  std::int32_t data;
271  memcpy(&data, data_ptr, sizeof(data));
272  return static_cast<PointCoordinateType>(data);
273  } else {
274  return static_cast<PointCoordinateType>(0.0);
275  }
276  } else if (type == 'U') {
277  if (size == 1) {
278  std::uint8_t data;
279  memcpy(&data, data_ptr, sizeof(data));
280  return static_cast<PointCoordinateType>(data);
281  } else if (size == 2) {
282  std::uint16_t data;
283  memcpy(&data, data_ptr, sizeof(data));
284  return static_cast<PointCoordinateType>(data);
285  } else if (size == 4) {
286  std::uint32_t data;
287  memcpy(&data, data_ptr, sizeof(data));
288  return static_cast<PointCoordinateType>(data);
289  } else {
290  return static_cast<PointCoordinateType>(0.0);
291  }
292  } else if (type == 'F') {
293  if (size == 4) {
294  float data;
295  memcpy(&data, data_ptr, sizeof(data));
296  return static_cast<PointCoordinateType>(data);
297  } else {
298  return static_cast<PointCoordinateType>(0.0);
299  }
300  }
301  return static_cast<PointCoordinateType>(0.0);
302 }
303 
304 ecvColor::Rgb UnpackBinaryPCDColor(const char* data_ptr,
305  const char type,
306  const int size) {
307  if (size == 4) {
308  std::uint8_t data[4];
309  memcpy(data, data_ptr, 4);
310  // color data is packed in BGR order.
311  return ecvColor::Rgb(data[2], data[1], data[0]);
312  } else {
313  return ecvColor::Rgb();
314  }
315 }
316 
317 ScalarType UnpackBinaryPCDScalar(const char* data_ptr,
318  const char type,
319  const int size) {
320  if (size == 1) {
321  std::uint8_t data;
322  memcpy(&data, data_ptr, 1);
323  ScalarType scalar = static_cast<ScalarType>(data);
324  return scalar;
325  } else {
326  return static_cast<ScalarType>(0);
327  }
328 }
329 
330 PointCoordinateType UnpackASCIIPCDElement(const char* data_ptr,
331  const char type,
332  const int size) {
333  char* end;
334  if (type == 'I') {
335  return static_cast<PointCoordinateType>(std::strtol(data_ptr, &end, 0));
336  } else if (type == 'U') {
337  return static_cast<PointCoordinateType>(
338  std::strtoul(data_ptr, &end, 0));
339  } else if (type == 'F') {
340  return static_cast<PointCoordinateType>(std::strtod(data_ptr, &end));
341  }
342  return static_cast<PointCoordinateType>(0.0);
343 }
344 
345 ecvColor::Rgb UnpackASCIIPCDColor(const char* data_ptr,
346  const char type,
347  const int size) {
348  if (size == 4) {
349  std::uint8_t data[4] = {0, 0, 0, 0};
350  char* end;
351  if (type == 'I') {
352  std::int32_t value = std::strtol(data_ptr, &end, 0);
353  memcpy(data, &value, 4);
354  } else if (type == 'U') {
355  std::uint32_t value = std::strtoul(data_ptr, &end, 0);
356  memcpy(data, &value, 4);
357  } else if (type == 'F') {
358  float value = std::strtof(data_ptr, &end);
359  memcpy(data, &value, 4);
360  }
361  return ecvColor::Rgb(data[2], data[1], data[0]);
362  } else {
363  return ecvColor::Rgb();
364  }
365 }
366 
367 ScalarType UnpackASCIIPCDScalar(const char* data_ptr,
368  const char type,
369  const int size) {
370  if (size == 1) {
371  std::uint8_t data;
372  char* end;
373  if (type == 'I') {
374  std::int32_t value = std::strtol(data_ptr, &end, 0);
375  memcpy(&data, &value, 1);
376  } else if (type == 'U') {
377  std::uint32_t value = std::strtoul(data_ptr, &end, 0);
378  memcpy(&data, &value, 1);
379  } else if (type == 'F') {
380  float value = std::strtof(data_ptr, &end);
381  memcpy(&data, &value, 1);
382  }
383  ScalarType scalar = static_cast<ScalarType>(data);
384  return scalar;
385  } else {
386  return static_cast<ScalarType>(0);
387  }
388 }
389 
390 bool ReadPCDData(FILE* file,
391  const PCDHeader& header,
392  ccPointCloud& pointcloud) {
393  pointcloud.clear();
394  // The header should have been checked
395  if (header.has_points) {
396  pointcloud.resize(static_cast<unsigned int>(header.points));
397  } else {
398  CVLog::Warning(QString(
399  "[ReadPCDData] Fields for point data are not complete."));
400  return false;
401  }
402  if (header.has_normals) {
403  pointcloud.reserveTheNormsTable();
404  }
405  if (header.has_colors) {
406  pointcloud.resizeTheRGBTable();
407  }
408 
409  // if the input field already exists...
410  size_t pointCount = static_cast<size_t>(header.points);
411 
412  // create new scalar field
413  ccScalarField* cc_intensity_field = nullptr;
414  if (header.has_intensity) {
415  int id = pointcloud.getScalarFieldIndexByName("intensity");
416  if (id >= 0) {
417  pointcloud.deleteScalarField(id);
418  }
419 
420  cc_intensity_field = new ccScalarField("intensity");
421  if (!cc_intensity_field->reserveSafe(
422  static_cast<unsigned>(pointCount))) {
423  cc_intensity_field->release();
424  return false;
425  }
426  }
427  ccScalarField* cc_timestamp_field = nullptr;
428  if (header.has_timestamp) {
429  int id = pointcloud.getScalarFieldIndexByName("timestamp");
430  if (id >= 0) {
431  pointcloud.deleteScalarField(id);
432  }
433 
434  cc_timestamp_field = new ccScalarField("timestamp");
435  if (!cc_timestamp_field->reserveSafe(
436  static_cast<unsigned>(pointCount))) {
437  cc_timestamp_field->release();
438  return false;
439  }
440  }
441  ccScalarField* cc_ring_field = nullptr;
442  if (header.has_ring) {
443  int id = pointcloud.getScalarFieldIndexByName("ring");
444  if (id >= 0) {
445  pointcloud.deleteScalarField(id);
446  }
447  cc_ring_field = new ccScalarField("ring");
448  if (!cc_ring_field->reserveSafe(static_cast<unsigned>(pointCount))) {
449  cc_ring_field->release();
450  return false;
451  }
452  }
453 
454  std::function<bool(double)> update_progress;
455  utility::CountingProgressReporter reporter(update_progress);
456  reporter.SetTotal(header.points);
457 
458  CCVector3 P(0, 0, 0);
459  CCVector3 N(0, 0, 0);
460  ecvColor::Rgb col;
461  ScalarType ring;
462  ScalarType intensity;
463  ScalarType timestamp;
464 
465  if (header.datatype == PCD_DATA_ASCII) {
466  char line_buffer[DEFAULT_IO_BUFFER_SIZE];
467  unsigned int idx = 0;
468  while (fgets(line_buffer, DEFAULT_IO_BUFFER_SIZE, file) &&
469  idx < (unsigned int)header.points) {
470  std::string line(line_buffer);
471  std::vector<std::string> strs;
472  utility::SplitString(strs, line, "\t\r\n ");
473  if ((int)strs.size() < header.elementnum) {
474  continue;
475  }
476 
477  bool find_point = false;
478  bool find_normal = false;
479  bool find_color = false;
480  bool find_ring = false;
481  bool find_intensity = false;
482  bool find_timestamp = false;
483  for (size_t i = 0; i < header.fields.size(); i++) {
484  const auto& field = header.fields[i];
485  if (field.name == "x") {
486  find_point = true;
487  P.x = UnpackASCIIPCDElement(
488  strs[field.count_offset].c_str(), field.type,
489  field.size);
490  } else if (field.name == "y") {
491  find_point = true;
492  P.y = UnpackASCIIPCDElement(
493  strs[field.count_offset].c_str(), field.type,
494  field.size);
495  } else if (field.name == "z") {
496  find_point = true;
497  P.z = UnpackASCIIPCDElement(
498  strs[field.count_offset].c_str(), field.type,
499  field.size);
500  } else if (field.name == "normal_x") {
501  find_normal = true;
502  N.x = UnpackASCIIPCDElement(
503  strs[field.count_offset].c_str(), field.type,
504  field.size);
505  } else if (field.name == "normal_y") {
506  find_normal = true;
507  N.y = UnpackASCIIPCDElement(
508  strs[field.count_offset].c_str(), field.type,
509  field.size);
510  } else if (field.name == "normal_z") {
511  find_normal = true;
512  N.z = UnpackASCIIPCDElement(
513  strs[field.count_offset].c_str(), field.type,
514  field.size);
515  } else if (field.name == "rgb" || field.name == "rgba") {
516  find_color = true;
517  col = UnpackASCIIPCDColor(strs[field.count_offset].c_str(),
518  field.type, field.size);
519  } else if (field.name == "intensity") {
520  find_intensity = true;
521  intensity = UnpackASCIIPCDScalar(
522  strs[field.count_offset].c_str(), field.type,
523  field.size);
524  } else if (field.name == "timestamp") {
525  find_timestamp = true;
526  timestamp = UnpackASCIIPCDScalar(
527  strs[field.count_offset].c_str(), field.type,
528  field.size);
529  } else if (field.name == "ring") {
530  find_ring = true;
531  ring = UnpackASCIIPCDScalar(
532  strs[field.count_offset].c_str(), field.type,
533  field.size);
534  }
535  }
536 
537  if (find_point) {
538  pointcloud.setPoint(idx, P);
539  }
540  if (header.has_normals && find_normal) {
541  pointcloud.addNorm(N);
542  }
543  if (header.has_colors && find_color) {
544  pointcloud.setPointColor(idx, col);
545  }
546  if (header.has_intensity && find_intensity) {
547  cc_intensity_field->addElement(intensity);
548  }
549  if (header.has_timestamp && find_timestamp) {
550  cc_timestamp_field->addElement(timestamp);
551  }
552  if (header.has_ring && find_ring) {
553  cc_ring_field->addElement(ring);
554  }
555 
556  idx++;
557  if (idx % 1000 == 0) {
558  reporter.Update(idx);
559  }
560  }
561  } else if (header.datatype == PCD_DATA_BINARY) {
562  std::unique_ptr<char[]> buffer(new char[header.pointsize]);
563  for (unsigned int i = 0; i < (unsigned int)header.points; i++) {
564  if (fread(buffer.get(), header.pointsize, 1, file) != 1) {
566  QString("[ReadPCDData] Failed to read data record."));
567  pointcloud.clear();
568  return false;
569  }
570 
571  bool find_point = false;
572  bool find_normal = false;
573  bool find_color = false;
574  bool find_ring = false;
575  bool find_intensity = false;
576  bool find_timestamp = false;
577  for (const auto& field : header.fields) {
578  if (field.name == "x") {
579  find_point = true;
580  P.x = UnpackBinaryPCDElement(buffer.get() + field.offset,
581  field.type, field.size);
582  } else if (field.name == "y") {
583  find_point = true;
584  P.y = UnpackBinaryPCDElement(buffer.get() + field.offset,
585  field.type, field.size);
586  } else if (field.name == "z") {
587  find_point = true;
588  P.z = UnpackBinaryPCDElement(buffer.get() + field.offset,
589  field.type, field.size);
590  } else if (field.name == "normal_x") {
591  find_normal = true;
592  N.x = UnpackBinaryPCDElement(buffer.get() + field.offset,
593  field.type, field.size);
594  } else if (field.name == "normal_y") {
595  find_normal = true;
596  N.y = UnpackBinaryPCDElement(buffer.get() + field.offset,
597  field.type, field.size);
598  } else if (field.name == "normal_z") {
599  find_normal = true;
600  N.z = UnpackBinaryPCDElement(buffer.get() + field.offset,
601  field.type, field.size);
602  } else if (field.name == "rgb" || field.name == "rgba") {
603  find_color = true;
604  col = UnpackBinaryPCDColor(buffer.get() + field.offset,
605  field.type, field.size);
606  } else if (field.name == "intensity") {
607  find_intensity = true;
608  intensity =
609  UnpackBinaryPCDScalar(buffer.get() + field.offset,
610  field.type, field.size);
611  } else if (field.name == "timestamp") {
612  find_timestamp = true;
613  timestamp =
614  UnpackBinaryPCDScalar(buffer.get() + field.offset,
615  field.type, field.size);
616  } else if (field.name == "ring") {
617  find_ring = true;
618  ring = UnpackBinaryPCDScalar(buffer.get() + field.offset,
619  field.type, field.size);
620  }
621  }
622 
623  if (find_point) {
624  pointcloud.setPoint(i, P);
625  }
626  if (header.has_normals && find_normal) {
627  pointcloud.addNorm(N);
628  }
629  if (header.has_colors && find_color) {
630  pointcloud.setPointColor(i, col);
631  }
632  if (header.has_intensity && find_intensity) {
633  cc_intensity_field->addElement(intensity);
634  }
635  if (header.has_timestamp && find_timestamp) {
636  cc_timestamp_field->addElement(timestamp);
637  }
638  if (header.has_ring && find_ring) {
639  cc_ring_field->addElement(ring);
640  }
641 
642  if (i % 1000 == 0) {
643  reporter.Update(i);
644  }
645  }
646  } else if (header.datatype == PCD_DATA_BINARY_COMPRESSED) {
647  double reporter_total = 100.0;
648  reporter.SetTotal(int(reporter_total));
649  reporter.Update(int(reporter_total * 0.01));
650 
651  std::uint32_t compressed_size;
652  std::uint32_t uncompressed_size;
653  if (fread(&compressed_size, sizeof(compressed_size), 1, file) != 1) {
655  QString("[ReadPCDData] Failed to read data record."));
656  pointcloud.clear();
657  return false;
658  }
659  if (fread(&uncompressed_size, sizeof(uncompressed_size), 1, file) !=
660  1) {
662  QString("[ReadPCDData] Failed to read data record."));
663  pointcloud.clear();
664  return false;
665  }
666 
668  QString("PCD data with %1 compressed size, and %2 uncompressed "
669  "size.")
670  .arg(compressed_size)
671  .arg(uncompressed_size));
672  std::unique_ptr<char[]> buffer_compressed(new char[compressed_size]);
673  reporter.Update(int(reporter_total * .1));
674  if (fread(buffer_compressed.get(), 1, compressed_size, file) !=
675  compressed_size) {
677  QString("[ReadPCDData] Failed to read data record."));
678  pointcloud.clear();
679  return false;
680  }
681  std::unique_ptr<char[]> buffer(new char[uncompressed_size]);
682  reporter.Update(int(reporter_total * .2));
683  if (lzf_decompress(buffer_compressed.get(),
684  (unsigned int)compressed_size, buffer.get(),
685  (unsigned int)uncompressed_size) !=
686  uncompressed_size) {
687  CVLog::Warning(QString("[ReadPCDData] Uncompression failed."));
688  pointcloud.clear();
689  return false;
690  }
691 
692  std::vector<CCVector3> normals;
693  if (header.has_normals) {
694  normals.resize(static_cast<unsigned int>(header.points));
695  }
696 
697  for (const auto& field : header.fields) {
698  const char* base_ptr = buffer.get() + field.offset * header.points;
699  double progress =
700  double(base_ptr - buffer.get()) / uncompressed_size;
701  reporter.Update(int(reporter_total * (progress + .2)));
702 
703  if (field.name == "x") {
704  for (size_t i = 0; i < (size_t)header.points; i++) {
705  pointcloud.getPointPtr(i)->x = UnpackBinaryPCDElement(
706  base_ptr + i * field.size * field.count, field.type,
707  field.size);
708  }
709  } else if (field.name == "y") {
710  for (size_t i = 0; i < (size_t)header.points; i++) {
711  pointcloud.getPointPtr(i)->y = UnpackBinaryPCDElement(
712  base_ptr + i * field.size * field.count, field.type,
713  field.size);
714  }
715  } else if (field.name == "z") {
716  for (size_t i = 0; i < (size_t)header.points; i++) {
717  pointcloud.getPointPtr(i)->z = UnpackBinaryPCDElement(
718  base_ptr + i * field.size * field.count, field.type,
719  field.size);
720  }
721  } else if (field.name == "normal_x") {
722  for (size_t i = 0; i < (size_t)header.points; i++) {
723  normals[i].x = UnpackBinaryPCDElement(
724  base_ptr + i * field.size * field.count, field.type,
725  field.size);
726  }
727  } else if (field.name == "normal_y") {
728  for (size_t i = 0; i < (size_t)header.points; i++) {
729  normals[i].y = UnpackBinaryPCDElement(
730  base_ptr + i * field.size * field.count, field.type,
731  field.size);
732  }
733  } else if (field.name == "normal_z") {
734  for (size_t i = 0; i < (size_t)header.points; i++) {
735  normals[i].z = UnpackBinaryPCDElement(
736  base_ptr + i * field.size * field.count, field.type,
737  field.size);
738  }
739  } else if (field.name == "rgb" || field.name == "rgba") {
740  for (unsigned int i = 0; i < (unsigned int)header.points; i++) {
741  ecvColor::Rgb color = UnpackBinaryPCDColor(
742  base_ptr + i * field.size * field.count, field.type,
743  field.size);
744  pointcloud.setPointColor(i, color);
745  }
746  } else if (field.name == "intensity") {
747  for (unsigned int i = 0; i < (unsigned int)header.points; i++) {
748  ScalarType intensity = UnpackBinaryPCDScalar(
749  base_ptr + i * field.size * field.count, field.type,
750  field.size);
751  cc_intensity_field->addElement(intensity);
752  }
753  } else if (field.name == "timestamp") {
754  for (unsigned int i = 0; i < (unsigned int)header.points; i++) {
755  ScalarType timestamp = UnpackBinaryPCDScalar(
756  base_ptr + i * field.size * field.count, field.type,
757  field.size);
758  cc_timestamp_field->addElement(timestamp);
759  }
760  } else if (field.name == "ring") {
761  for (unsigned int i = 0; i < (unsigned int)header.points; i++) {
762  ScalarType ring = UnpackBinaryPCDScalar(
763  base_ptr + i * field.size * field.count, field.type,
764  field.size);
765  cc_ring_field->addElement(ring);
766  }
767  }
768  }
769 
770  if (header.has_normals) {
771  pointcloud.addNorms(normals);
772  }
773  }
774 
775  if (header.has_ring && cc_ring_field) {
776  cc_ring_field->computeMinAndMax();
777  int sfIdex = pointcloud.addScalarField(cc_ring_field);
778  pointcloud.setCurrentDisplayedScalarField(sfIdex);
779  pointcloud.showSF(true);
780  }
781 
782  if (header.has_intensity && cc_intensity_field) {
783  cc_intensity_field->computeMinAndMax();
784  int sfIdex = pointcloud.addScalarField(cc_intensity_field);
785  pointcloud.setCurrentDisplayedScalarField(sfIdex);
786  pointcloud.showSF(true);
787  }
788 
789  if (header.has_timestamp && cc_timestamp_field) {
790  cc_timestamp_field->computeMinAndMax();
791  int sfIdex = pointcloud.addScalarField(cc_timestamp_field);
792  pointcloud.setCurrentDisplayedScalarField(sfIdex);
793  pointcloud.showSF(true);
794  }
795 
796  reporter.Finish();
797  return true;
798 }
799 
800 bool ReadPointCloudFromPCD(const std::string& filename,
801  ccPointCloud& pointcloud) {
802  PCDHeader header;
803  FILE* file = utility::filesystem::FOpen(filename.c_str(), "rb");
804  if (file == NULL) {
805  CVLog::Warning(QString("Read PCD failed: unable to open file: %1")
806  .arg(qPrintable(filename.c_str())));
807  return false;
808  }
809  if (ReadPCDHeader(file, header) == false) {
810  CVLog::Warning(QString("Read PCD failed: unable to parse header."));
811  fclose(file);
812  return false;
813  }
814 
815  CVLog::PrintDebug(QString("PCD header indicates %1 fields, %2 bytes "
816  "per point, and %3 points in total.")
817  .arg(header.fields.size())
818  .arg(header.pointsize)
819  .arg(header.points));
820  for (const auto& field : header.fields) {
821  CVLog::PrintDebug(QString("%1, %2, %3, %4, %5")
822  .arg(field.name.c_str())
823  .arg(field.type)
824  .arg(field.size)
825  .arg(field.count)
826  .arg(field.offset));
827  }
829  QString("Compression method is %1.").arg(header.datatype));
830  CVLog::PrintDebug(QString("Points: %1; normals: %2; colors: %3")
831  .arg(header.has_points ? "yes" : "no")
832  .arg(header.has_normals ? "yes" : "no")
833  .arg(header.has_colors ? "yes" : "no"));
834  if (!ReadPCDData(file, header, pointcloud)) {
835  CVLog::Warning(QString("Read PCD failed: unable to read data."));
836  fclose(file);
837  return false;
838  }
839  fclose(file);
840  return true;
841 }
842 
843 } // namespace
844 
846  : FileIOFilter({"_Point Cloud Library Filter",
847  13.0f, // priority
848  QStringList{"pcd"}, "pcd",
849  QStringList{"Point Cloud Library cloud (*.pcd)"},
850  QStringList{"Point Cloud Library cloud (*.pcd)"},
851  Import | Export}) {}
852 
854  bool& multiple,
855  bool& exclusive) const {
856  // only one cloud per file
857  if (type == CV_TYPES::POINT_CLOUD) {
858  multiple = false;
859  exclusive = true;
860  return true;
861  }
862 
863  return false;
864 }
865 
869 }
870 
872 class ccPCDFileOutputForamtDialog : public QDialog,
873  public Ui::PCDOutputFormatDialog {
874 public:
875  explicit ccPCDFileOutputForamtDialog(QWidget* parent = nullptr)
876  : QDialog(parent, Qt::Tool), Ui::PCDOutputFormatDialog() {
877  setupUi(this);
878  }
879 };
880 
882 class SavePCDFileDialog : public QDialog, public Ui::SavePCDFileDlg {
883 public:
885  explicit SavePCDFileDialog(QWidget* parent = nullptr)
886  : QDialog(parent), Ui::SavePCDFileDlg() {
887  setupUi(this);
888  }
889 };
890 
892  const QString& filename,
893  const SaveParameters& parameters) {
894  if (!entity || filename.isEmpty()) {
895  return CC_FERR_BAD_ARGUMENT;
896  }
897 
898  // the cloud to save
899  ccPointCloud* ccCloud = ccHObjectCaster::ToPointCloud(entity);
900  if (!ccCloud) {
901  CVLog::Warning("[PCL] This filter can only save one cloud at a time!");
903  }
904 
905  QSettings settings("save pcd");
906  settings.beginGroup("SavePcd");
907  bool saveOriginOrientation =
908  settings.value("saveOriginOrientation", true).toBool();
909  bool saveBinary = settings.value("SavePCDBinary", true).toBool();
910  bool compressedMode = settings.value("Compressed", true).toBool();
911 
913  if (outputFileFormat == AUTO) {
914  if (nullptr == parameters.parentWidget) {
915  // defaulting to compressed binary
916  outputFileFormat = COMPRESSED_BINARY;
917  } else {
918  // GUI version: show a dialog to let the user choose the output
919  // format
921  static PcdFilter::PCDOutputFileFormat s_previousOutputFileFormat =
923  switch (s_previousOutputFileFormat) {
924  case COMPRESSED_BINARY:
925  dialog.compressedBinaryRadioButton->setChecked(true);
926  break;
927  case BINARY:
928  dialog.binaryRadioButton->setChecked(true);
929  break;
930  case ASCII:
931  dialog.asciiRadioButton->setChecked(true);
932  break;
933  }
934 
935  QAbstractButton* clickedButton = nullptr;
936 
937  QObject::connect(
938  dialog.buttonBox, &QDialogButtonBox::clicked,
939  [&](QAbstractButton* button) { clickedButton = button; });
940 
941  if (dialog.exec()) {
942  if (dialog.compressedBinaryRadioButton->isChecked()) {
943  outputFileFormat = COMPRESSED_BINARY;
944  } else if (dialog.binaryRadioButton->isChecked()) {
945  outputFileFormat = BINARY;
946  } else if (dialog.asciiRadioButton->isChecked()) {
947  outputFileFormat = ASCII;
948  } else {
949  assert(false);
950  }
951 
952  s_previousOutputFileFormat = outputFileFormat;
953 
954  if (clickedButton ==
955  dialog.buttonBox->button(
956  QDialogButtonBox::StandardButton::YesToAll)) {
957  // remember once and for all the output file format
958  s_outputFileFormat = outputFileFormat;
959  }
960  } else {
962  }
963  }
964 
965  saveOriginOrientation = true;
966  switch (outputFileFormat) {
967  case COMPRESSED_BINARY: {
968  saveBinary = true;
969  compressedMode = true;
970  break;
971  }
972  case BINARY: {
973  saveBinary = true;
974  compressedMode = false;
975  break;
976  }
977  case ASCII: {
978  saveBinary = false;
979  compressedMode = false;
980  break;
981  }
982  }
983 
984  } else {
985  // display pcd save dialog
986  if (nullptr == parameters.parentWidget) {
987  // defaulting to compressed binary
988  saveOriginOrientation = saveOriginOrientation;
989  saveBinary = saveBinary;
990  compressedMode = compressedMode;
991  } else {
992  SavePCDFileDialog spfDlg(parameters.parentWidget);
993  compressedMode = saveBinary && compressedMode ? true : false;
994  {
995  spfDlg.saveOriginOrientationCheckBox->setChecked(
996  saveOriginOrientation);
997  spfDlg.saveBinaryCheckBox->setChecked(saveBinary);
998  spfDlg.saveCompressedCheckBox->setChecked(compressedMode);
999 
1000  if (!spfDlg.exec()) return CC_FERR_CANCELED_BY_USER;
1001 
1002  saveOriginOrientation =
1003  spfDlg.saveOriginOrientationCheckBox->isChecked();
1004  saveBinary = spfDlg.saveBinaryCheckBox->isChecked();
1005  compressedMode = spfDlg.saveCompressedCheckBox->isChecked();
1006  }
1007  }
1008  }
1009 
1010  settings.setValue("saveOriginOrientation", saveOriginOrientation);
1011  settings.setValue("SavePCDBinary", saveBinary);
1012  settings.setValue("Compressed",
1013  saveBinary && compressedMode ? true : false);
1014  settings.endGroup();
1015 
1016  PCLCloud::Ptr pclCloud = cc2smReader(ccCloud).getAsSM();
1017  if (!pclCloud) {
1019  }
1020 
1021  if (saveOriginOrientation) {
1022  // search for a sensor as child (we take the first if there are
1023  // several of them)
1024  ccSensor* sensor(nullptr);
1025  {
1026  for (unsigned i = 0; i < ccCloud->getChildrenNumber(); ++i) {
1027  ccHObject* child = ccCloud->getChild(i);
1028 
1029  // try to cast to a ccSensor
1030  sensor = ccHObjectCaster::ToSensor(child);
1031  if (sensor) break;
1032  }
1033  }
1034 
1035  Eigen::Vector4f pos;
1036  Eigen::Quaternionf ori;
1037  if (!sensor) {
1038  // we append to the cloud null sensor informations
1039  pos = Eigen::Vector4f::Zero();
1040  ori = Eigen::Quaternionf::Identity();
1041  } else {
1042  // we get out valid sensor informations
1043  ccGLMatrix mat = sensor->getRigidTransformation();
1044  CCVector3 trans = mat.getTranslationAsVec3D();
1045  pos(0) = trans.x;
1046  pos(1) = trans.y;
1047  pos(2) = trans.z;
1048 
1049  // also the rotation
1050  Eigen::Matrix3f eigrot;
1051  for (int i = 0; i < 3; ++i)
1052  for (int j = 0; j < 3; ++j) eigrot(i, j) = mat.getColumn(j)[i];
1053 
1054  // now translate to a quaternion notation
1055  ori = Eigen::Quaternionf(eigrot);
1056  }
1057 
1058  if (ccCloud->size() == 0) {
1059  pcl::PCDWriter w;
1060  QFile file(filename);
1061  if (!file.open(QFile::WriteOnly | QFile::Truncate))
1062  return CC_FERR_WRITING;
1063  QTextStream stream(&file);
1064 
1065  if (compressedMode) {
1066  stream << QString(w.generateHeaderBinaryCompressed(*pclCloud,
1067  pos, ori)
1068  .c_str())
1069  << "DATA binary\n";
1070  } else {
1071  stream << QString(w.generateHeaderBinary(*pclCloud, pos, ori)
1072  .c_str())
1073  << "DATA binary\n";
1074  }
1075  return CC_FERR_NO_ERROR;
1076  }
1077 
1078  if (compressedMode) {
1079  pcl::PCDWriter w;
1080  if (w.writeBinaryCompressed(
1081  /*qPrintable*/ CVTools::FromQString(filename),
1082  *pclCloud, pos, ori) < 0) {
1084  }
1085  } else {
1086  if (pcl::io::savePCDFile(
1087  /*qPrintable*/ CVTools::FromQString(filename),
1088  *pclCloud, pos, ori,
1089  saveBinary) < 0) // DGM: warning, toStdString doesn't
1090  // preserve "local" characters
1091  {
1093  }
1094  }
1095  } else {
1096  if (ccCloud->size() == 0) {
1097  pcl::PCDWriter w;
1098  QFile file(filename);
1099  if (!file.open(QFile::WriteOnly | QFile::Truncate))
1100  return CC_FERR_WRITING;
1101  QTextStream stream(&file);
1102 
1103  Eigen::Vector4f pos;
1104  Eigen::Quaternionf ori;
1105 
1106  if (compressedMode) {
1107  stream << QString(w.generateHeaderBinaryCompressed(*pclCloud,
1108  pos, ori)
1109  .c_str())
1110  << "DATA binary\n";
1111  } else {
1112  stream << QString(w.generateHeaderBinary(*pclCloud, pos, ori)
1113  .c_str())
1114  << "DATA binary\n";
1115  }
1116  return CC_FERR_NO_ERROR;
1117  }
1118 
1119  bool hasColor = ccCloud->hasColors();
1120  bool hasNormals = ccCloud->hasNormals();
1121  if (hasColor && !hasNormals) {
1122  PointCloudRGB::Ptr rgbCloud(new PointCloudRGB);
1123  FROM_PCL_CLOUD(*pclCloud, *rgbCloud);
1124  if (!rgbCloud) {
1126  }
1127  if (compressedMode) {
1128  if (pcl::io::savePCDFileBinaryCompressed(
1129  CVTools::FromQString(filename), *rgbCloud) <
1130  0) // DGM: warning, toStdString doesn't preserve
1131  // "local" characters
1132  {
1134  }
1135  } else {
1136  if (pcl::io::savePCDFile(CVTools::FromQString(filename),
1137  *rgbCloud, saveBinary) <
1138  0) // DGM: warning, toStdString doesn't preserve
1139  // "local" characters
1140  {
1142  }
1143  }
1144  } else if (!hasColor && hasNormals) {
1145  PointCloudNormal::Ptr normalCloud(new PointCloudNormal);
1146  FROM_PCL_CLOUD(*pclCloud, *normalCloud);
1147  if (!normalCloud) {
1149  }
1150  if (compressedMode) {
1151  if (pcl::io::savePCDFileBinaryCompressed(
1152  CVTools::FromQString(filename), *normalCloud) <
1153  0) // DGM: warning, toStdString doesn't preserve
1154  // "local" characters
1155  {
1157  }
1158  } else {
1159  if (pcl::io::savePCDFile(CVTools::FromQString(filename),
1160  *normalCloud, saveBinary) <
1161  0) // DGM: warning, toStdString doesn't preserve
1162  // "local" characters
1163  {
1165  }
1166  }
1167  } else if (hasColor && hasNormals) {
1168  PointCloudRGBNormal::Ptr rgbNormalCloud(new PointCloudRGBNormal);
1169  FROM_PCL_CLOUD(*pclCloud, *rgbNormalCloud);
1170  if (!rgbNormalCloud) {
1172  }
1173  if (compressedMode) {
1174  if (pcl::io::savePCDFileBinaryCompressed(
1176  *rgbNormalCloud) <
1177  0) // DGM: warning, toStdString doesn't preserve
1178  // "local" characters
1179  {
1181  }
1182  } else {
1183  if (pcl::io::savePCDFile(CVTools::FromQString(filename),
1184  *rgbNormalCloud, saveBinary) <
1185  0) // DGM: warning, toStdString doesn't preserve
1186  // "local" characters
1187  {
1189  }
1190  }
1191  } else // just save xyz coordinates
1192  {
1193  PointCloudT::Ptr xyzCloud(new PointCloudT);
1194  FROM_PCL_CLOUD(*pclCloud, *xyzCloud);
1195  if (!xyzCloud) {
1197  }
1198  if (compressedMode) {
1199  if (pcl::io::savePCDFileBinaryCompressed(
1200  CVTools::FromQString(filename), *xyzCloud) <
1201  0) // DGM: warning, toStdString doesn't preserve
1202  // "local" characters
1203  {
1205  }
1206  } else {
1207  if (pcl::io::savePCDFile(CVTools::FromQString(filename),
1208  *xyzCloud, saveBinary) <
1209  0) // DGM: warning, toStdString doesn't preserve
1210  // "local" characters
1211  {
1213  }
1214  }
1215  }
1216  }
1217 
1218  return CC_FERR_NO_ERROR;
1219 }
1220 
1222  ccHObject& container,
1223  LoadParameters& parameters) {
1224  Eigen::Vector4f origin;
1225  Eigen::Quaternionf orientation;
1226  int pcd_version;
1227  int data_type;
1228  unsigned int data_idx;
1229  size_t pointCount = -1;
1230  PCLCloud::Ptr inputCloud(new PCLCloud);
1231  // Load the given file
1232  pcl::PCDReader p;
1233 
1234  const std::string& fileName = CVTools::FromQString(filename);
1235 
1236  if (p.readHeader(fileName, *inputCloud, origin, orientation, pcd_version,
1237  data_type, data_idx) < 0) {
1238  CVLog::Warning(QString("[PCL] An error occurred while reading PCD "
1239  "header and try to "
1240  "mannually read %1")
1241  .arg(qPrintable(filename)));
1242  ccPointCloud* ccCloud = new ccPointCloud("pointCloud");
1243  if (ReadPointCloudFromPCD(fileName, *ccCloud)) {
1244  container.addChild(ccCloud);
1245  return CC_FERR_NO_ERROR;
1246  } else {
1247  CVLog::Warning(QString("[PCL] Failed to "
1248  "mannually read %1")
1249  .arg(qPrintable(filename)));
1250  }
1252  }
1253 
1254  pointCount = inputCloud->width * inputCloud->height;
1255  CVLog::Print(QString("%1: Point Count: %2")
1256  .arg(qPrintable(filename))
1257  .arg(pointCount));
1258 
1259  if (pointCount == 0) {
1260  return CC_FERR_NO_LOAD;
1261  }
1262 
1263  // DGM: warning, toStdString doesn't preserve "local" characters
1264  if (pcl::io::loadPCDFile(fileName, *inputCloud, origin, orientation) < 0) {
1265  CVLog::Warning(QString("[PCL] An error occurred while "
1266  "pcl::io::loadPCDFile and try to "
1267  "mannually read %1")
1268  .arg(qPrintable(filename)));
1269  ccPointCloud* ccCloud = new ccPointCloud("pointCloud");
1270  if (ReadPointCloudFromPCD(fileName, *ccCloud)) {
1271  container.addChild(ccCloud);
1272  return CC_FERR_NO_ERROR;
1273  } else {
1274  CVLog::Warning(QString("[PCL] Failed to "
1275  "mannually read %1")
1276  .arg(qPrintable(filename)));
1277  }
1279  }
1280 
1281  // data may contain NaNs --> remove them
1282  if (!inputCloud->is_dense) {
1283  // now we need to remove NaNs
1284  pcl::PassThrough<PCLCloud> passFilter;
1285  passFilter.setInputCloud(inputCloud);
1286  passFilter.filter(*inputCloud);
1287  }
1288  ccPointCloud* ccCloud = pcl2cc::Convert(*inputCloud);
1289 
1290  // convert to CC cloud
1291  if (!ccCloud) {
1293  "[PCL] An error occurred while converting PCD cloud to "
1294  "CloudViewer cloud!");
1295  return CC_FERR_CONSOLE_ERROR;
1296  }
1297  ccCloud->setName(QStringLiteral("unnamed"));
1298 
1299  // now we construct a ccGBLSensor
1300  {
1301  // get orientation as rot matrix and copy it into a ccGLMatrix
1302  ccGLMatrix ccRot;
1303  {
1304  Eigen::Matrix3f eigrot = orientation.toRotationMatrix();
1305  float* X = ccRot.getColumn(0);
1306  float* Y = ccRot.getColumn(1);
1307  float* Z = ccRot.getColumn(2);
1308 
1309  X[0] = eigrot(0, 0);
1310  X[1] = eigrot(1, 0);
1311  X[2] = eigrot(2, 0);
1312  Y[0] = eigrot(0, 1);
1313  Y[1] = eigrot(1, 1);
1314  Y[2] = eigrot(2, 1);
1315  Z[0] = eigrot(0, 2);
1316  Z[1] = eigrot(1, 2);
1317  Z[2] = eigrot(2, 2);
1318 
1319  ccRot.getColumn(3)[3] = 1.0f;
1320  ccRot.setTranslation(origin.data());
1321  }
1322 
1323  ccGBLSensor* sensor = new ccGBLSensor;
1324  sensor->setRigidTransformation(ccRot);
1325  sensor->setYawStep(static_cast<PointCoordinateType>(0.05));
1326  sensor->setPitchStep(static_cast<PointCoordinateType>(0.05));
1327  sensor->setVisible(true);
1328  // uncertainty to some default
1329  sensor->setUncertainty(static_cast<PointCoordinateType>(0.01));
1330  // graphic scale
1331  sensor->setGraphicScale(ccCloud->getOwnBB().getDiagNorm() / 10);
1332 
1333  // Compute parameters
1335  sensor->computeAutoParameters(pc);
1336 
1337  sensor->setEnabled(false);
1338 
1339  ccCloud->addChild(sensor);
1340  }
1341 
1342  container.addChild(ccCloud);
1343 
1344  return CC_FERR_NO_ERROR;
1345 }
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
Definition: CVTypes.h:97
std::string filename
filament::Texture::InternalFormat format
int width
int size
PCDDataType datatype
bool has_ring
bool has_colors
bool has_intensity
std::string version
int pointsize
int elementnum
std::vector< PCLPointField > fields
std::string name
std::string viewpoint
bool has_normals
int height
int count
int count_offset
int offset
int points
bool has_points
char type
CC_FILE_ERROR
Typical I/O filter errors.
Definition: FileIOFilter.h:20
@ CC_FERR_CONSOLE_ERROR
Definition: FileIOFilter.h:33
@ CC_FERR_CANCELED_BY_USER
Definition: FileIOFilter.h:30
@ CC_FERR_THIRD_PARTY_LIB_FAILURE
Definition: FileIOFilter.h:36
@ CC_FERR_NO_LOAD
Definition: FileIOFilter.h:28
@ CC_FERR_WRITING
Definition: FileIOFilter.h:25
@ CC_FERR_BAD_ARGUMENT
Definition: FileIOFilter.h:22
@ CC_FERR_NO_ERROR
Definition: FileIOFilter.h:21
@ CC_FERR_BAD_ENTITY_TYPE
Definition: FileIOFilter.h:29
math::float4 color
static PcdFilter::PCDOutputFileFormat s_outputFileFormat
Definition: PcdFilter.cpp:866
void * X
Definition: SmallVector.cpp:45
#define NULL
virtual void release()
Decrease counter and deletes object when 0.
Definition: CVShareable.cpp:35
static bool PrintDebug(const char *format,...)
Same as Print, but works only in Debug mode.
Definition: CVLog.cpp:153
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
static std::string FromQString(const QString &qs)
Definition: CVTools.cpp:100
Generic file I/O filter.
Definition: FileIOFilter.h:46
PCDOutputFileFormat
Output file format.
Definition: PcdFilter.h:31
@ COMPRESSED_BINARY
Definition: PcdFilter.h:32
virtual CC_FILE_ERROR saveToFile(ccHObject *entity, const QString &filename, const SaveParameters &parameters)
Saves an entity (or a group of) to a file.
Definition: PcdFilter.cpp:891
virtual CC_FILE_ERROR loadFile(const QString &filename, ccHObject &container, LoadParameters &parameters)
Loads one or more entities from a file.
Definition: PcdFilter.cpp:1221
virtual bool canSave(CV_CLASS_ENUM type, bool &multiple, bool &exclusive) const
Returns whether this I/O filter can save the specified type of entity.
Definition: PcdFilter.cpp:853
static void SetOutputFileFormat(PCDOutputFileFormat format)
Set the output file format.
Definition: PcdFilter.cpp:867
PCD File Save dialog.
Definition: PcdFilter.cpp:882
SavePCDFileDialog(QWidget *parent=nullptr)
Default constructor.
Definition: PcdFilter.cpp:885
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
virtual void setVisible(bool state)
Sets entity visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
Ground-based Laser sensor.
Definition: ecvGBLSensor.h:26
void setUncertainty(PointCoordinateType u)
Sets the Z-buffer uncertainty on depth values.
Definition: ecvGBLSensor.h:153
bool computeAutoParameters(cloudViewer::GenericCloud *theCloud)
Computes angular parameters automatically (all but the angular steps!)
void setYawStep(PointCoordinateType dTheta)
Sets the yaw step.
void setPitchStep(PointCoordinateType dPhi)
Sets the pitch step.
Vector3Tpl< T > getTranslationAsVec3D() const
Returns a copy of the translation as a CCVector3.
void setTranslation(const Vector3Tpl< float > &Tr)
Sets translation (float version)
T * getColumn(unsigned index)
Returns a pointer to a given column.
Float version of ccGLMatrixTpl.
Definition: ecvGLMatrix.h:19
A 3D cloud interface with associated features (color, normals, octree, etc.)
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
static ccGenericPointCloud * ToGenericPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccGenericPointCloud.
static ccSensor * ToSensor(ccHObject *obj)
Converts current object to ccSensor (if possible)
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
unsigned getChildrenNumber() const
Returns the number of children.
Definition: ecvHObject.h:312
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
Definition: ecvHObject.h:325
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
virtual void setEnabled(bool state)
Sets the "enabled" property.
Definition: ecvObject.h:102
Dialog for the PCV plugin.
Definition: PcdFilter.cpp:873
ccPCDFileOutputForamtDialog(QWidget *parent=nullptr)
Definition: PcdFilter.cpp:875
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
void addNorms(const std::vector< CCVector3 > &Ns)
void addNorm(const CCVector3 &N)
Pushes a normal vector on stack (shortcut)
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
bool hasNormals() const override
Returns whether normals are enabled or not.
bool resizeTheRGBTable(bool fillWithWhite=false)
Resizes the RGB colors array.
bool reserveTheNormsTable()
Reserves memory to store the compressed normals.
void clear() override
Clears the entity from all its points and features.
bool hasColors() const override
Returns whether colors are enabled or not.
bool resize(unsigned numberOfPoints) override
Resizes all the active features arrays.
void deleteScalarField(int index) override
Deletes a specific scalar field.
void setPointColor(size_t pointIndex, const ecvColor::Rgb &col)
Sets a particular point color.
A scalar field associated to display-related parameters.
void computeMinAndMax() override
Determines the min and max values.
Generic sensor interface.
Definition: ecvSensor.h:27
virtual ccGLMatrix & getRigidTransformation()
Definition: ecvSensor.h:105
virtual void setRigidTransformation(const ccGLMatrix &mat)
Definition: ecvSensor.h:99
void setGraphicScale(PointCoordinateType scale)
Sets the sensor graphic representation scale.
Definition: ecvSensor.h:125
T getDiagNorm() const
Returns diagonal length.
Definition: BoundingBox.h:172
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
CCVector3 * getPointPtr(size_t index)
unsigned size() const override
Definition: PointCloudTpl.h:38
void setPoint(size_t index, const CCVector3 &P)
void addElement(ScalarType value)
Definition: ScalarField.h:99
bool reserveSafe(std::size_t count)
Reserves memory (no exception thrown)
Definition: ScalarField.cpp:71
RGB color structure.
Definition: ecvColorTypes.h:49
double normals[3]
#define DEFAULT_IO_BUFFER_SIZE
Definition: Logging.h:31
Helper functions for the ml ops.
@ POINT_CLOUD
Definition: CVTypes.h:104
bool ReadPointCloudFromPCD(const std::string &filename, ccPointCloud &pointcloud, const ReadPointCloudOption &params)
static bool ReadPCDData(FILE *file, PCDHeader &header, t::geometry::PointCloud &pointcloud, const ReadPointCloudOption &params)
Definition: FilePCD.cpp:457
static bool ReadPCDHeader(FILE *file, PCDHeader &header)
Definition: FilePCD.cpp:197
static void UnpackASCIIPCDElement(scalar_t &data, const char *data_ptr)=delete
FILE * FOpen(const std::string &filename, const std::string &mode)
Definition: FileSystem.cpp:609
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.
RgbTpl< ColorCompType > Rgb
3 components, default type
Generic loading parameters.
Definition: FileIOFilter.h:51
Generic saving parameters.
Definition: FileIOFilter.h:84
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:93