/* * Software License Agreement (BSD License) * * Point Cloud Library (PCL) - www.pointclouds.org * Copyright (c) 2010-2011, Willow Garage, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the copyright holder(s) nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $Id$ * */ #pragma once #include #include #include #include #include #include namespace pcl { /** \brief @b PointRepresentation provides a set of methods for converting a point structs/object into an * n-dimensional vector. * \note This is an abstract class. Subclasses must set nr_dimensions_ to the appropriate value in the constructor * and provide an implementation of the pure virtual copyToFloatArray method. * \author Michael Dixon */ template class PointRepresentation { protected: /** \brief The number of dimensions in this point's vector (i.e. the "k" in "k-D") */ int nr_dimensions_ = 0; /** \brief A vector containing the rescale factor to apply to each dimension. */ std::vector alpha_; /** \brief Indicates whether this point representation is trivial. It is trivial if and only if the following * conditions hold: * - the relevant data consists only of float values * - the vectorize operation directly copies the first nr_dimensions_ elements of PointT to the out array * - sizeof(PointT) is a multiple of sizeof(float) * In short, a trivial point representation converts the input point to a float array that is the same as if * the point was reinterpret_casted to a float array of length nr_dimensions_ . This value says that this * representation can be trivial; it is only trivial if setRescaleValues() has not been set. */ bool trivial_ = false; public: using Ptr = shared_ptr >; using ConstPtr = shared_ptr >; /** \brief Empty destructor */ virtual ~PointRepresentation () = default; //TODO: check if copy and move constructors / assignment operators are needed /** \brief Copy point data from input point to a float array. This method must be overridden in all subclasses. * \param[in] p The input point * \param[out] out A pointer to a float array. */ virtual void copyToFloatArray (const PointT &p, float *out) const = 0; /** \brief Returns whether this point representation is trivial. It is trivial if and only if the following * conditions hold: * - the relevant data consists only of float values * - the vectorize operation directly copies the first nr_dimensions_ elements of PointT to the out array * - sizeof(PointT) is a multiple of sizeof(float) * In short, a trivial point representation converts the input point to a float array that is the same as if * the point was reinterpret_casted to a float array of length nr_dimensions_ . */ inline bool isTrivial() const { return trivial_ && alpha_.empty (); } /** \brief Verify that the input point is valid. * \param p The point to validate */ virtual bool isValid (const PointT &p) const { bool is_valid = true; if (trivial_) { const float* temp = reinterpret_cast(&p); for (int i = 0; i < nr_dimensions_; ++i) { if (!std::isfinite (temp[i])) { is_valid = false; break; } } } else { float *temp = new float[nr_dimensions_]; copyToFloatArray (p, temp); for (int i = 0; i < nr_dimensions_; ++i) { if (!std::isfinite (temp[i])) { is_valid = false; break; } } delete [] temp; } return (is_valid); } /** \brief Convert input point into a vector representation, rescaling by \a alpha. * \param[in] p the input point * \param[out] out The output vector. Can be of any type that implements the [] operator. */ template void vectorize (const PointT &p, OutputType &out) const { float *temp = new float[nr_dimensions_]; copyToFloatArray (p, temp); if (alpha_.empty ()) { for (int i = 0; i < nr_dimensions_; ++i) out[i] = temp[i]; } else { for (int i = 0; i < nr_dimensions_; ++i) out[i] = temp[i] * alpha_[i]; } delete [] temp; } /** \brief Set the rescale values to use when vectorizing points * \param[in] rescale_array The array/vector of rescale values. Can be of any type that implements the [] operator. */ void setRescaleValues (const float *rescale_array) { alpha_.resize (nr_dimensions_); std::copy_n(rescale_array, nr_dimensions_, alpha_.begin()); } /** \brief Return the number of dimensions in the point's vector representation. */ inline int getNumberOfDimensions () const { return (nr_dimensions_); } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** \brief @b DefaultPointRepresentation extends PointRepresentation to define default behavior for common point types. */ template class DefaultPointRepresentation : public PointRepresentation { using PointRepresentation ::nr_dimensions_; using PointRepresentation ::trivial_; public: // Boost shared pointers using Ptr = shared_ptr >; using ConstPtr = shared_ptr >; DefaultPointRepresentation () { // If point type is unknown, assume it's a struct/array of floats, and compute the number of dimensions nr_dimensions_ = sizeof (PointDefault) / sizeof (float); // Limit the default representation to the first 3 elements if (nr_dimensions_ > 3) nr_dimensions_ = 3; trivial_ = true; } ~DefaultPointRepresentation () {} inline Ptr makeShared () const { return (Ptr (new DefaultPointRepresentation (*this))); } void copyToFloatArray (const PointDefault &p, float * out) const override { // If point type is unknown, treat it as a struct/array of floats const float* ptr = reinterpret_cast (&p); std::copy_n(ptr, nr_dimensions_, out); } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** \brief @b DefaulFeatureRepresentation extends PointRepresentation and is intended to be used when defining the * default behavior for feature descriptor types (i.e., copy each element of each field into a float array). */ template class DefaultFeatureRepresentation : public PointRepresentation { protected: using PointRepresentation ::nr_dimensions_; private: struct IncrementFunctor { IncrementFunctor (int &n) : n_ (n) { n_ = 0; } template inline void operator () () { n_ += pcl::traits::datatype::size; } private: int &n_; }; struct NdCopyPointFunctor { using Pod = typename traits::POD::type; NdCopyPointFunctor (const PointDefault &p1, float * p2) : p1_ (reinterpret_cast(p1)), p2_ (p2), f_idx_ (0) { } template inline void operator() () { using FieldT = typename pcl::traits::datatype::type; const int NrDims = pcl::traits::datatype::size; Helper::copyPoint (p1_, p2_, f_idx_); } // Copy helper for scalar fields template struct Helper { static void copyPoint (const Pod &p1, float * p2, int &f_idx) { const std::uint8_t * data_ptr = reinterpret_cast (&p1) + pcl::traits::offset::value; p2[f_idx++] = *reinterpret_cast (data_ptr); } }; // Copy helper for array fields template struct Helper { static void copyPoint (const Pod &p1, float * p2, int &f_idx) { const std::uint8_t * data_ptr = reinterpret_cast (&p1) + pcl::traits::offset::value; int nr_dims = NrDims; const FieldT * array = reinterpret_cast (data_ptr); for (int i = 0; i < nr_dims; ++i) { p2[f_idx++] = array[i]; } } }; private: const Pod &p1_; float * p2_; int f_idx_; }; public: // Boost shared pointers using Ptr = shared_ptr>; using ConstPtr = shared_ptr>; using FieldList = typename pcl::traits::fieldList::type; DefaultFeatureRepresentation () { nr_dimensions_ = 0; // zero-out the nr_dimensions_ before it gets incremented pcl::for_each_type (IncrementFunctor (nr_dimensions_)); } inline Ptr makeShared () const { return (Ptr (new DefaultFeatureRepresentation (*this))); } void copyToFloatArray (const PointDefault &p, float * out) const override { pcl::for_each_type (NdCopyPointFunctor (p, out)); } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public PointRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 3; trivial_ = true; } void copyToFloatArray (const PointXYZ &p, float * out) const override { out[0] = p.x; out[1] = p.y; out[2] = p.z; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public PointRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 3; trivial_ = true; } void copyToFloatArray (const PointXYZI &p, float * out) const override { out[0] = p.x; out[1] = p.y; out[2] = p.z; // By default, p.intensity is not part of the PointXYZI vectorization } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public PointRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 3; trivial_ = true; } void copyToFloatArray (const PointNormal &p, float * out) const override { out[0] = p.x; out[1] = p.y; out[2] = p.z; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation {}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation {}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 4; trivial_ = true; } void copyToFloatArray (const PPFSignature &p, float * out) const override { out[0] = p.f1; out[1] = p.f2; out[2] = p.f3; out[3] = p.f4; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation {}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation {}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation {}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation {}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation {}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public PointRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 36; trivial_=false; } void copyToFloatArray (const Narf36 &p, float * out) const override { for (int i = 0; i < nr_dimensions_; ++i) out[i] = p.descriptor[i]; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public DefaultFeatureRepresentation {}; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public PointRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 1980; } void copyToFloatArray (const ShapeContext1980 &p, float * out) const override { for (int i = 0; i < nr_dimensions_; ++i) out[i] = p.descriptor[i]; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public PointRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 1960; } void copyToFloatArray (const UniqueShapeContext1960 &p, float * out) const override { for (int i = 0; i < nr_dimensions_; ++i) out[i] = p.descriptor[i]; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public PointRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 352; } void copyToFloatArray (const SHOT352 &p, float * out) const override { for (int i = 0; i < nr_dimensions_; ++i) out[i] = p.descriptor[i]; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template <> class DefaultPointRepresentation : public PointRepresentation { public: DefaultPointRepresentation () { nr_dimensions_ = 1344; } void copyToFloatArray (const SHOT1344 &p, float * out) const override { for (int i = 0; i < nr_dimensions_; ++i) out[i] = p.descriptor[i]; } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** \brief @b CustomPointRepresentation extends PointRepresentation to allow for sub-part selection on the point. */ template class CustomPointRepresentation : public PointRepresentation { using PointRepresentation ::nr_dimensions_; public: // Boost shared pointers using Ptr = shared_ptr >; using ConstPtr = shared_ptr >; /** \brief Constructor * \param[in] max_dim the maximum number of dimensions to use * \param[in] start_dim the starting dimension */ CustomPointRepresentation (const int max_dim = 3, const int start_dim = 0) : max_dim_(max_dim), start_dim_(start_dim) { // If point type is unknown, assume it's a struct/array of floats, and compute the number of dimensions nr_dimensions_ = static_cast (sizeof (PointDefault) / sizeof (float)) - start_dim_; // Limit the default representation to the first 3 elements if (nr_dimensions_ > max_dim_) nr_dimensions_ = max_dim_; } inline Ptr makeShared () const { return Ptr (new CustomPointRepresentation (*this)); } /** \brief Copy the point data into a float array * \param[in] p the input point * \param[out] out the resultant output array */ virtual void copyToFloatArray (const PointDefault &p, float *out) const { // If point type is unknown, treat it as a struct/array of floats const float *ptr = (reinterpret_cast (&p)) + start_dim_; std::copy_n(ptr, nr_dimensions_, out); } protected: /** \brief Use at most this many dimensions (i.e. the "k" in "k-D" is at most max_dim_) -- \note float fields are assumed */ int max_dim_; /** \brief Use dimensions only starting with this one (i.e. the "k" in "k-D" is = dim - start_dim_) -- \note float fields are assumed */ int start_dim_; }; }