pcl::PointCloud<PointT> uses std::vector internally as the container to store points, and applies the aligned allocator that Eigen inherited from std::allocator.
pcl::PointCloud<pcl::PointXYZ>::Ptrcloud (new pcl::PointCloud<pcl::PointXYZ>);
pcl::XX::Ptr uses shared_ptr internally as the smart pointer to keep track of the number of references and automatically manage the memory. The shared_ptr is a class essentially.
pcl::XX::Ptr cloud (new XX) takes the pointer created by new and passes to the constructor as an argument. The constructor also initializes other variables such as the one used to keep track of the number of references.
pcl::XX::Ptrcloud (new pcl::PointCloud<pcl::PointXYZ>);pcl::XX::Ptrcloud (new pcl::PointCloud<pcl::PointXYZ>() );
new Thing(); is explicit that you want a constructor called whereas new Thing; is taken to imply you don't mind if the constructor isn't called. See this reference page and this example.
For example, new Thing(); may initialize all values to 0, but new Thing; may not.
// correctpcl::PointCloud<pcl::PointXYZRGB> source_cloud_transformed;sac_ia.align (source_cloud_transformed);// incorrectpcl::PointCloud<pcl::PointXYZRGB>::Ptrsource_cloud_transformed (new pcl::PointCloud<pcl::PointXYZRGB>);sac_ia.align (source_cloud_transformed);// because align function takes in only raw pointers rather than smart pointers
In this example, new should not be used, since we want to leave the constructor to the align function. Otherwise the compilation error is the following.
error: no matching function for call to ‘pcl::SampleConsensusInitialAlignment<pcl::PointXYZRGB, pcl::PointXYZRGB, pcl::FPFHSignature33>::align(pcl::PointCloud<pcl::PointXYZRGB>::Ptr&)’
sac_ia.align (source_cloud_transformed);
no known conversion for argument 1 from ‘pcl::PointCloud<pcl::PointXYZRGB>::Ptr {aka boost::shared_ptr<pcl::PointCloud<pcl::PointXYZRGB> >}’ to ‘pcl::Registration<pcl::PointXYZRGB, pcl::PointXYZRGB, float>::PointCloudSource& {aka pcl::PointCloud<pcl::PointXYZRGB>&}’
The default precision used in FLANN is 0.8, according to the autotuned parameter settings here.
KdTree Point Representation
PCL uses the PointRepresentation class as a middle layer to convert various point types (including common ones as well as point types created for feature descriptors) into unified float vectors, to pass into the Kd-tree.
For example, the PointXYZRGBA point type can have 3 float fields (12 bytes) for 3D position, and 4 unit8 fields (4 bytes) for RGBA color channels. However, KdTree can only accept uniform vectors with all fields to be float, and will measure distance equally in each dimension. Therefore, there is need to adapt the two interfaces. By default, it will only take the first 3 dimensions/fields in the point type (the 3D position of the point).
If there is need to incorporate more fields into the kdtree search, then we need to implement a customized PointRepresentation class for this purpose. For example for the XYZRGB point type, how to map from uint8 to float, how to normalize the range, and how to assign weights to distance measure need to be considered carefully. In addition, it might be good to implement a customized distance measure as needed, because by default the kdtree will use L2_Simple for input float vectors.
// pcl/point_representation.htemplate <typenamePointT>classPointRepresentation {protected:int nr_dimensions_; std::vector<float> alpha_;bool trivial_;public:PointRepresentation () : nr_dimensions_ (0),alpha_ (0),trivial_ (false) {}virtualboolisValid (const PointT &p) consttemplate <typenameOutputType> voidvectorize (const PointT &p, OutputType &out) const};// extends PointRepresentation to define default behavior for common point types.template <typenamePointDefault>classDefaultPointRepresentation:publicPointRepresentation <PointDefault> {DefaultPointRepresentation () { nr_dimensions_ =sizeof (PointDefault) /sizeof (float);if (nr_dimensions_ >3) nr_dimensions_ =3; trivial_ =true; }};// 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 <typenamePointDefault>classDefaultFeatureRepresentation:publicPointRepresentation <PointDefault>// extends PointRepresentation to allow for sub-part selection on the point.template <typenamePointDefault>class CustomPointRepresentation : publicPointRepresentation <PointDefault>
In order to use customized point representation, we need to replace point_representation_ in KdTreeFLANN with our customized one. By default it is set to DefaultPointRepresentation initialized in its parent KdTree class.
By default, PCL has only compiled L2_Simple as the distance measure, and set a header guard PCL_NO_PRECOMPILE to avoid the recompilation of the hpp files.
// in file pcl/search/kdtree.h// ...#ifdefPCL_NO_PRECOMPILE#include<pcl/search/impl/kdtree.hpp>// will be skipped by default#else#definePCL_INSTANTIATE_KdTree(T) templateclass PCL_EXPORTS pcl::search::KdTree<T>;#endif
In this case, using distance measure other than the default L2_Simple will cause the following error.
undefined reference to `pcl::search::KdTree<pcl::PointXYZRGBNormal, pcl::KdTreeFLANN<pcl::PointXYZRGBNormal, flann::L1<float> > >::KdTree(bool)'
The solution is to enforce the compilation of the hpp file again.
// to use pcl::Search::KdTree with L1 distance#include<pcl/search/impl/kdtree.hpp>pcl::search::KdTree<PointT, pcl::KdTreeFLANN<PointT, flann::L1<float>>>::Ptr kdtree (new pcl::search::KdTree<PointT, pcl::KdTreeFLANN<PointT, flann::L1<float>>>);// to use pcl::KdTreeFLANN with L1 distance#include<pcl/kdtree/impl/kdtree_flann.hpp>boost::shared_ptr<pcl::KdTreeFLANN<FeatureT, flann::L1<float>>> feature_tree (new pcl::KdTreeFLANN<FeatureT, flann::L1<float>>);
Recall that one of the use cases of transformation matrices is to change the reference frame. Suppose that point p is fixed in space. Given p1​and p2​in frame 1 and frame 2 respectively, we have the relation p2​=T21​p1​, where T21​is the transformation matrix between frame 1 and frame 2 (in this case, indicating the configuration of frame 1 with respect to frame 2).
Note that when we transform a point cloud, we actually apply the transformation matrix to each and every point in the cloud (not the origin, not the reference frame). Therefore, it follows the aforementioned relation p2​=T21​p1​.
Accordingly in PCL, when we use pcl::transformPointCloud , the transformation matrix being used is actually T21​(not T12​), though with this matrix we can obtain the new point cloud 2 from point cloud 1. It is important to keep in mind this subscript, especially when subscript cancellation is needed in the following steps.