Skip to content

Commit 2556e89

Browse files
refactor PointcloudColorHandlerGenericField to deal with any field type
1 parent 107616f commit 2556e89

File tree

3 files changed

+198
-200
lines changed

3 files changed

+198
-200
lines changed

visualization/include/pcl/visualization/impl/point_cloud_color_handlers.hpp

Lines changed: 172 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -361,86 +361,6 @@ PointCloudColorHandlerHSVField<PointT>::getColor () const
361361
return scalars;
362362
}
363363

364-
365-
template <typename PointT> void
366-
PointCloudColorHandlerGenericField<PointT>::setInputCloud (
367-
const PointCloudConstPtr &cloud)
368-
{
369-
PointCloudColorHandler<PointT>::setInputCloud (cloud);
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>
385-
PointCloudColorHandlerGenericField<PointT>::getColor () const
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-
444364
template <typename PointT> void
445365
PointCloudColorHandlerRGBAField<PointT>::setInputCloud (
446366
const PointCloudConstPtr &cloud)
@@ -564,6 +484,177 @@ PointCloudColorHandlerLabelField<PointT>::getColor () const
564484
return scalars;
565485
}
566486

487+
// ----
488+
// template specializations for PointCloud and PCLPointCloud2 to access certain
489+
// data from PointCloudColorHandlerGenericField without needing to know the
490+
// cloud type
491+
492+
// Get point fields from cloud. Could not get it to work with existing
493+
// pcl::getFields
494+
inline template <typename CloudT> std::vector<pcl::PCLPointField>
495+
getFields(const CloudT& cloud)
496+
{
497+
return pcl::getFields<typename CloudT::PointType>();
498+
}
499+
500+
// Get point step. Does not directly exist in pcl::PointCloud
501+
inline template <typename CloudT> int getPointStep(const CloudT&)
502+
{
503+
return sizeof(typename CloudT::PointType);
504+
}
505+
506+
// Get cloud data blob
507+
inline template <typename CloudT> const std::uint8_t* getCloudData(const CloudT& cloud)
508+
{
509+
return reinterpret_cast<const std::uint8_t*>(cloud.points.data());
510+
}
511+
512+
inline const std::uint8_t* getCloudData(const typename pcl::PCLPointCloud2& cloud)
513+
{
514+
return reinterpret_cast<const std::uint8_t*>(cloud.data.data());
515+
}
516+
517+
// copy of pcl::getFieldIndex() from impl/io.hpp, without the unused template
518+
// parameter
519+
static int getFieldIndex(const std::string& field_name,
520+
const std::vector<pcl::PCLPointField>& fields)
521+
{
522+
const auto result =
523+
std::find_if(fields.begin(), fields.end(), [&field_name](const auto& field) {
524+
return field.name == field_name;
525+
});
526+
if (result == fields.end()) {
527+
return -1;
528+
}
529+
return std::distance(fields.begin(), result);
530+
}
531+
532+
template <typename DType, typename RType> RType reinterpret_and_cast(const std::uint8_t* p)
533+
{
534+
return static_cast<RType>(*reinterpret_cast<const DType*>(p));
535+
}
536+
537+
/**
538+
* @brief Get the value of a point field from raw data pointer and field type.
539+
*
540+
* @tparam T return type the field will be cast as
541+
* @param data data pointer
542+
* @param type point field type
543+
*
544+
* @return field value
545+
*/
546+
template <typename T> T point_field_as(const std::uint8_t* data, const std::uint8_t type)
547+
{
548+
switch (type) {
549+
case pcl::PCLPointField::PointFieldTypes::FLOAT32:
550+
return reinterpret_and_cast<float, T>(data);
551+
break;
552+
case pcl::PCLPointField::PointFieldTypes::UINT8:
553+
return reinterpret_and_cast<std::uint8_t, T>(data);
554+
break;
555+
case pcl::PCLPointField::PointFieldTypes::UINT16:
556+
return reinterpret_and_cast<std::uint16_t, T>(data);
557+
break;
558+
case pcl::PCLPointField::PointFieldTypes::UINT32:
559+
return reinterpret_and_cast<std::uint32_t, T>(data);
560+
break;
561+
case pcl::PCLPointField::PointFieldTypes::UINT64:
562+
return reinterpret_and_cast<std::uint64_t, T>(data);
563+
break;
564+
case pcl::PCLPointField::PointFieldTypes::BOOL:
565+
return reinterpret_and_cast<bool, T>(data);
566+
break;
567+
case pcl::PCLPointField::PointFieldTypes::FLOAT64:
568+
return reinterpret_and_cast<double, T>(data);
569+
break;
570+
case pcl::PCLPointField::PointFieldTypes::INT16:
571+
return reinterpret_and_cast<std::int16_t, T>(data);
572+
break;
573+
case pcl::PCLPointField::PointFieldTypes::INT32:
574+
return reinterpret_and_cast<std::int32_t, T>(data);
575+
break;
576+
case pcl::PCLPointField::PointFieldTypes::INT64:
577+
return reinterpret_and_cast<std::int64_t, T>(data);
578+
break;
579+
default:
580+
return 0;
581+
break;
582+
}
583+
}
584+
585+
template <typename PointT>
586+
PointCloudColorHandlerGenericField<PointT>::PointCloudColorHandlerGenericField(
587+
const PointCloudConstPtr& cloud, const std::string& field_name)
588+
: PointCloudColorHandler<PointT>(cloud), field_name_(field_name)
589+
{
590+
this->fields_ = getFields(*cloud);
591+
this->setInputCloud(cloud);
592+
}
593+
594+
template <typename PointT> void PointCloudColorHandlerGenericField<PointT>::setInputCloud(
595+
const PointCloudConstPtr& cloud)
596+
{
597+
PointCloudColorHandler<PointT>::setInputCloud(cloud);
598+
this->field_idx_ = getFieldIndex(field_name_, this->fields_);
599+
this->capable_ = this->field_idx_ != -1;
600+
}
601+
602+
template <typename PointT> std::string PointCloudColorHandlerGenericField<PointT>::getFieldName() const
603+
{
604+
return field_name_;
605+
}
606+
607+
template <typename PointT> vtkSmartPointer<vtkDataArray> PointCloudColorHandlerGenericField<PointT>::getColor() const
608+
{
609+
if (!this->capable_ || !this->cloud_) {
610+
return nullptr;
611+
}
612+
613+
auto scalars = vtkSmartPointer<vtkFloatArray>::New();
614+
scalars->SetNumberOfComponents(1);
615+
616+
const vtkIdType nr_points = this->cloud_->width * this->cloud_->height;
617+
scalars->SetNumberOfTuples(nr_points);
618+
619+
// per-point color as a float value. vtk turns that into rgb somehow
620+
float* colors = new float[nr_points];
621+
622+
// Find X channel
623+
int x_channel_idx = -1;
624+
for (std::size_t channel_idx = 0; channel_idx < this->fields_.size(); ++channel_idx) {
625+
if (this->fields_[channel_idx].name == "x") {
626+
x_channel_idx = static_cast<int>(channel_idx);
627+
}
628+
}
629+
630+
int point_offset = this->fields_[this->field_idx_].offset;
631+
const int point_step = getPointStep<PointCloud>(*this->cloud_);
632+
const std::uint8_t* p_data = getCloudData<PointCloud>(*this->cloud_);
633+
const std::uint8_t field_type = this->fields_[this->field_idx_].datatype;
634+
635+
// current index into colors array
636+
int pt_idx = 0;
637+
638+
// Color every point
639+
for (vtkIdType cp = 0; cp < nr_points; ++cp, point_offset += point_step) {
640+
641+
if (x_channel_idx != -1 && !pcl::isXYZFinite((*this->cloud_)[cp])) {
642+
// no x channel in the cloud, or point is infinite
643+
continue;
644+
} else {
645+
// point data at index, field offset already baked into point_offset
646+
const std::uint8_t* pt_data = &p_data[point_offset];
647+
648+
colors[pt_idx] = point_field_as<float>(pt_data, field_type);
649+
650+
}
651+
652+
++pt_idx;
653+
}
654+
655+
scalars->SetArray(colors, pt_idx, 0, vtkFloatArray::VTK_DATA_ARRAY_DELETE);
656+
return scalars;
657+
}
658+
567659
} // namespace visualization
568660
} // namespace pcl
569-

