上周猛男快乐开发时遇到个bug,要用pcl的函数对自定义的点云进行处理。一起解决问题时遇到了很多问题,解决后整理出来分享给各位参考,以免踩一样的坑😊。文章中自定义的点我用PointT
来表示,自定义点云一般指的是pcl::PointCloud<PointXYZITNormalVelocity> cloud
。
(修这个bug真的烧了很多脑子🧠)

文章目录
1. 构造自定义PointT类型
为了涵盖日常开发中可能使用的点的类型,PCL中已经定义了很多种数据类型。因此在确定要构造自定义类型时,可以先去头文件pcl/impl/point_types.hpp里查看下是否有满足自己需求的点类型。
利用下面这个模板可以完成自定义PointT类型的定义,其中EIGEN_ALIGN16
和PCL_MAKE_ALIGNED_OPERATOR_NEW
切记要加上。PCL中大量利用SSE指令集来加速,所以内存对齐是很必要的。
struct EIGEN_ALIGN16 _PointT // EIGEN_ALIGN16表示16字节对齐,[必须项]
{
// 添加自定义点内部的字段信息 PCL_ADD_RGB;
// ...
// 必须项,确保内存正确对其,旧版本是EIGEN_MAKE_ALIGNED_OPERATOR_NEW
PCL_MAKE_ALIGNED_OPERATOR_NEW
};
struct EIGEN_ALIGN16 PointT: public _PointT
{
// 参考下面的方式补充构造参数,当输入参数是constexpr,那么产生的对象的所有成员都是constexpr。
// inline constexpr PointT (/*输入参数列表*/): /*初始化参数列表*/ {}
// 重载运算符 <<,这样就可以通过std::cout << point 来查看点的信息。
friend std::ostream& operator << (std::ostream& os, const PointT& p);
PCL_MAKE_ALIGNED_OPERATOR_NEW
};
// 点云注册,这里的字段名影响PointCloud<PointT>等相关函数的拷贝、保存或加载功能。
POINT_CLOUD_REGISTER_POINT_STRUCT (_PointT,
// 输入要注册的字段名,比如
// (float, x, x)
// (float, vx, vx)
)
POINT_CLOUD_REGISTER_POINT_WRAPPER(PointT, _PointT)
基于这个模板,我们来定义一个点PointXYZITNormalVelocity
,其包含位置、法向、强度、速度、时间信息。
- 第一步:定义基础类 _PointXYZITNormalVelocity。在添加字段时,参考如下规则:
- 每组信息,满足16字节的优先构建。比如位置,法向,速度,这些数据组。其他信息比如强度,时间等放在后面定义。
- 尽可能利用PCL提供的数据组构建方式。PCL中提供的数据组构建方式列举如下,一般16字节的数据组,都有个
float [4]
来填充,这个对应的字段名在定义的时候要记得防止冲突。切记:尽可能使用已有的,且不要尝试往字段的预留区域添加信息,比如位置信息PCL_ADD_POINT4D
这个,pcl在做点云运算时,可能会将第四个字节也就是data[3]这里赋值为0或1来加速运算。PCL_ADD_POINT4D
[16字节]:定义字段float x,y,z
。16字节对应的字段名为float data[4]
PCL_ADD_NORMAL4D
[16字节]:定义字段float normal_x, normal_y, normal_z
,或者可以通过字段float normal[3]
来访问。16字节对应的字段名为float data_n[4]
PCL_ADD_RGB
:定义字段uint8_t b, g, r, a
,或者可以通过字段uint32_t rgba
来访问。PCL_ADD_INTENSITY
:定义字段float intensity
。PCL_ADD_INTENSITY_8U
:定义字段uint8_t intensity
。PCL_ADD_INTENSITY_32U
:定义字段uint32_t intensity
。
基于上述信息,对应定义代码如下:
struct