Point Cloud Library (PCL)  1.15.1-dev
io.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2011, Willow Garage, Inc.
6  * Copyright (c) 2012-, Open Perception, Inc.
7  *
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * * Redistributions of source code must retain the above copyright
15  * notice, this list of conditions and the following disclaimer.
16  * * Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  * * Neither the name of the copyright holder(s) nor the names of its
21  * contributors may be used to endorse or promote products derived
22  * from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  *
37  * $Id$
38  *
39  */
40 
41 #pragma once
42 
43 #include <pcl/conversions.h> // for FieldAdder
44 #include <pcl/common/concatenate.h>
45 #include <pcl/common/copy_point.h>
46 #include <pcl/common/io.h>
47 
48 namespace pcl
49 {
50 
51 template <typename PointT> int
53  const std::string &field_name,
54  std::vector<pcl::PCLPointField> &fields)
55 {
56  return getFieldIndex<PointT>(field_name, fields);
57 }
58 
59 
60 template <typename PointT> int
61 getFieldIndex (const std::string &field_name,
62  std::vector<pcl::PCLPointField> &fields)
63 {
64  fields = getFields<PointT> ();
65  const auto& ref = fields;
66  return pcl::getFieldIndex<PointT> (field_name, ref);
67 }
68 
69 
70 template <typename PointT> int
71 getFieldIndex (const std::string &field_name,
72  const std::vector<pcl::PCLPointField> &fields)
73 {
74  const auto result = std::find_if(fields.begin (), fields.end (),
75  [&field_name](const auto& field) { return field.name == field_name; });
76  if (result == fields.end ())
77  return -1;
78  return std::distance(fields.begin (), result);
79 }
80 
81 
82 template <typename PointT> void
83 getFields (const pcl::PointCloud<PointT> &, std::vector<pcl::PCLPointField> &fields)
84 {
85  fields = getFields<PointT> ();
86 }
87 
88 
89 template <typename PointT> void
90 getFields (std::vector<pcl::PCLPointField> &fields)
91 {
92  fields = getFields<PointT> ();
93 }
94 
95 
96 template <typename PointT> std::vector<pcl::PCLPointField>
98 {
99  std::vector<pcl::PCLPointField> fields;
100  // Get the fields list
101  pcl::for_each_type<typename pcl::traits::fieldList<PointT>::type>(pcl::detail::FieldAdder<PointT>(fields));
102  return fields;
103 }
104 
105 template <typename CloudT> inline std::vector<pcl::PCLPointField>
106 getFields (const CloudT& /*cloud*/)
107 {
108  return pcl::getFields<typename CloudT::PointType>();
109 }
110 
111 // Template specialization for PCLPointCloud2
112 template <> inline std::vector<pcl::PCLPointField>
113 getFields<pcl::PCLPointCloud2> (const pcl::PCLPointCloud2& cloud) {
114  return cloud.fields;
115 }
116 
117 
118 template <typename PointT> std::string
120 {
121  // Get the fields list
122  const auto fields = getFields<PointT>();
123  std::string result;
124  for (std::size_t i = 0; i < fields.size () - 1; ++i)
125  result += fields[i].name + " ";
126  result += fields[fields.size () - 1].name;
127  return (result);
128 }
129 
130 /**
131  * \brief reinterpret a pointer as a type, dereference it, and return result as target
132  * type
133  *
134  * \tparam DType Pointer type of the data
135  * \tparam RType Return type which the dereferenced result is cast to
136  *
137  * \return value
138  */
139 template <typename DType, typename RType> RType reinterpret_and_cast (const std::uint8_t* p)
140 {
141  return static_cast<RType>(*reinterpret_cast<const DType*>(p));
142 }
143 
144 template <typename T> T point_field_as (const std::uint8_t* data, const std::uint8_t type)
145 {
146  switch (type) {
147  case pcl::PCLPointField::PointFieldTypes::FLOAT32:
148  return reinterpret_and_cast<float, T>(data);
149  break;
150  case pcl::PCLPointField::PointFieldTypes::UINT8:
151  return reinterpret_and_cast<std::uint8_t, T>(data);
152  break;
153  case pcl::PCLPointField::PointFieldTypes::UINT16:
154  return reinterpret_and_cast<std::uint16_t, T>(data);
155  break;
156  case pcl::PCLPointField::PointFieldTypes::UINT32:
157  return reinterpret_and_cast<std::uint32_t, T>(data);
158  break;
159  case pcl::PCLPointField::PointFieldTypes::UINT64:
160  return reinterpret_and_cast<std::uint64_t, T>(data);
161  break;
162  case pcl::PCLPointField::PointFieldTypes::BOOL:
163  return reinterpret_and_cast<bool, T>(data);
164  break;
165  case pcl::PCLPointField::PointFieldTypes::FLOAT64:
166  return reinterpret_and_cast<double, T>(data);
167  break;
168  case pcl::PCLPointField::PointFieldTypes::INT16:
169  return reinterpret_and_cast<std::int16_t, T>(data);
170  break;
171  case pcl::PCLPointField::PointFieldTypes::INT32:
172  return reinterpret_and_cast<std::int32_t, T>(data);
173  break;
174  case pcl::PCLPointField::PointFieldTypes::INT64:
175  return reinterpret_and_cast<std::int64_t, T>(data);
176  break;
177  default:
178  return 0;
179  break;
180  }
181 }
182 
183 
184 namespace detail
185 {
186 
187  template <typename PointInT, typename PointOutT> void
189  pcl::PointCloud<PointOutT> &cloud_out)
190  {
191  // Iterate over each point, if the point types of two clouds are different
192  for (std::size_t i = 0; i < cloud_in.size (); ++i)
193  copyPoint (cloud_in[i], cloud_out[i]);
194  }
195 
196 
197  template <typename PointT> void
199  pcl::PointCloud<PointT> &cloud_out)
200  {
201  // Use std::copy directly, if the point types of two clouds are same
202  std::copy (cloud_in.data(), cloud_in.data() + cloud_in.size (), cloud_out.data());
203  }
204 
205 } // namespace detail
206 
207 template <typename PointInT, typename PointOutT> void
209  pcl::PointCloud<PointOutT> &cloud_out)
210 {
211  // Allocate enough space and copy the basics
212  cloud_out.header = cloud_in.header;
213  cloud_out.width = cloud_in.width;
214  cloud_out.height = cloud_in.height;
215  cloud_out.is_dense = cloud_in.is_dense;
216  cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
217  cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
218  cloud_out.resize (cloud_in.size ());
219 
220  if (!cloud_in.empty ())
221  detail::copyPointCloudMemcpy (cloud_in, cloud_out);
222 }
223 
224 
225 template <typename PointT, typename IndicesVectorAllocator> void
228  pcl::PointCloud<PointT> &cloud_out)
229 {
230  // Do we want to copy everything?
231  if (indices.size () == cloud_in.size ())
232  {
233  cloud_out = cloud_in;
234  return;
235  }
236 
237  // Allocate enough space and copy the basics
238  cloud_out.clear ();
239  cloud_out.reserve (indices.size ());
240  cloud_out.header = cloud_in.header;
241  cloud_out.width = indices.size ();
242  cloud_out.height = 1;
243  cloud_out.is_dense = cloud_in.is_dense;
244  cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
245  cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
246 
247  // Iterate over each point
248  for (const auto& index : indices)
249  cloud_out.transient_push_back (cloud_in[index]);
250 }
251 
252 
253 template <typename PointInT, typename PointOutT, typename IndicesVectorAllocator> void
256  pcl::PointCloud<PointOutT> &cloud_out)
257 {
258  // Allocate enough space and copy the basics
259  cloud_out.resize (indices.size ());
260  cloud_out.header = cloud_in.header;
261  cloud_out.width = indices.size ();
262  cloud_out.height = 1;
263  cloud_out.is_dense = cloud_in.is_dense;
264  cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
265  cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
266 
267  // Iterate over each point
268  for (std::size_t i = 0; i < indices.size (); ++i)
269  copyPoint (cloud_in[indices[i]], cloud_out[i]);
270 }
271 
272 
273 template <typename PointT> void
275  const pcl::PointIndices &indices,
276  pcl::PointCloud<PointT> &cloud_out)
277 {
278  copyPointCloud (cloud_in, indices.indices, cloud_out);
279 }
280 
281 
282 template <typename PointInT, typename PointOutT> void
284  const pcl::PointIndices &indices,
285  pcl::PointCloud<PointOutT> &cloud_out)
286 {
287  copyPointCloud (cloud_in, indices.indices, cloud_out);
288 }
289 
290 
291 template <typename PointT> void
293  const std::vector<pcl::PointIndices> &indices,
294  pcl::PointCloud<PointT> &cloud_out)
295 {
296  std::size_t nr_p = 0;
297  for (const auto &index : indices)
298  nr_p += index.indices.size ();
299 
300  // Do we want to copy everything? Remember we assume UNIQUE indices
301  if (nr_p == cloud_in.size ())
302  {
303  cloud_out = cloud_in;
304  return;
305  }
306 
307  // Allocate enough space and copy the basics
308  cloud_out.clear ();
309  cloud_out.reserve (nr_p);
310  cloud_out.header = cloud_in.header;
311  cloud_out.width = nr_p;
312  cloud_out.height = 1;
313  cloud_out.is_dense = cloud_in.is_dense;
314  cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
315  cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
316 
317  // Iterate over each cluster
318  for (const auto &cluster_index : indices)
319  {
320  // Iterate over each idx
321  for (const auto &index : cluster_index.indices)
322  {
323  // Iterate over each dimension
324  cloud_out.transient_push_back (cloud_in[index]);
325  }
326  }
327 }
328 
329 
330 template <typename PointInT, typename PointOutT> void
332  const std::vector<pcl::PointIndices> &indices,
333  pcl::PointCloud<PointOutT> &cloud_out)
334 {
335  const auto nr_p = std::accumulate(indices.begin (), indices.end (), 0,
336  [](const auto& acc, const auto& index) { return index.indices.size() + acc; });
337 
338  // Do we want to copy everything? Remember we assume UNIQUE indices
339  if (nr_p == cloud_in.size ())
340  {
341  copyPointCloud (cloud_in, cloud_out);
342  return;
343  }
344 
345  // Allocate enough space and copy the basics
346  cloud_out.resize (nr_p);
347  cloud_out.header = cloud_in.header;
348  cloud_out.width = nr_p;
349  cloud_out.height = 1;
350  cloud_out.is_dense = cloud_in.is_dense;
351  cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
352  cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
353 
354  // Iterate over each cluster
355  std::size_t cp = 0;
356  for (const auto &cluster_index : indices)
357  {
358  // Iterate over each idx
359  for (const auto &index : cluster_index.indices)
360  {
361  copyPoint (cloud_in[index], cloud_out[cp]);
362  ++cp;
363  }
364  }
365 }
366 
367 
368 template <typename PointIn1T, typename PointIn2T, typename PointOutT> void
370  const pcl::PointCloud<PointIn2T> &cloud2_in,
371  pcl::PointCloud<PointOutT> &cloud_out)
372 {
373  using FieldList1 = typename pcl::traits::fieldList<PointIn1T>::type;
374  using FieldList2 = typename pcl::traits::fieldList<PointIn2T>::type;
375 
376  if (cloud1_in.size () != cloud2_in.size ())
377  {
378  PCL_ERROR ("[pcl::concatenateFields] The number of points in the two input datasets differs!\n");
379  return;
380  }
381 
382  // Resize the output dataset
383  cloud_out.resize (cloud1_in.size ());
384  cloud_out.header = cloud1_in.header;
385  cloud_out.width = cloud1_in.width;
386  cloud_out.height = cloud1_in.height;
387  if (!cloud1_in.is_dense || !cloud2_in.is_dense)
388  cloud_out.is_dense = false;
389  else
390  cloud_out.is_dense = true;
391 
392  // Iterate over each point
393  for (std::size_t i = 0; i < cloud_out.size (); ++i)
394  {
395  // Iterate over each dimension
396  pcl::for_each_type <FieldList1> (pcl::NdConcatenateFunctor <PointIn1T, PointOutT> (cloud1_in[i], cloud_out[i]));
397  pcl::for_each_type <FieldList2> (pcl::NdConcatenateFunctor <PointIn2T, PointOutT> (cloud2_in[i], cloud_out[i]));
398  }
399 }
400 
401 
402 template <typename PointT> void
404  int top, int bottom, int left, int right, pcl::InterpolationType border_type, const PointT& value)
405 {
406  if (top < 0 || left < 0 || bottom < 0 || right < 0)
407  {
408  std::string faulty = (top < 0) ? "top" : (left < 0) ? "left" : (bottom < 0) ? "bottom" : "right";
409  PCL_THROW_EXCEPTION (pcl::BadArgumentException, "[pcl::copyPointCloud] error: " << faulty << " must be positive!");
410  return;
411  }
412 
413  if (top == 0 && left == 0 && bottom == 0 && right == 0)
414  cloud_out = cloud_in;
415  else
416  {
417  // Allocate enough space and copy the basics
418  cloud_out.header = cloud_in.header;
419  cloud_out.width = cloud_in.width + left + right;
420  cloud_out.height = cloud_in.height + top + bottom;
421  if (cloud_out.size () != cloud_out.width * cloud_out.height)
422  cloud_out.resize (cloud_out.width * cloud_out.height);
423  cloud_out.is_dense = cloud_in.is_dense;
424  cloud_out.sensor_orientation_ = cloud_in.sensor_orientation_;
425  cloud_out.sensor_origin_ = cloud_in.sensor_origin_;
426 
427  if (border_type == pcl::BORDER_TRANSPARENT)
428  {
429  const PointT* in = cloud_in.data();
430  PointT* out = cloud_out.data();
431  PointT* out_inner = out + cloud_out.width*top + left;
432  for (std::uint32_t i = 0; i < cloud_in.height; i++, out_inner += cloud_out.width, in += cloud_in.width)
433  {
434  if (out_inner != in) {
435  std::copy(in, in + cloud_in.width, out_inner);
436  }
437  }
438  }
439  else
440  {
441  // Copy the data
442  if (border_type != pcl::BORDER_CONSTANT)
443  {
444  try
445  {
446  std::vector<int> padding (cloud_out.width - cloud_in.width);
447  int right = cloud_out.width - cloud_in.width - left;
448  int bottom = cloud_out.height - cloud_in.height - top;
449 
450  for (int i = 0; i < left; i++)
451  padding[i] = pcl::interpolatePointIndex (i-left, cloud_in.width, border_type);
452 
453  for (int i = 0; i < right; i++)
454  padding[i+left] = pcl::interpolatePointIndex (cloud_in.width+i, cloud_in.width, border_type);
455 
456  const PointT* in = cloud_in.data();
457  PointT* out = cloud_out.data();
458  PointT* out_inner = out + cloud_out.width*top + left;
459 
460  for (std::uint32_t i = 0; i < cloud_in.height; i++, out_inner += cloud_out.width, in += cloud_in.width)
461  {
462  if (out_inner != in) {
463  std::copy(in, in + cloud_in.width, out_inner);
464  }
465 
466  for (int j = 0; j < left; j++)
467  out_inner[j - left] = in[padding[j]];
468 
469  for (int j = 0; j < right; j++)
470  out_inner[j + cloud_in.width] = in[padding[j + left]];
471  }
472 
473  for (int i = 0; i < top; i++)
474  {
475  int j = pcl::interpolatePointIndex (i - top, cloud_in.height, border_type);
476  std::copy(out + (j+top) * cloud_out.width, out + (j+top) * cloud_out.width + cloud_out.width,
477  out + i*cloud_out.width);
478  }
479 
480  for (int i = 0; i < bottom; i++)
481  {
482  int j = pcl::interpolatePointIndex (i + cloud_in.height, cloud_in.height, border_type);
483  std::copy(out + (j+top)*cloud_out.width, out + (j+top)*cloud_out.width + cloud_out.width,
484  out + (i + cloud_in.height + top)*cloud_out.width);
485  }
486  }
488  {
489  PCL_ERROR ("[pcl::copyPointCloud] Unhandled interpolation type %d!\n", border_type);
490  }
491  }
492  else
493  {
494  int right = cloud_out.width - cloud_in.width - left;
495  int bottom = cloud_out.height - cloud_in.height - top;
496  std::vector<PointT> buff (cloud_out.width, value);
497  PointT* buff_ptr = buff.data();
498  const PointT* in = cloud_in.data();
499  PointT* out = cloud_out.data();
500  PointT* out_inner = out + cloud_out.width*top + left;
501 
502  for (std::uint32_t i = 0; i < cloud_in.height; i++, out_inner += cloud_out.width, in += cloud_in.width)
503  {
504  if (out_inner != in) {
505  std::copy(in, in + cloud_in.width, out_inner);
506  }
507 
508  std::copy(buff_ptr, buff_ptr + left, out_inner - left);
509  std::copy(buff_ptr, buff_ptr + right, out_inner + cloud_in.width);
510  }
511 
512  for (int i = 0; i < top; i++)
513  {
514  std::copy(buff_ptr, buff_ptr + cloud_out.width, out + i*cloud_out.width);
515  }
516 
517  for (int i = 0; i < bottom; i++)
518  {
519  std::copy(buff_ptr, buff_ptr + cloud_out.width,
520  out + (i + cloud_in.height + top)*cloud_out.width);
521  }
522  }
523  }
524  }
525 }
526 
527 } // namespace pcl
An exception that is thrown when the arguments number or type is wrong/unhandled.
Definition: exceptions.h:259
PointCloud represents the base class in PCL for storing collections of 3D points.
Definition: point_cloud.h:174
PointT * data() noexcept
Definition: point_cloud.h:448
bool empty() const
Definition: point_cloud.h:447
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
Definition: point_cloud.h:404
void resize(std::size_t count)
Resizes the container to contain count elements.
Definition: point_cloud.h:463
Eigen::Quaternionf sensor_orientation_
Sensor acquisition pose (rotation).
Definition: point_cloud.h:409
void transient_push_back(const PointT &pt)
Insert a new point in the cloud, at the end of the container.
Definition: point_cloud.h:676
std::uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:399
pcl::PCLHeader header
The point cloud header.
Definition: point_cloud.h:393
std::uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:401
void clear()
Removes all points in a cloud and sets the width and height to 0.
Definition: point_cloud.h:886
std::size_t size() const
Definition: point_cloud.h:444
Eigen::Vector4f sensor_origin_
Sensor acquisition pose (origin/translation).
Definition: point_cloud.h:407
void reserve(std::size_t n)
Definition: point_cloud.h:446
T point_field_as(const std::uint8_t *data, const std::uint8_t type)
Get the value of a point field from raw data pointer and field type.
Definition: io.hpp:144
std::string getFieldsList(const pcl::PointCloud< PointT > &)
Get the list of all fields available in a given cloud.
Definition: io.hpp:119
void copyPoint(const PointInT &point_in, PointOutT &point_out)
Copy the fields of a source point into a target point.
Definition: copy_point.hpp:137
void concatenateFields(const pcl::PointCloud< PointIn1T > &cloud1_in, const pcl::PointCloud< PointIn2T > &cloud2_in, pcl::PointCloud< PointOutT > &cloud_out)
Concatenate two datasets representing different fields.
Definition: io.hpp:369
void copyPointCloud(const pcl::PointCloud< PointInT > &cloud_in, pcl::PointCloud< PointOutT > &cloud_out)
Copy all the fields from a given point cloud into a new point cloud.
Definition: io.hpp:208
void copyPointCloudMemcpy(const pcl::PointCloud< PointInT > &cloud_in, pcl::PointCloud< PointOutT > &cloud_out)
Definition: io.hpp:188
float distance(const PointT &p1, const PointT &p2)
Definition: geometry.h:60
int getFieldIndex(const pcl::PointCloud< PointT > &, const std::string &field_name, std::vector< pcl::PCLPointField > &fields)
Definition: io.hpp:52
InterpolationType
Definition: io.h:278
@ BORDER_TRANSPARENT
Definition: io.h:281
@ BORDER_CONSTANT
Definition: io.h:279
PCL_EXPORTS int interpolatePointIndex(int p, int length, InterpolationType type)
std::vector< index_t, Allocator > IndicesAllocator
Type used for indices in PCL.
Definition: types.h:128
RType reinterpret_and_cast(const std::uint8_t *p)
reinterpret a pointer as a type, dereference it, and return result as target type
Definition: io.hpp:139
void getFields(const pcl::PointCloud< PointT > &, std::vector< pcl::PCLPointField > &fields)
Definition: io.hpp:83
Helper functor structure for concatenate.
Definition: concatenate.h:50
std::vector<::pcl::PCLPointField > fields
A point structure representing Euclidean xyz coordinates, and the RGB color.