Point Cloud Library (PCL)  1.14.1-dev
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 
43 #include <pcl/pcl_macros.h>
44 #include <pcl/common/colors.h>
45 #include <pcl/common/io.h> // for getFieldIndex
46 #include <pcl/common/point_tests.h> // for pcl::isFinite
47 
48 
49 namespace pcl
50 {
51 
52 namespace visualization
53 {
54 
55 template <typename PointT> vtkSmartPointer<vtkDataArray>
57 {
58  if (!capable_ || !cloud_)
59  return nullptr;
60 
62  scalars->SetNumberOfComponents (3);
63 
64  vtkIdType nr_points = cloud_->size ();
65  scalars->SetNumberOfTuples (nr_points);
66 
67  // Get a random color
68  unsigned char* colors = new unsigned char[nr_points * 3];
69 
70  // Color every point
71  for (vtkIdType cp = 0; cp < nr_points; ++cp)
72  {
73  colors[cp * 3 + 0] = static_cast<unsigned char> (r_);
74  colors[cp * 3 + 1] = static_cast<unsigned char> (g_);
75  colors[cp * 3 + 2] = static_cast<unsigned char> (b_);
76  }
77  scalars->SetArray (colors, 3 * nr_points, 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
78  return scalars;
79 }
80 
81 
82 template <typename PointT> vtkSmartPointer<vtkDataArray>
84 {
85  if (!capable_ || !cloud_)
86  return nullptr;
87 
89  scalars->SetNumberOfComponents (3);
90 
91  vtkIdType nr_points = cloud_->size ();
92  scalars->SetNumberOfTuples (nr_points);
93 
94  // Get a random color
95  unsigned char* colors = new unsigned char[nr_points * 3];
96  double r, g, b;
98 
99  int r_ = static_cast<int> (pcl_lrint (r * 255.0)),
100  g_ = static_cast<int> (pcl_lrint (g * 255.0)),
101  b_ = static_cast<int> (pcl_lrint (b * 255.0));
102 
103  // Color every point
104  for (vtkIdType cp = 0; cp < nr_points; ++cp)
105  {
106  colors[cp * 3 + 0] = static_cast<unsigned char> (r_);
107  colors[cp * 3 + 1] = static_cast<unsigned char> (g_);
108  colors[cp * 3 + 2] = static_cast<unsigned char> (b_);
109  }
110  scalars->SetArray (colors, 3 * nr_points, 0, vtkUnsignedCharArray::VTK_DATA_ARRAY_DELETE);
111  return scalars;
112 }
113 
114 
115 template <typename PointT> void
117  const PointCloudConstPtr &cloud)
118 {
120  // Handle the 24-bit packed RGB values
121  field_idx_ = pcl::getFieldIndex<PointT> ("rgb", fields_);
122  if (field_idx_ != -1)
123  {
124  capable_ = true;
125  return;
126  }
127  else
128  {
129  field_idx_ = pcl::getFieldIndex<PointT> ("rgba", fields_);
130  if (field_idx_ != -1)
131  capable_ = true;
132  else
133  capable_ = false;
134  }
135 }
136 
137 
138 template <typename PointT> vtkSmartPointer<vtkDataArray>
140 {
141  if (!capable_ || !cloud_)
142  return nullptr;
143 
144  // Get the RGB field index
145  std::vector<pcl::PCLPointField> fields;
146  int rgba_index = -1;
147  rgba_index = pcl::getFieldIndex<PointT> ("rgb", fields);
148  if (rgba_index == -1)
149  rgba_index = pcl::getFieldIndex<PointT> ("rgba", fields);
150 
151  int rgba_offset = fields[rgba_index].offset;
152 
154  scalars->SetNumberOfComponents (3);
155 
156  vtkIdType nr_points = cloud_->size ();
157  scalars->SetNumberOfTuples (nr_points);
158  unsigned char* colors = scalars->GetPointer (0);
159 
160  // If XYZ present, check if the points are invalid
161  int x_idx = -1;
162  for (std::size_t d = 0; d < fields_.size (); ++d)
163  if (fields_[d].name == "x")
164  x_idx = static_cast<int> (d);
165 
166  pcl::RGB rgb;
167  if (x_idx != -1)
168  {
169  int j = 0;
170  // Color every point
171  for (vtkIdType cp = 0; cp < nr_points; ++cp)
172  {
173  // Copy the value at the specified field
174  if (!pcl::isXYZFinite((*cloud_)[cp]))
175  continue;
176  memcpy (&rgb, (reinterpret_cast<const char *> (&(*cloud_)[cp])) + rgba_offset, sizeof (pcl::RGB));
177  colors[j ] = rgb.r;
178  colors[j + 1] = rgb.g;
179  colors[j + 2] = rgb.b;
180  j += 3;
181  }
182  }
183  else
184  {
185  // Color every point
186  for (vtkIdType cp = 0; cp < nr_points; ++cp)
187  {
188  int idx = static_cast<int> (cp) * 3;
189  memcpy (&rgb, (reinterpret_cast<const char *> (&(*cloud_)[cp])) + rgba_offset, sizeof (pcl::RGB));
190  colors[idx ] = rgb.r;
191  colors[idx + 1] = rgb.g;
192  colors[idx + 2] = rgb.b;
193  }
194  }
195  return scalars;
196 }
197 
198 
199 template <typename PointT>
202 {
203  // Check for the presence of the "H" field
204  field_idx_ = pcl::getFieldIndex<PointT> ("h", fields_);
205  if (field_idx_ == -1)
206  {
207  capable_ = false;
208  return;
209  }
210 
211  // Check for the presence of the "S" field
212  s_field_idx_ = pcl::getFieldIndex<PointT> ("s", fields_);
213  if (s_field_idx_ == -1)
214  {
215  capable_ = false;
216  return;
217  }
218 
219  // Check for the presence of the "V" field
220  v_field_idx_ = pcl::getFieldIndex<PointT> ("v", fields_);
221  if (v_field_idx_ == -1)
222  {
223  capable_ = false;
224  return;
225  }
226  capable_ = true;
227 }
228 
229 
230 template <typename PointT> vtkSmartPointer<vtkDataArray>
232 {
233  if (!capable_ || !cloud_)
234  return nullptr;
235 
237  scalars->SetNumberOfComponents (3);
238 
239  vtkIdType nr_points = cloud_->size ();
240  scalars->SetNumberOfTuples (nr_points);
241  unsigned char* colors = scalars->GetPointer (0);
242 
243  int idx = 0;
244  // If XYZ present, check if the points are invalid
245  int x_idx = -1;
246 
247  for (std::size_t d = 0; d < fields_.size (); ++d)
248  if (fields_[d].name == "x")
249  x_idx = static_cast<int> (d);
250 
251  if (x_idx != -1)
252  {
253  // Color every point
254  for (vtkIdType cp = 0; cp < nr_points; ++cp)
255  {
256  // Copy the value at the specified field
257  if (!pcl::isXYZFinite((*cloud_)[cp]))
258  continue;
259 
260  ///@todo do this with the point_types_conversion in common, first template it!
261 
262  float h = (*cloud_)[cp].h;
263  float v = (*cloud_)[cp].v;
264  float s = (*cloud_)[cp].s;
265 
266  // Fill color data with HSV here:
267  // restrict the hue value to [0,360[
268  h = h < 0.0f ? h - (((int)h)/360 - 1)*360 : h - (((int)h)/360)*360;
269 
270  // restrict s and v to [0,1]
271  if (s > 1.0f) s = 1.0f;
272  if (s < 0.0f) s = 0.0f;
273  if (v > 1.0f) v = 1.0f;
274  if (v < 0.0f) v = 0.0f;
275 
276  if (s == 0.0f)
277  {
278  colors[idx] = colors[idx+1] = colors[idx+2] = v*255;
279  }
280  else
281  {
282  // calculate p, q, t from HSV-values
283  float a = h / 60;
284  int i = std::floor (a);
285  float f = a - i;
286  float p = v * (1 - s);
287  float q = v * (1 - s * f);
288  float t = v * (1 - s * (1 - f));
289 
290  switch (i)
291  {
292  case 0:
293  colors[idx] = v*255; colors[idx+1] = t*255; colors[idx+2] = p*255; break;
294  case 1:
295  colors[idx] = q*255; colors[idx+1] = v*255; colors[idx+2] = p*255; break;
296  case 2:
297  colors[idx] = p*255; colors[idx+1] = v*255; colors[idx+2] = t*255; break;
298  case 3:
299  colors[idx] = p*255; colors[idx+1] = q*255; colors[idx+2] = v*255; break;
300  case 4:
301  colors[idx] = t*255; colors[idx+1] = p*255; colors[idx+2] = v*255; break;
302  case 5:
303  colors[idx] = v*255; colors[idx+1] = p*255; colors[idx+2] = q*255; break;
304  }
305  }
306  idx +=3;
307  }
308  }
309  else
310  {
311  // Color every point
312  for (vtkIdType cp = 0; cp < nr_points; ++cp)
313  {
314  float h = (*cloud_)[cp].h;
315  float v = (*cloud_)[cp].v;
316  float s = (*cloud_)[cp].s;
317 
318  // Fill color data with HSV here:
319  // restrict the hue value to [0,360[
320  h = h < 0.0f ? h - (((int)h)/360 - 1)*360 : h - (((int)h)/360)*360;
321 
322  // restrict s and v to [0,1]
323  if (s > 1.0f) s = 1.0f;
324  if (s < 0.0f) s = 0.0f;
325  if (v > 1.0f) v = 1.0f;
326  if (v < 0.0f) v = 0.0f;
327 
328  if (s == 0.0f)
329  {
330  colors[idx] = colors[idx+1] = colors[idx+2] = v*255;
331  }
332  else
333  {
334  // calculate p, q, t from HSV-values
335  float a = h / 60;
336  int i = std::floor (a);
337  float f = a - i;
338  float p = v * (1 - s);
339  float q = v * (1 - s * f);
340  float t = v * (1 - s * (1 - f));
341 
342  switch (i)
343  {
344  case 0:
345  colors[idx] = v*255; colors[idx+1] = t*255; colors[idx+2] = p*255; break;
346  case 1:
347  colors[idx] = q*255; colors[idx+1] = v*255; colors[idx+2] = p*255; break;
348  case 2:
349  colors[idx] = p*255; colors[idx+1] = v*255; colors[idx+2] = t*255; break;
350  case 3:
351  colors[idx] = p*255; colors[idx+1] = q*255; colors[idx+2] = v*255; break;
352  case 4:
353  colors[idx] = t*255; colors[idx+1] = p*255; colors[idx+2] = v*255; break;
354  case 5:
355  colors[idx] = v*255; colors[idx+1] = p*255; colors[idx+2] = q*255; break;
356  }
357  }
358  idx +=3;
359  }
360  }
361  return scalars;
362 }
363 
364 
365 template <typename PointT> void
367  const PointCloudConstPtr &cloud)
368 {
370  field_idx_ = pcl::getFieldIndex<PointT> (field_name_, fields_);
371  if (field_idx_ == -1) {
372  capable_ = false;
373  return;
374  }
375  if (fields_[field_idx_].datatype != pcl::PCLPointField::PointFieldTypes::FLOAT32) {
376  capable_ = false;
377  PCL_ERROR("[pcl::PointCloudColorHandlerGenericField::setInputCloud] This currently only works with float32 fields, but field %s has a different type.\n", field_name_.c_str());
378  return;
379  }
380  capable_ = true;
381 }
382 
383 
384 template <typename PointT> vtkSmartPointer<vtkDataArray>
386 {
387  if (!capable_ || !cloud_)
388  return nullptr;
389 
390  auto scalars = vtkSmartPointer<vtkFloatArray>::New ();
391  scalars->SetNumberOfComponents (1);
392 
393  vtkIdType nr_points = cloud_->size ();
394  scalars->SetNumberOfTuples (nr_points);
395 
396  using FieldList = typename pcl::traits::fieldList<PointT>::type;
397 
398  float* colors = new float[nr_points];
399  float field_data;
400 
401  int j = 0;
402  // If XYZ present, check if the points are invalid
403  int x_idx = -1;
404  for (std::size_t d = 0; d < fields_.size (); ++d)
405  if (fields_[d].name == "x")
406  x_idx = static_cast<int> (d);
407 
408  if (x_idx != -1)
409  {
410  // Color every point
411  for (vtkIdType cp = 0; cp < nr_points; ++cp)
412  {
413  // Copy the value at the specified field
414  if (!pcl::isXYZFinite((*cloud_)[cp]))
415  continue;
416 
417  const std::uint8_t* pt_data = reinterpret_cast<const std::uint8_t*> (&(*cloud_)[cp]);
418  memcpy (&field_data, pt_data + fields_[field_idx_].offset, pcl::getFieldSize (fields_[field_idx_].datatype));
419 
420  colors[j] = field_data;
421  j++;
422  }
423  }
424  else
425  {
426  // Color every point
427  for (vtkIdType cp = 0; cp < nr_points; ++cp)
428  {
429  const std::uint8_t* pt_data = reinterpret_cast<const std::uint8_t*> (&(*cloud_)[cp]);
430  memcpy (&field_data, pt_data + fields_[field_idx_].offset, pcl::getFieldSize (fields_[field_idx_].datatype));
431 
432  if (!std::isfinite (field_data))
433  continue;
434 
435  colors[j] = field_data;
436  j++;
437  }
438  }
439  scalars->SetArray (colors, j, 0, vtkFloatArray::VTK_DATA_ARRAY_DELETE);
440  return scalars;
441 }
442 
443 
444 template <typename PointT> void
446  const PointCloudConstPtr &cloud)
447 {
449  // Handle the 24-bit packed RGBA values
450  field_idx_ = pcl::getFieldIndex<PointT> ("rgba", fields_);
451  if (field_idx_ != -1)
452  capable_ = true;
453  else
454  capable_ = false;
455 }
456 
457 
458 template <typename PointT> vtkSmartPointer<vtkDataArray>
460 {
461  if (!capable_ || !cloud_)
462  return nullptr;
463 
465  scalars->SetNumberOfComponents (4);
466 
467  vtkIdType nr_points = cloud_->size ();
468  scalars->SetNumberOfTuples (nr_points);
469  unsigned char* colors = scalars->GetPointer (0);
470 
471  // If XYZ present, check if the points are invalid
472  int x_idx = -1;
473  for (std::size_t d = 0; d < fields_.size (); ++d)
474  if (fields_[d].name == "x")
475  x_idx = static_cast<int> (d);
476 
477  if (x_idx != -1)
478  {
479  int j = 0;
480  // Color every point
481  for (vtkIdType cp = 0; cp < nr_points; ++cp)
482  {
483  // Copy the value at the specified field
484  if (!pcl::isXYZFinite((*cloud_)[cp]))
485  continue;
486 
487  colors[j ] = (*cloud_)[cp].r;
488  colors[j + 1] = (*cloud_)[cp].g;
489  colors[j + 2] = (*cloud_)[cp].b;
490  colors[j + 3] = (*cloud_)[cp].a;
491  j += 4;
492  }
493  }
494  else
495  {
496  // Color every point
497  for (vtkIdType cp = 0; cp < nr_points; ++cp)
498  {
499  int idx = static_cast<int> (cp) * 4;
500  colors[idx ] = (*cloud_)[cp].r;
501  colors[idx + 1] = (*cloud_)[cp].g;
502  colors[idx + 2] = (*cloud_)[cp].b;
503  colors[idx + 3] = (*cloud_)[cp].a;
504  }
505  }
506  return scalars;
507 }
508 
509 
510 template <typename PointT> void
512 {
514  field_idx_ = pcl::getFieldIndex<PointT> ("label", fields_);
515  if (field_idx_ != -1)
516  {
517  capable_ = true;
518  return;
519  }
520 }
521 
522 
523 template <typename PointT> vtkSmartPointer<vtkDataArray>
525 {
526  if (!capable_ || !cloud_)
527  return nullptr;
528 
530  scalars->SetNumberOfComponents (3);
531 
532  vtkIdType nr_points = cloud_->size ();
533  scalars->SetNumberOfTuples (nr_points);
534  unsigned char* colors = scalars->GetPointer (0);
535 
536 
537  std::map<std::uint32_t, pcl::RGB> colormap;
538  if (!static_mapping_)
539  {
540  std::set<std::uint32_t> labels;
541  // First pass: find unique labels
542  for (vtkIdType i = 0; i < nr_points; ++i)
543  labels.insert ((*cloud_)[i].label);
544 
545  // Assign Glasbey colors in ascending order of labels
546  std::size_t color = 0;
547  for (std::set<std::uint32_t>::iterator iter = labels.begin (); iter != labels.end (); ++iter, ++color)
548  colormap[*iter] = GlasbeyLUT::at (color % GlasbeyLUT::size ());
549  }
550 
551  int j = 0;
552  for (vtkIdType cp = 0; cp < nr_points; ++cp)
553  {
554  if (pcl::isFinite ((*cloud_)[cp]))
555  {
556  const pcl::RGB& color = static_mapping_ ? GlasbeyLUT::at ((*cloud_)[cp].label % GlasbeyLUT::size ()) : colormap[(*cloud_)[cp].label];
557  colors[j ] = color.r;
558  colors[j + 1] = color.g;
559  colors[j + 2] = color.b;
560  j += 3;
561  }
562  }
563 
564  return scalars;
565 }
566 
567 } // namespace visualization
568 } // namespace pcl
569 
static std::size_t size()
Get the number of colors in the lookup table.
static RGB at(std::size_t color_id)
Get a color from the lookup table with a given id.
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.
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.
int getFieldSize(const int datatype)
Obtains the size of a specific field data type in bytes.
Definition: io.h:127
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.
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:55
constexpr bool isXYZFinite(const PointT &) noexcept
Definition: point_tests.h:125
Defines all the PCL and non-PCL macros used.
#define pcl_lrint(x)
Definition: pcl_macros.h:255
A point structure representing Euclidean xyz coordinates, and the RGB color.
A structure representing RGB color information.