visualization/include/pcl/visualization/point_cloud_color_handlers.h

Lines changed: 26 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -336,62 +336,45 @@ namespace pcl
336336

337337
//////////////////////////////////////////////////////////////////////////////////////
338338
/** \brief Generic field handler class for colors. Uses an user given field to extract
339-
* 1D data and display the color at each point using a min-max lookup table.
340-
* \author Radu B. Rusu
341-
* \ingroup visualization
342-
*/
339+
* 1D data and display the color at each point.
340+
* \ingroup visualization
341+
*/
343342
template <typename PointT>
344-
class PointCloudColorHandlerGenericField : public PointCloudColorHandler<PointT>
345-
{
343+
class PointCloudColorHandlerGenericField : public PointCloudColorHandler<PointT> {
346344
using PointCloud = typename PointCloudColorHandler<PointT>::PointCloud;
347345
using PointCloudPtr = typename PointCloud::Ptr;
348346
using PointCloudConstPtr = typename PointCloud::ConstPtr;
349347

350-
public:
351-
using Ptr = shared_ptr<PointCloudColorHandlerGenericField<PointT> >;
352-
using ConstPtr = shared_ptr<const PointCloudColorHandlerGenericField<PointT> >;
348+
public:
349+
using Ptr = std::shared_ptr<PointCloudColorHandlerGenericField<PointT>>;
350+
using ConstPtr = std::shared_ptr<const PointCloudColorHandlerGenericField<PointT>>;
353351

354-
/** \brief Constructor. */
355-
PointCloudColorHandlerGenericField (const std::string &field_name)
356-
: field_name_ (field_name)
357-
{
358-
capable_ = false;
359-
}
352+
/** \brief constructor */
353+
PointCloudColorHandlerGenericField(const PointCloudConstPtr& cloud,
354+
const std::string& field_name);
360355

361-
/** \brief Constructor. */
362-
PointCloudColorHandlerGenericField (const PointCloudConstPtr &cloud,
363-
const std::string &field_name)
364-
: PointCloudColorHandler<PointT> (cloud)
365-
, field_name_ (field_name)
366-
{
367-
setInputCloud (cloud);
368-
}
356+
/** \brief Set the input cloud to be used.
357+
* \param[in] cloud the input cloud to be used by the handler
358+
*/
359+
void setInputCloud(const PointCloudConstPtr& cloud);
369360

370-
/** \brief Get the name of the field used. */
371-
virtual std::string getFieldName () const { return (field_name_); }
361+
vtkSmartPointer<vtkDataArray> getColor() const override;
372362

373-
vtkSmartPointer<vtkDataArray>
374-
getColor () const override;
363+
protected:
375364

376-
/** \brief Set the input cloud to be used.
377-
* \param[in] cloud the input cloud to be used by the handler
378-
*/
379-
virtual void
380-
setInputCloud (const PointCloudConstPtr &cloud);
365+
/** \brief Name of the field used to create the color handler. */
366+
std::string field_name_;
381367

382-
protected:
383-
/** \brief Class getName method. */
384-
virtual std::string
385-
getName () const { return ("PointCloudColorHandlerGenericField"); }
368+
std::vector<pcl::PCLPointField> fields_;
386369

387-
private:
388-
using PointCloudColorHandler<PointT>::cloud_;
389-
using PointCloudColorHandler<PointT>::capable_;
390-
using PointCloudColorHandler<PointT>::field_idx_;
391-
using PointCloudColorHandler<PointT>::fields_;
370+
/** \brief Get the name of the field used. */
371+
std::string getFieldName() const override;
392372

393-
/** \brief Name of the field used to create the color handler. */
394-
std::string field_name_;
373+
/** \brief Class getName method. */
374+
std::string getName() const override
375+
{
376+
return ("PointCloudColorHandlerGenericField");
377+
}
395378
};
396379

397380

0 commit comments

Comments
 (0)