Point Cloud Library (PCL) 1.15.1-dev
Loading...
Searching...
No Matches
point_cloud_color_handlers.hpp
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Point Cloud Library (PCL) - www.pointclouds.org
5 * Copyright (c) 2012-, Open Perception, Inc.
6 *
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 *
13 * * Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer in the documentation and/or other materials provided
18 * with the distribution.
19 * * Neither the name of the copyright holder(s) nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 *
36 */
37
38#pragma once
39
40#include <set>
41#include <map>
42#include <stdexcept>
43
44#include <pcl/pcl_macros.h>
45#include <pcl/common/colors.h>
46#include <pcl/common/io.h> // for getFieldIndex
47#include <pcl/common/point_tests.h> // for pcl::isFinite
48
49
50namespace pcl
51{
52
53namespace visualization
54{
55
56template <typename PointT> vtkSmartPointer<vtkDataArray>
58{
59 if (!capable_ || !cloud_)
60 return nullptr;
61
63 scalars->SetNumberOfComponents (3);
64
65 vtkIdType nr_points = cloud_->size ();
66 scalars->SetNumberOfTuples (nr_points);
67
68 // Get a random color
69 unsigned char* colors = new unsigned char[nr_points * 3];
70
71 // Color every point
72 for (vtkIdType cp = 0; cp < nr_points; ++cp)
73 {
74 colors[cp * 3 + 0] = static_cast<unsigned char> (r_);
75 colors[cp * 3 + 1] = static_cast<unsigned char> (g_);
76 colors[cp * 3 + 2] = static_cast<unsigned char> (b_);
77 }
78 scalars->SetArray (colors, 3 * nr_points, 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
79 return scalars;
80}
81
82
83template <typename PointT> vtkSmartPointer<vtkDataArray>
85{
86 if (!capable_ || !cloud_)
87 return nullptr;
88
90 scalars->SetNumberOfComponents (3);
91
92 vtkIdType nr_points = cloud_->size ();
93 scalars->SetNumberOfTuples (nr_points);
94
95 // Get a random color
96 unsigned char* colors = new unsigned char[nr_points * 3];
97 double r, g, b;
99
100 int r_ = static_cast<int> (pcl_lrint (r * 255.0)),
101 g_ = static_cast<int> (pcl_lrint (g * 255.0)),
102 b_ = static_cast<int> (pcl_lrint (b * 255.0));
103
104 // Color every point
105 for (vtkIdType cp = 0; cp < nr_points; ++cp)
106 {
107 colors[cp * 3 + 0] = static_cast<unsigned char> (r_);
108 colors[cp * 3 + 1] = static_cast<unsigned char> (g_);
109 colors[cp * 3 + 2] = static_cast<unsigned char> (b_);
110 }
111 scalars->SetArray (colors, 3 * nr_points, 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
112 return scalars;
113}
114
115
116template <typename PointT> void
118 const PointCloudConstPtr &cloud)
119{
121 // Handle the 24-bit packed RGB values
122 field_idx_ = pcl::getFieldIndex<PointT> ("rgb", fields_);
123 if (field_idx_ != -1)
124 {
125 capable_ = true;
126 return;
127 }
128 else
129 {
130 field_idx_ = pcl::getFieldIndex<PointT> ("rgba", fields_);
131 if (field_idx_ != -1)
132 capable_ = true;
133 else
134 capable_ = false;
135 }
136}
137
138
139template <typename PointT> vtkSmartPointer<vtkDataArray>
141{
142 if (!capable_ || !cloud_)
143 return nullptr;
144
145 // Get the RGB field index
146 std::vector<pcl::PCLPointField> fields;
147 int rgba_index = -1;
148 rgba_index = pcl::getFieldIndex<PointT> ("rgb", fields);
149 if (rgba_index == -1)
150 rgba_index = pcl::getFieldIndex<PointT> ("rgba", fields);
151
152 int rgba_offset = fields[rgba_index].offset;
153
155 scalars->SetNumberOfComponents (3);
156
157 vtkIdType nr_points = cloud_->size ();
158 scalars->SetNumberOfTuples (nr_points);
159 unsigned char* colors = scalars->GetPointer (0);
160
161 // If XYZ present, check if the points are invalid
162 int x_idx = -1;
163 for (std::size_t d = 0; d < fields_.size (); ++d)
164 if (fields_[d].name == "x")
165 x_idx = static_cast<int> (d);
166
167 pcl::RGB rgb;
168 if (x_idx != -1)
169 {
170 int j = 0;
171 // Color every point
172 for (vtkIdType cp = 0; cp < nr_points; ++cp)
173 {
174 // Copy the value at the specified field
175 if (!pcl::isXYZFinite((*cloud_)[cp]))
176 continue;
177 memcpy (&rgb, (reinterpret_cast<const char *> (&(*cloud_)[cp])) + rgba_offset, sizeof (pcl::RGB));
178 colors[j ] = rgb.r;
179 colors[j + 1] = rgb.g;
180 colors[j + 2] = rgb.b;
181 j += 3;
182 }
183 }
184 else
185 {
186 // Color every point
187 for (vtkIdType cp = 0; cp < nr_points; ++cp)
188 {
189 int idx = static_cast<int> (cp) * 3;
190 memcpy (&rgb, (reinterpret_cast<const char *> (&(*cloud_)[cp])) + rgba_offset, sizeof (pcl::RGB));
191 colors[idx ] = rgb.r;
192 colors[idx + 1] = rgb.g;
193 colors[idx + 2] = rgb.b;
194 }
195 }
196 return scalars;
197}
198
199
200template <typename PointT>
203{
204 // Check for the presence of the "H" field
205 field_idx_ = pcl::getFieldIndex<PointT> ("h", fields_);
206 if (field_idx_ == -1)
207 {
208 capable_ = false;
209 return;
210 }
211
212 // Check for the presence of the "S" field
213 s_field_idx_ = pcl::getFieldIndex<PointT> ("s", fields_);
214 if (s_field_idx_ == -1)
215 {
216 capable_ = false;
217 return;
218 }
219
220 // Check for the presence of the "V" field
221 v_field_idx_ = pcl::getFieldIndex<PointT> ("v", fields_);
222 if (v_field_idx_ == -1)
223 {
224 capable_ = false;
225 return;
226 }
227 capable_ = true;
228}
229
230
231template <typename PointT> vtkSmartPointer<vtkDataArray>
233{
234 if (!capable_ || !cloud_)
235 return nullptr;
236
238 scalars->SetNumberOfComponents (3);
239
240 vtkIdType nr_points = cloud_->size ();
241 scalars->SetNumberOfTuples (nr_points);
242 unsigned char* colors = scalars->GetPointer (0);
243
244 int idx = 0;
245 // If XYZ present, check if the points are invalid
246 int x_idx = -1;
247
248 for (std::size_t d = 0; d < fields_.size (); ++d)
249 if (fields_[d].name == "x")
250 x_idx = static_cast<int> (d);
251
252 if (x_idx != -1)
253 {
254 // Color every point
255 for (vtkIdType cp = 0; cp < nr_points; ++cp)
256 {
257 // Copy the value at the specified field
258 if (!pcl::isXYZFinite((*cloud_)[cp]))
259 continue;
260
261 ///@todo do this with the point_types_conversion in common, first template it!
262
263 float h = (*cloud_)[cp].h;
264 float v = (*cloud_)[cp].v;
265 float s = (*cloud_)[cp].s;
266
267 // Fill color data with HSV here:
268 // restrict the hue value to [0,360[
269 h = h < 0.0f ? h - (((int)h)/360 - 1)*360 : h - (((int)h)/360)*360;
270
271 // restrict s and v to [0,1]
272 if (s > 1.0f) s = 1.0f;
273 if (s < 0.0f) s = 0.0f;
274 if (v > 1.0f) v = 1.0f;
275 if (v < 0.0f) v = 0.0f;
276
277 if (s == 0.0f)
278 {
279 colors[idx] = colors[idx+1] = colors[idx+2] = v*255;
280 }
281 else
282 {
283 // calculate p, q, t from HSV-values
284 float a = h / 60;
285 int i = std::floor (a);
286 float f = a - i;
287 float p = v * (1 - s);
288 float q = v * (1 - s * f);
289 float t = v * (1 - s * (1 - f));
290
291 switch (i)
292 {
293 case 0:
294 colors[idx] = v*255; colors[idx+1] = t*255; colors[idx+2] = p*255; break;
295 case 1:
296 colors[idx] = q*255; colors[idx+1] = v*255; colors[idx+2] = p*255; break;
297 case 2:
298 colors[idx] = p*255; colors[idx+1] = v*255; colors[idx+2] = t*255; break;
299 case 3:
300 colors[idx] = p*255; colors[idx+1] = q*255; colors[idx+2] = v*255; break;
301 case 4:
302 colors[idx] = t*255; colors[idx+1] = p*255; colors[idx+2] = v*255; break;
303 case 5:
304 colors[idx] = v*255; colors[idx+1] = p*255; colors[idx+2] = q*255; break;
305 }
306 }
307 idx +=3;
308 }
309 }
310 else
311 {
312 // Color every point
313 for (vtkIdType cp = 0; cp < nr_points; ++cp)
314 {
315 float h = (*cloud_)[cp].h;
316 float v = (*cloud_)[cp].v;
317 float s = (*cloud_)[cp].s;
318
319 // Fill color data with HSV here:
320 // restrict the hue value to [0,360[
321 h = h < 0.0f ? h - (((int)h)/360 - 1)*360 : h - (((int)h)/360)*360;
322
323 // restrict s and v to [0,1]
324 if (s > 1.0f) s = 1.0f;
325 if (s < 0.0f) s = 0.0f;
326 if (v > 1.0f) v = 1.0f;
327 if (v < 0.0f) v = 0.0f;
328
329 if (s == 0.0f)
330 {
331 colors[idx] = colors[idx+1] = colors[idx+2] = v*255;
332 }
333 else
334 {
335 // calculate p, q, t from HSV-values
336 float a = h / 60;
337 int i = std::floor (a);
338 float f = a - i;
339 float p = v * (1 - s);
340 float q = v * (1 - s * f);
341 float t = v * (1 - s * (1 - f));
342
343 switch (i)
344 {
345 case 0:
346 colors[idx] = v*255; colors[idx+1] = t*255; colors[idx+2] = p*255; break;
347 case 1:
348 colors[idx] = q*255; colors[idx+1] = v*255; colors[idx+2] = p*255; break;
349 case 2:
350 colors[idx] = p*255; colors[idx+1] = v*255; colors[idx+2] = t*255; break;
351 case 3:
352 colors[idx] = p*255; colors[idx+1] = q*255; colors[idx+2] = v*255; break;
353 case 4:
354 colors[idx] = t*255; colors[idx+1] = p*255; colors[idx+2] = v*255; break;
355 case 5:
356 colors[idx] = v*255; colors[idx+1] = p*255; colors[idx+2] = q*255; break;
357 }
358 }
359 idx +=3;
360 }
361 }
362 return scalars;
363}
364
365template <typename PointT> void
367 const PointCloudConstPtr &cloud)
368{
370 // Handle the 24-bit packed RGBA values
371 field_idx_ = pcl::getFieldIndex<PointT> ("rgba", fields_);
372 if (field_idx_ != -1)
373 capable_ = true;
374 else
375 capable_ = false;
376}
377
378
379template <typename PointT> vtkSmartPointer<vtkDataArray>
381{
382 if (!capable_ || !cloud_)
383 return nullptr;
384
386 scalars->SetNumberOfComponents (4);
387
388 vtkIdType nr_points = cloud_->size ();
389 scalars->SetNumberOfTuples (nr_points);
390 unsigned char* colors = scalars->GetPointer (0);
391
392 // If XYZ present, check if the points are invalid
393 int x_idx = -1;
394 for (std::size_t d = 0; d < fields_.size (); ++d)
395 if (fields_[d].name == "x")
396 x_idx = static_cast<int> (d);
397
398 if (x_idx != -1)
399 {
400 int j = 0;
401 // Color every point
402 for (vtkIdType cp = 0; cp < nr_points; ++cp)
403 {
404 // Copy the value at the specified field
405 if (!pcl::isXYZFinite((*cloud_)[cp]))
406 continue;
407
408 colors[j ] = (*cloud_)[cp].r;
409 colors[j + 1] = (*cloud_)[cp].g;
410 colors[j + 2] = (*cloud_)[cp].b;
411 colors[j + 3] = (*cloud_)[cp].a;
412 j += 4;
413 }
414 }
415 else
416 {
417 // Color every point
418 for (vtkIdType cp = 0; cp < nr_points; ++cp)
419 {
420 int idx = static_cast<int> (cp) * 4;
421 colors[idx ] = (*cloud_)[cp].r;
422 colors[idx + 1] = (*cloud_)[cp].g;
423 colors[idx + 2] = (*cloud_)[cp].b;
424 colors[idx + 3] = (*cloud_)[cp].a;
425 }
426 }
427 return scalars;
428}
429
430
431template <typename PointT> void
433{
435 field_idx_ = pcl::getFieldIndex<PointT> ("label", fields_);
436 if (field_idx_ != -1)
437 {
438 capable_ = true;
439 return;
440 }
441}
442
443
444template <typename PointT> vtkSmartPointer<vtkDataArray>
446{
447 if (!capable_ || !cloud_)
448 return nullptr;
449
451 scalars->SetNumberOfComponents (3);
452
453 vtkIdType nr_points = cloud_->size ();
454 scalars->SetNumberOfTuples (nr_points);
455 unsigned char* colors = scalars->GetPointer (0);
456
457
458 std::map<std::uint32_t, pcl::RGB> colormap;
459 if (!static_mapping_)
460 {
461 std::set<std::uint32_t> labels;
462 // First pass: find unique labels
463 for (vtkIdType i = 0; i < nr_points; ++i)
464 labels.insert ((*cloud_)[i].label);
465
466 // Assign Glasbey colors in ascending order of labels
467 std::size_t color = 0;
468 for (std::set<std::uint32_t>::iterator iter = labels.begin (); iter != labels.end (); ++iter, ++color)
469 colormap[*iter] = GlasbeyLUT::at (color % GlasbeyLUT::size ());
470 }
471
472 int j = 0;
473 for (vtkIdType cp = 0; cp < nr_points; ++cp)
474 {
475 if (pcl::isFinite ((*cloud_)[cp]))
476 {
477 const pcl::RGB& color = static_mapping_ ? GlasbeyLUT::at ((*cloud_)[cp].label % GlasbeyLUT::size ()) : colormap[(*cloud_)[cp].label];
478 colors[j ] = color.r;
479 colors[j + 1] = color.g;
480 colors[j + 2] = color.b;
481 j += 3;
482 }
483 }
484
485 return scalars;
486}
487
488// ----
489// template specializations for PointCloud and PCLPointCloud2 to access certain
490// data from PointCloudColorHandlerGenericField without needing to know the
491// cloud type
492
493template <typename CloudT> inline int getPointStep(const CloudT&)
494{
495 return sizeof(typename CloudT::PointType);
496}
497
498template <> inline int
500 return cloud.point_step;
501}
502
503// Get cloud data blob
504template <typename CloudT> inline const std::uint8_t* getCloudData(const CloudT& cloud)
505{
506 return reinterpret_cast<const std::uint8_t*>(cloud.data());
507}
508
509template <> inline const std::uint8_t* getCloudData<pcl::PCLPointCloud2>(const typename pcl::PCLPointCloud2& cloud) {
510 return cloud.data.data();
511}
512
513// copy of pcl::getFieldIndex() from impl/io.hpp, without the unused template
514// parameter
515static int getFieldIndex(const std::string& field_name,
516 const std::vector<pcl::PCLPointField>& fields)
517{
518 const auto result =
519 std::find_if(fields.begin(), fields.end(), [&field_name](const auto& field) {
520 return field.name == field_name;
521 });
522 if (result == fields.end()) {
523 return -1;
524 }
525 return std::distance(fields.begin(), result);
526}
527
528// Cloud type agnostic isXYZFinite wrappers to check if pointcloud or PCLPointCloud2 at
529// given index is finite
530template <typename CloudT> inline bool isXYZFiniteAt(const CloudT& cloud, int index)
531{
532 return pcl::isXYZFinite(cloud.at(index));
533}
534
535template <> inline bool isXYZFiniteAt(const PCLPointCloud2& cloud, int index)
536{
537 // get x,y,z field indices
538 const auto x_field_idx = getFieldIndex("x", cloud.fields);
539 const auto y_field_idx = getFieldIndex("y", cloud.fields);
540 const auto z_field_idx = getFieldIndex("z", cloud.fields);
541
542 // if any missing, error
543 if (x_field_idx == -1 || y_field_idx == -1 || z_field_idx == -1) {
544 throw std::out_of_range("isXYZFiniteAt(): input cloud missing at least one of x, y, z fields");
545 }
546 // get x,y,z field values
547 const auto position_x = index * cloud.point_step + cloud.fields[x_field_idx].offset;
548 const auto position_y = index * cloud.point_step + cloud.fields[y_field_idx].offset;
549 const auto position_z = index * cloud.point_step + cloud.fields[z_field_idx].offset;
550 if (cloud.data.size () >= (position_x + sizeof(float)) &&
551 cloud.data.size () >= (position_y + sizeof(float)) &&
552 cloud.data.size () >= (position_z + sizeof(float))) {
553 const float x = *reinterpret_cast<const float*>(&cloud.data[position_x]);
554 const float y = *reinterpret_cast<const float*>(&cloud.data[position_y]);
555 const float z = *reinterpret_cast<const float*>(&cloud.data[position_z]);
556 return isXYZFinite(PointXYZ(x, y, z));
557 } else {
558 // the last of the three is out of range
559 throw std::out_of_range("isXYZFiniteAt(): requested for index larger than number of points");
560 }
561}
562
563template <typename PointT>
565 const PointCloudConstPtr& cloud, const std::string& field_name)
566: PointCloudColorHandler<PointT>(cloud), field_name_(field_name)
567{
568 this->setInputCloud(cloud);
569}
570
571template <typename PointT>
574
576 const PointCloudConstPtr& cloud)
577{
579 this->fields_ = getFields(*cloud);
580 this->field_idx_ = getFieldIndex(field_name_, this->fields_);
581 this->capable_ = this->field_idx_ != -1;
582}
583
584template <typename PointT> std::string PointCloudColorHandlerGenericField<PointT>::getFieldName() const
585{
586 return field_name_;
587}
588
590{
591 if (!this->capable_ || !this->cloud_) {
592 return nullptr;
593 }
594
596 scalars->SetNumberOfComponents(1);
597
598 const vtkIdType nr_points = this->cloud_->width * this->cloud_->height;
599 scalars->SetNumberOfTuples(nr_points);
600
601 // per-point color as a float value. vtk turns that into rgb somehow
602 float* colors = new float[nr_points];
603
604 // Find X channel
605 int x_channel_idx = -1;
606 for (std::size_t channel_idx = 0; channel_idx < this->fields_.size(); ++channel_idx) {
607 if (this->fields_[channel_idx].name == "x") {
608 x_channel_idx = static_cast<int>(channel_idx);
609 }
610 }
611
612 size_t point_offset = this->fields_[this->field_idx_].offset;
613 const int point_step = getPointStep<PointCloud>(*this->cloud_);
614 const std::uint8_t* p_data = getCloudData<PointCloud>(*this->cloud_);
615 const std::uint8_t field_type = this->fields_[this->field_idx_].datatype;
616
617 // current index into colors array
618 int pt_idx = 0;
619
620 // Color every point
621 for (vtkIdType cp = 0; cp < nr_points; ++cp, point_offset += point_step) {
622
623 if (x_channel_idx != -1 && !isXYZFiniteAt(*this->cloud_, cp)) {
624 // no x channel in the cloud, or point is infinite
625 continue;
626 } else {
627 // point data at index, field offset already baked into point_offset
628 const std::uint8_t* pt_data = &p_data[point_offset];
629
630 colors[pt_idx] = point_field_as<float>(pt_data, field_type);
631
632 }
633
634 ++pt_idx;
635 }
636
637 scalars->SetArray(colors, pt_idx, 0, vtkFloatArray::VTK_DATA_ARRAY_DELETE);
638 return scalars;
639}
640
641} // namespace visualization
642} // namespace pcl
vtkSmartPointer< vtkDataArray > getColor() const override
Obtain the actual color for the input dataset as a VTK data array.
PointCloudColorHandlerGenericField(const PointCloudConstPtr &cloud, const std::string &field_name)
constructor
std::string getFieldName() const override
Get the name of the field used.
vtkSmartPointer< vtkDataArray > getColor() const override
Obtain the actual color for the input dataset as a VTK data array.
void setInputCloud(const PointCloudConstPtr &cloud)
Set the input cloud to be used.
PointCloudColorHandlerHSVField(const PointCloudConstPtr &cloud)
Constructor.
vtkSmartPointer< vtkDataArray > getColor() const override
Obtain the actual color for the input dataset as a VTK data array.
Base Handler class for PointCloud colors.
bool capable_
True if this handler is capable of handling the input data, false otherwise.
virtual void setInputCloud(const PointCloudConstPtr &cloud)
Set the input cloud to be used.
std::vector< pcl::PCLPointField > fields_
The list of fields available for this PointCloud.
int field_idx_
The index of the field holding the data that represents the color.
virtual void setInputCloud(const PointCloudConstPtr &cloud)
Set the input cloud to be used.
vtkSmartPointer< vtkDataArray > getColor() const override
Obtain the actual color for the input dataset as a VTK data array.
vtkSmartPointer< vtkDataArray > getColor() const override
Obtain the actual color for the input dataset as a VTK data array.
virtual void setInputCloud(const PointCloudConstPtr &cloud)
Set the input cloud to be used.
vtkSmartPointer< vtkDataArray > getColor() const override
Obtain the actual color for the input dataset as a VTK data array.
virtual void setInputCloud(const PointCloudConstPtr &cloud)
Set the input cloud to be used.
vtkSmartPointer< vtkDataArray > getColor() const override
Obtain the actual color for the input dataset as a VTK data array.
std::vector< pcl::PCLPointField > getFields()
Get the list of available fields (i.e., dimension/channel)
Definition io.hpp:97
const std::uint8_t * getCloudData< pcl::PCLPointCloud2 >(const typename pcl::PCLPointCloud2 &cloud)
PCL_EXPORTS void getRandomColors(double &r, double &g, double &b, double min=0.2, double max=2.8)
Get (good) random values for R/G/B.
const std::uint8_t * getCloudData(const CloudT &cloud)
bool isXYZFiniteAt(const CloudT &cloud, int index)
int getPointStep< pcl::PCLPointCloud2 >(const pcl::PCLPointCloud2 &cloud)
static int getFieldIndex(const std::string &field_name, const std::vector< pcl::PCLPointField > &fields)
bool isFinite(const PointT &pt)
Tests if the 3D components of a point are all finite param[in] pt point to be tested return true if f...
Definition point_tests.h:56
constexpr bool isXYZFinite(const PointT &) noexcept
Defines all the PCL and non-PCL macros used.
#define pcl_lrint(x)
Definition pcl_macros.h:252
std::vector<::pcl::PCLPointField > fields
std::vector< std::uint8_t > data
A point structure representing Euclidean xyz coordinates.
A point structure representing Euclidean xyz coordinates, and the RGB color.
A structure representing RGB color information.