PCL:自定义点类型(合并PCL已有字段 | 添加新的字段)

Posted 没事就要敲代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PCL:自定义点类型(合并PCL已有字段 | 添加新的字段)相关的知识,希望对你有一定的参考价值。

1 为什么要自定义点云类型

PCL 附带了各种预定义的点类型,从 XYZ 数据到更复杂的 n 维直方图表示,如 PFH(点特征直方图)。为了涵盖我们可以想到的所有可能的情况,PCL定义了大量的点类型。有关完整列表,请参阅point_types.hpp

但是,在某些情况下,用户希望定义新类型,来满足自身的需求。

比如,PCL提供了Point XYZIPointXYZRGB,却没有提供同时包含坐标、颜色和强度的点类型;又比如,PCL没有提供有包含GPSTime的点类型。

这里,给出PCL自定义点类型的方法,可以根据实际需要,合并PCL已有的点类型(将PointXYZIPointXYZRGB 合并为 PointXYZRGBI ),或者自定义新的字段(GPSTime)作为新的点类型(PointXYZRGBIGpsTime

2 自定义点云类型的方法

2.1 合并已有的字段(以PointXYZRGBI为例)

描述:以合并XYZRGBIntensity为例,定义新的点类型 PointXYZRGBI

代码:

#include <pcl/io/pcd_io.h>

//-------------------------- 自定义点云类型 --------------------------
struct PointXYZRGBIGpsTime

	PCL_ADD_POINT4D;	//添加XYZ,此时相当于 PointXYZ
	PCL_ADD_RGB;		//添加RGB,此时相当于 PointXYZRGB
	PCL_ADD_INTENSITY;	//添加Intensity,此时相当于 PointXYZRGBI

	EIGEN_MAKE_ALIGNED_OPERATOR_NEW		//确保new操作符对齐操作

EIGEN_ALIGN16;//强制SSE内存对齐

//注册点类型宏(要包含所有添加的字段,否则无法正常使用未注册的字段)
POINT_CLOUD_REGISTER_POINT_STRUCT(PointXYZRGBIGpsTime,
									(float, x, x)
									(float, y, y)
									(float, z, z)
									(uint8_t, b, b)
									(uint8_t, g, g)
									(uint8_t, r, r)
									(float, rgb, rgb)
									(float, intensity, intensity)
)
//========================== 自定义点云类型 ==========================

using namespace std;

typedef PointXYZRGBIGpsTime PointT;

//测试函数
void test_XYZRGBI()

	pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
	cloud->width = 1000;
	cloud->height = 1;
	cloud->is_dense = true;
	cloud->points.resize(cloud->width*cloud->height);
	for (size_t i = 0; i < cloud->points.size(); i++)
	
		///XYZ
		cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
		///RGB
		cloud->points[i].r = (uint8_t)(i * 255 / cloud->points.size());
		cloud->points[i].g = (uint8_t)((cloud->points.size() - i) * 255 / cloud->points.size());
		cloud->points[i].b = (uint8_t)(i * 255 / cloud->points.size());
		///Intensity
		cloud->points[i].intensity = i;
	
	pcl::io::savePCDFileBinary("PointXYZRGBI.pcd", *cloud);


int main()

	test_XYZRGBI();

	return 0;

结果展示:

图1 点云展示

图2 PointXYZRGBI.pcd 文件头

注意:

  • 可以给合并的字段赋值,并且能够成功显示赋值后的点云,说明自定义点类型成功!
  • 可根据实际需要,合并任意PCL中已有的任意字段,构造出新的点类型。
  • 注册点类型宏时,要包含所有添加的字段,否则无法正常使用未注册的字段。

2.2 添加新的字段(以GpsTime为例)

描述:合并XYZ和RGB,并定义新的字段 GpsTime

代码:

#include <pcl/io/pcd_io.h>

//-------------------------- 自定义点云类型 --------------------------
struct PointXYZRGBGpsTime

	PCL_ADD_POINT4D;	//添加XYZ,此时相当于 PointXYZ
	PCL_ADD_RGB;		//添加RGB,此时相当于 PointXYZRGB
	
	double GpsTime;		//添加新的字段

	EIGEN_MAKE_ALIGNED_OPERATOR_NEW		//确保new操作符对齐操作

EIGEN_ALIGN16;//强制SSE内存对齐

//注册点类型宏(要包含所有添加的字段,否则无法正常使用未注册的字段)
POINT_CLOUD_REGISTER_POINT_STRUCT(PointXYZRGBGpsTime,
									(float, x, x)
									(float, y, y)
									(float, z, z)
									(uint8_t, b, b)
									(uint8_t, g, g)
									(uint8_t, r, r)
									(float, rgb, rgb)
									(double, GpsTime, GpsTime)
)
//========================== 自定义点云类型 ==========================

using namespace std;

typedef PointXYZRGBGpsTime PointT;

//测试函数
void test_XYZRGBGpsTime()

	pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
	cloud->width = 1000;
	cloud->height = 1;
	cloud->is_dense = true;
	cloud->points.resize(cloud->width*cloud->height);
	for (size_t i = 0; i < cloud->points.size(); i++)
	
		///XYZ
		cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
		///RGB
		cloud->points[i].r = (uint8_t)(i * 255 / cloud->points.size());
		cloud->points[i].g = (uint8_t)((cloud->points.size() - i) * 255 / cloud->points.size());
		cloud->points[i].b = (uint8_t)(i * 255 / cloud->points.size());
		///GpsTime
		cloud->points[i].GpsTime = i * 1.0;
	
	pcl::io::savePCDFileBinary("PointXYZRGBGpsTime.pcd", *cloud);


int main()

	test_XYZRGBGpsTime();

	return 0;

结果展示:

图1 点云展示

图2 PointXYZRGBGpsTime.pcd 文件头

注意:

  • 可以给新的字段赋值,并且能够成功显示赋值后的点云,说明自定义点类型成功!
  • 可根据实际需要,定义任意字段,构造出新的点类型。
  • 注册点类型宏时,要包含所有添加的字段,否则无法正常使用未注册的字段。

3 自定义点类型调用PCL模板类

从 PCL-1.7 开始,如果希望新的点类型和PCL提供的点类型那样,能够使用 PCL 中特定的模板类或者模板函数,需要先定义PCL_NO_PRECOMPILE,然后再包含任何 PCL 头文件以包含模板化算法。需要在所有头文件之前添加以下代码:

#define PCL_NO_PRECOMPILE

描述:以新的点类型调用PCL的体素下采样模板类为例。

代码:

#define PCL_NO_PRECOMPILE		//如果想使用PCL提供的模板类,比如体素下采样,需要添加此行代码。若不添加,生成代码时回报错。
#include <pcl/io/pcd_io.h>
#include<pcl/io/pcd_io.h>
#include<pcl/filters/voxel_grid.h>

//-------------------------- 自定义点云类型 --------------------------
struct PointXYZRGBGpsTime

	PCL_ADD_POINT4D;	//添加XYZ,此时相当于 PointXYZ
	PCL_ADD_RGB;		//添加RGB,此时相当于 PointXYZRGB
	
	double GpsTime;		//添加新的字段

	EIGEN_MAKE_ALIGNED_OPERATOR_NEW		//确保new操作符对齐操作

EIGEN_ALIGN16;//强制SSE内存对齐

//注册点类型宏(要包含所有添加的字段,否则无法正常使用未注册的字段)
POINT_CLOUD_REGISTER_POINT_STRUCT(PointXYZRGBGpsTime,
									(float, x, x)
									(float, y, y)
									(float, z, z)
									(uint8_t, b, b)
									(uint8_t, g, g)
									(uint8_t, r, r)
									(float, rgb, rgb)
									(double, GpsTime, GpsTime)
)
//========================== 自定义点云类型 ==========================

using namespace std;

typedef PointXYZRGBGpsTime PointT;

void test_XYZRGBGpsTime_sub()

	//----------------------------- 点云填充 -----------------------------
	pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
	cloud->width = 1000;
	cloud->height = 1;
	cloud->is_dense = true;
	cloud->points.resize(cloud->width*cloud->height);
	for (size_t i = 0; i < cloud->points.size(); i++)
	
		///XYZ
		cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
		cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
		///RGB
		cloud->points[i].r = (uint8_t)(i * 255 / cloud->points.size());
		cloud->points[i].g = (uint8_t)((cloud->points.size() - i) * 255 / cloud->points.size());
		cloud->points[i].b = (uint8_t)(i * 255 / cloud->points.size());
		///GpsTime
		cloud->points[i].GpsTime = i * 1.0;
	
	pcl::io::savePCDFileBinary("PointXYZRGBGpsTime.pcd", *cloud);
	//============================= 点云填充 ==============================

	//---------------------------- 体素下采样 -----------------------------
	pcl::VoxelGrid<PointT>vg;
	vg.setInputCloud(cloud);
	vg.setLeafSize(100, 100, 100);
	pcl::PointCloud<PointT>::Ptr cloud_sub(new pcl::PointCloud<PointT>);
	vg.filter(*cloud_sub);

	pcl::io::savePCDFileBinary("PointXYZRGBGpsTime_sub.pcd", *cloud_sub);
	//============================ 体素下采样 =============================


int main()

	test_XYZRGBGpsTime_sub();

	return 0;

结果展示:


参考链接:https://pcl.readthedocs.io/projects/tutorials/en/master/adding_custom_ptype.html#adding-custom-ptype

以上是关于PCL:自定义点类型(合并PCL已有字段 | 添加新的字段)的主要内容,如果未能解决你的问题,请参考以下文章

PCL:Visualizer 可视化❤️自定义颜色显示

PCL:点云赋色 | 自定义点云中任意一点的颜色

PCL:las点云转pcd点云(全字段转换:XYZRGBIntensityGpsTime)

为啥 PCL 条件过滤器返回相同的点云?

PCL:合并两个点云

点云合并pcl重载“+”