当前文档不仅解释了如何增加自己的PointT点的类型,而且还说明了有什么 templated point types 在PCL,为什么它们的存在,and how are they exposed。如果你已经熟悉了这个信息,随意跳到文件的最后部分。
Adding your own custom PointT type
Why PointT types
What PointT types are available in PCL?
How are the point types exposed?
How to add a new PointT type
Example
注意:当前文档是仅适用于PCL 0.X和1.x
PCL有多种预定义的点类型,从SSE-aligned structures for XYZ data,到更复杂的n维直方图表示,如PFH(点特征直方图)。这些类型应足以支持PCL实现的所有算法和方法。然而,有时,用户希望定义一个新类型。本文介绍了步骤涉及了制定自己的自定义PointT类型,同时确保您的项目能够成功编译并运行。
PCL的PointT传统可以追溯到它是在ROS中开发的库。共识是,点云是一个复杂的N维结构需要能够代表不同类型的信息。然而,用户应该知道和了解需要什么类型的信息被传来传去,以使代码更易于调试,优化等。
一个例子是通过在XYZ数据的简单操作来表示。The most efficient way for SSE-enabled processors, is to store the 3 dimensions as floats, followed by an extra float for padding:
struct PointXYZ
{
float x;
float y;
float z;
float padding;
};
然而,在有些情况下,用户在一个嵌入式平台上编译PCL,加入额外的填充可以浪费内存。Therefore, a simpler PointXYZ structure without the last float could be used instead.
此外,如果应用程序需要其中包含XYZ三维数据,RGBA信息(颜色),并且估计在每个点处的表面法线一个P,它的定义与上述的结构区别不是很大。由于PCL所有算法是模板,除了结构定义所需的变化其他并没有其他什么变化。
为了覆盖我们能想到的所有可能的情况,因而我们定义在PCL点类型有点多。下面可能只是一个片段,更多的请参阅point_types.hpp完整列表。
这份名单是很重要的,因为定义自己的自定义类型之前,你需要了解why the existing types were created they way they were。另外,可能您要的类型可能已经为你定义。
PointXYZ - Members: float x, y, z;
这是最常用的数据类型中的一种,因为它仅表示三维XYZ信息。3个float类型的数据被填充,一个附加float类型数据是为了SSE对齐。The user can either access points[i].data[0] or points[i].x for accessing say, the x coordinate.
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
PointXYZI - Members: float x, y, z, intensity;
简单的XYZ +强度 点类型。在理想情况下,这4个部件将创建一个单结构,并且SSE对齐。However, because the majority of point operations will either set the last component of the data[4] array (from the xyz union) to 0 or 1 (for transformations), we cannot make intensity a member of the same structure, as its contents will be overwritten.例如,两个点之间的点积将他们的第4个组件设置为0,否则就没有任何的意义。
Therefore for SSE-alignment, we pad intensity with 3 extra floats. Inefficient in terms of storage, but good in terms of memory alignment.
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
struct
{
float intensity;
};
float data_c[4];
};
PointXYZRGBA - Members: float x, y, z; uint32_t rgba;
类似于PointXYZI,除了RGBA包含打包成一个无符号的32位整数的RGBA信息。由于union的声明,还可以通过名字分别访问颜色通道。
注意:The nested union declaration provides yet another way to look at the RGBA data–as a single precision floating point number. 这是基于历史原因做,不应该在新的代码中使用。
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
union
{
struct
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
};
float rgb;
};
uint32_t rgba;
};
PointXYZRGB - float x, y, z; uint32_t rgba;
Same as PointXYZRGBA.
PointXY - float x, y;
Simple 2D x-y point structure.
struct
{
float x;
float y;
};
InterestPoint - float x, y, z, strength;
Similar to PointXYZI, except strength contains a measure of the strength of the keypoint.
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
struct
{
float strength;
};
float data_c[4];
};
Normal - float normal[3], curvature;
另一个最常用的数据类型的,the Normal structure represents the surface normal at a given point,和(曲率的量度,其在相同的呼叫作为表面片的特征值之间的关系获得的 - 参见NormalEstimation类API获得更多信息)。
因为在表面法线进行操作在PCL是相当普遍,we pad the 3 components with a fourth one, in order to be SSE-aligned and computationally efficient. The user can either access points[i].data_n[0] or points[i].normal[0] or points[i].normal_x for accessing say, the first coordinate of the normal vector.同样,曲率不能被存储在相同的结构,因为它会通过对正常数据的操作所覆盖。
union
{
float data_n[4];
float normal[3];
struct
{
float normal_x;
float normal_y;
float normal_z;
};
}
union
{
struct
{
float curvature;
};
float data_c[4];
};
PointNormal - float x, y, z; float normal[3], curvature;
A point structure that holds XYZ data, together with 表面法向量和区率.
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
float data_n[4];
float normal[3];
struct
{
float normal_x;
float normal_y;
float normal_z;
};
};
union
{
struct
{
float curvature;
};
float data_c[4];
};
PointXYZRGBNormal - float x, y, z, normal[3], curvature; uint32_t rgba;
A point structure that holds XYZ data, and RGBA colors, together with surface normals and curvatures.
注意:除了这个名字,这一点确实类型包含alpha颜色通道。
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
float data_n[4];
float normal[3];
struct
{
float normal_x;
float normal_y;
float normal_z;
};
}
union
{
struct
{
union
{
union
{
struct
{
uint8_t b;
uint8_t g;
uint8_t r;
uint8_t a;
};
float rgb;
};
uint32_t rgba;
};
float curvature;
};
float data_c[4];
};
PointXYZINormal - float x, y, z, intensity, normal[3], curvature;
A point structure that holds XYZ data, and 强度值, together with 表面法向量 and 曲率.
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
float data_n[4];
float normal[3];
struct
{
float normal_x;
float normal_y;
float normal_z;
};
}
union
{
struct
{
float intensity;
float curvature;
};
float data_c[4];
};
PointWithRange - float x, y, z (union with float point[4]), range;
Similar to PointXYZI, except range contains a measure of the distance from the acquisition viewpoint to the point in the world.
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
struct
{
float range;
};
float data_c[4];
};
PointWithViewpoint - float x, y, z, vp_x, vp_y, vp_z;
Similar to PointXYZI, except vp_x, vp_y, and vp_z contain the acquisition viewpoint as a 3D point.
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
struct
{
float vp_x;
float vp_y;
float vp_z;
};
float data_c[4];
};
MomentInvariants - float j1, j2, j3;
Simple point type holding the 3个不变矩 at a surface patch. See MomentInvariantsEstimation for more information.
struct
{
float j1, j2, j3;
};
PrincipalRadiiRSD - float r_min, r_max;
Simple point type holding the 2 RSD radii at a surface patch. See RSDEstimation for more information.
struct
{
float r_min, r_max;
};
Boundary - uint8_t boundary_point;
Simple point type holding whether the point is lying on a surface boundary or not. See BoundaryEstimation for more information.
struct
{
uint8_t boundary_point;
};
PrincipalCurvatures - float principal_curvature[3], pc1, pc2;
Simple point type 对于给定点包含了其曲率. See PrincipalCurvaturesEstimation for more information.
struct
{
union
{
float principal_curvature[3];
struct
{
float principal_curvature_x;
float principal_curvature_y;
float principal_curvature_z;
};
};
float pc1;
float pc2;
};
PFHSignature125 - float pfh[125];
Simple point type holding the PFH (点特征直方图) of a given point. See PFHEstimation for more information.
struct
{
float histogram[125];
};
FPFHSignature33 - float fpfh[33];
Simple point type holding the FPFH (快速点特征直方图) of a given point. See FPFHEstimation for more information.
struct
{
float histogram[33];
};
VFHSignature308 - float vfh[308];
Simple point type holding the VFH (Viewpoint特征直方图) of a given point. See VFHEstimation for more information.
struct
{
float histogram[308];
};
Narf36 - float x, y, z, roll, pitch, yaw; float descriptor[36];
Simple point type holding the NARF (Normally Aligned Radius Feature正常校准半径功能) of a given point. See NARFEstimation for more information.
struct
{
float x, y, z, roll, pitch, yaw;
float descriptor[36];
};
BorderDescription - int x, y; BorderTraits traits;
Simple point type holding 对于给定点的边框类型. See BorderEstimation for more information.
struct
{
int x, y;
BorderTraits traits;
};
IntensityGradient - float gradient[3];
Simple point type holding 给定点的梯度强度. See IntensityGradientEstimation for more information.
struct
{
union
{
float gradient[3];
struct
{
float gradient_x;
float gradient_y;
float gradient_z;
};
};
};
Histogram - float histogram[N];
General purpose n-D histogram placeholder.
template
struct Histogram
{
float histogram[N];
};
PointWithScale - float x, y, z, scale;
Similar to PointXYZI, except scale contains the scale at which a certain point was considered for a geometric operation (e.g. the radius of the sphere for its nearest neighbors computation, the window size, etc).
struct
{
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
float scale;
};
PointSurfel - float x, y, z, normal[3], rgba, radius, confidence, curvature;
A complex point type containing XYZ data, 表面法向量, together with RGB 信息, 比例, 置信度, and 表面曲率.
union
{
float data[4];
struct
{
float x;
float y;
float z;
};
};
union
{
float data_n[4];
float normal[3];
struct
{
float normal_x;
float normal_y;
float normal_z;
};
};
union
{
struct
{
uint32_t rgba;
float radius;
float confidence;
float curvature;
};
float data_c[4];
};
由于其体积较大,而且它是一个模板库,其中包含在一个源文件中的许多PCL算法减慢了编译过程。在撰写本文的时候,大多数C ++编译器仍然没有得到很好的优化,以应对大套的模板文件,especially when optimizations (-O2 or -O3) are involved。
为了加快包括和链接PCL的过程,我们使用显式模板实例,by including all possible combinations in which all algorithms could be called using the already defined point types from PCL。这意味着,一旦PCL被编译为一个库,任何用户代码不需要编译模板代码,从而加快编译时间。he trick involves separating the templated implementations from the headers which forward declare our classes and methods, and resolving at link time. 下面是一个虚构的例子:
// foo.h
#ifndef PCL_FOO_
#define PCL_FOO_
template
class Foo
{
public:
void
compute (const pcl::PointCloud &input,
pcl::PointCloud &output);
}
#endif // PCL_FOO_
以上定义了头文件通常由所有的用户代码包括。正如我们所看到的,我们定义了方法和类,但我们还没有实现任何东西。
// impl/foo.hpp
#ifndef PCL_IMPL_FOO_
#define PCL_IMPL_FOO_
#include "foo.h"
template void
Foo::compute (const pcl::PointCloud &input,
pcl::PointCloud &output)
{
output = input;
}
#endif // PCL_IMPL_FOO_
The above defines the actual template implementation of the method Foo::compute. 这通常对于用户是隐藏的。
// foo.cpp
#include "pcl/point_types.h"
#include "pcl/impl/instantiate.hpp"
#include "foo.h"
#include "impl/foo.hpp"
// Instantiations of specific point types
PCL_INSTANTIATE(Foo, PCL_XYZ_POINT_TYPES));
最后,the above shows the way the explicit instantiations are done in PCL。The macro PCL_INSTANTIATE does nothing else but go over a given list of types and creates an explicit instantiation for each.From pcl/include/pcl/impl/instantiate.hpp:
// PCL_INSTANTIATE: call to instantiate template TEMPLATE for all
// POINT_TYPES
#define PCL_INSTANTIATE_IMPL(r, TEMPLATE, POINT_TYPE) \
BOOST_PP_CAT(PCL_INSTANTIATE_, TEMPLATE)(POINT_TYPE)
#define PCL_INSTANTIATE(TEMPLATE, POINT_TYPES) \
BOOST_PP_SEQ_FOR_EACH(PCL_INSTANTIATE_IMPL, TEMPLATE, POINT_TYPES);
Where PCL_XYZ_POINT_TYPES is (from pcl/include/pcl/impl/point_types.hpp):
// Define all point types that include XYZ data
#define PCL_XYZ_POINT_TYPES \
(pcl::PointXYZ) \
(pcl::PointXYZI) \
(pcl::PointXYZRGBA) \
(pcl::PointXYZRGB) \
(pcl::InterestPoint) \
(pcl::PointNormal) \
(pcl::PointXYZRGBNormal) \
(pcl::PointXYZINormal) \
(pcl::PointWithRange) \
(pcl::PointWithViewpoint) \
(pcl::PointWithScale)
Basically, if you only want to e显式实例Foo for pcl::PointXYZ, 不需要使用宏, 只需要像下面这样做即可:
// foo.cpp
#include "pcl/point_types.h"
#include "pcl/impl/instantiate.hpp"
#include "foo.h"
#include "impl/foo.hpp"
template class Foo;
注意:有关显式实例化的更多信息,请参阅C ++模板。
要添加新的点类型,你首先要定义它。例如:
struct MyPointType
{
float test;
};
Then, you need to make sure your code includes the template header implementation of the specific class/algorithm in PCL that you want your new point type MyPointType to work with. For example, say you want to use pcl::PassThrough. All you would have to do is:
#define PCL_NO_PRECOMPILE
#include
#include
// the rest of the code goes here
If your code is part of the library, which gets used by others, it might also make sense to try to use explicit instantiations for your MyPointType types, for any classes that you expose (from PCL our outside PCL).
从PCL-1.7开始,你需要定义PCL_NO_PRECOMPILE您包括任何PCL头之前,包括模板算法也是如此。
The following code片段 example creates a new point type that contains XYZ data (SSE padded), together with a test float.
#define PCL_NO_PRECOMPILE
#include
#include
#include
#include
struct MyPointType
{
PCL_ADD_POINT4D; // preferred way of adding a XYZ+padding
float test;
PCL_MAKE_ALIGNED_OPERATOR_NEW // make sure our new allocators are aligned
} EIGEN_ALIGN16; // enforce SSE padding for correct memory alignment
POINT_CLOUD_REGISTER_POINT_STRUCT (MyPointType, // here we assume a XYZ + "test" (as fields)
(float, x, x)
(float, y, y)
(float, z, z)
(float, test, test)
)
int
main (int argc, char** argv)
{
pcl::PointCloud cloud;
cloud.points.resize (2);
cloud.width = 2;
cloud.height = 1;
cloud.points[0].test = 1;
cloud.points[1].test = 2;
cloud.points[0].x = cloud.points[0].y = cloud.points[0].z = 0;
cloud.points[1].x = cloud.points[1].y = cloud.points[1].z = 3;
pcl::io::savePCDFile ("test.pcd", cloud);
}