3.PCL点云合并
文章目录
- 概念
- 第一种拼接方式:点数量叠加(点云字段与维度一致)
- 第二种拼接方式:字段维度叠加(点云数量一致)
- 官方示例
概念
第一种拼接方式:点数量叠加(点云字段与维度一致)
场景描述:
- 两个点云具有相同的字段结构(比如都是 PointXYZ 类型),但点的数量不同。
- 合并方式是将两个点云中的点逐个点地拼接在一起,最终得到一个点数更多、结构一致的新点云。
示例: - 点云 A:包含 100 个点,每个点的结构是 PointXYZ(x, y, z)。
- 点云 B:包含 200 个点,每个点的结构也是 PointXYZ。
- 合并后点云 C:包含 300 个点,结构仍然是 PointXYZ。
📌 应用场景:
多帧点云数据的拼接(如激光雷达在不同时间扫描的点云)。
多视角点云合并(如多个角度扫描的点云合并成一个更完整的模型)。
数据增强:将多个样本点云合并成一个大的数据集。
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_a (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_b (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ> cloud_c;
cloud_c = *cloud_a + *cloud_b; // 合并
第二种拼接方式:字段维度叠加(点云数量一致)
场景描述:
- 两个点云具有相同的点数量,但字段结构不同。
- 合并方式是将每个点的字段信息合并到一起,形成一个新的点类型。
示例:
- 点云 A:包含 100 个点,每个点的结构是 PointXYZ(x, y, z)。
- 点云 B:包含 100 个点,每个点的结构是 PointRGB(r, g, b)。
- 合并后点云 C:包含 100 个点,每个点的结构是 PointXYZRGB(x, y, z, r, g, b)。
📌 应用场景:
将几何信息(如位置)与颜色信息(RGB)融合。
将法线(Normal)信息、强度(Intensity)、类别标签(Label)等附加到点云中。
多模态数据融合,比如将深度图和颜色图对应的点云进行合并。
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_a (new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointRGB>::Ptr cloud_b (new pcl::PointCloud<pcl::PointRGB>);
pcl::PointCloud<pcl::PointXYZRGB> cloud_c;
for (size_t i = 0; i < cloud_a->size(); ++i) {pcl::PointXYZRGB point;point.x = cloud_a->points[i].x;point.y = cloud_a->points[i].y;point.z = cloud_a->points[i].z;point.r = cloud_b->points[i].r;point.g = cloud_b->points[i].g;point.b = cloud_b->points[i].b;cloud_c.push_back(point);
}
官方示例
#include <iostream>
#include <pcl/io/pcd_io.h> // PCL 的点云文件读写功能
#include <pcl/point_types.h> // PCL 的点类型定义(如 PointXYZ、Normal、PointNormal 等)int main(int argc, char** argv)
{// 检查命令行参数是否正确,必须传入 "-f" 或 "-p"if (argc != 2){std::cerr << "please specify command line arg '-f' or '-p'" << std::endl;exit(0);}// 定义三个点云对象:// cloud_a:PointXYZ 类型,用于存储点坐标// cloud_b:同上,用于拼接// cloud_c:结果点云pcl::PointCloud<pcl::PointXYZ> cloud_a, cloud_b, cloud_c;// 定义法线点云 n_cloud_bpcl::PointCloud<pcl::Normal> n_cloud_b;// 定义带法线的点云 p_n_cloud_cpcl::PointCloud<pcl::PointNormal> p_n_cloud_c;// 填充点云数据// 设置 cloud_a 的宽度为 5,高度为 1(即 5 个点)cloud_a.width = 5;cloud_a.height = cloud_b.height = n_cloud_b.height = 1; // 所有点云为单行排列(非结构化点云)// 调整 cloud_a 的大小cloud_a.points.resize(cloud_a.width * cloud_a.height);// 根据命令行参数决定填充 cloud_b 或 n_cloud_bif (strcmp(argv[1], "-p") == 0){// "-p" 模式:cloud_b 宽度为 3,即 3 个点cloud_b.width = 3;cloud_b.points.resize(cloud_b.width * cloud_b.height);}else{// "-f" 模式:n_cloud_b 宽度为 5,即 5 个法线点n_cloud_b.width = 5;n_cloud_b.points.resize(n_cloud_b.width * n_cloud_b.height);}// 初始化 cloud_a 中的点,随机生成 x, y, z 坐标for (std::size_t i = 0; i < cloud_a.size(); ++i){cloud_a[i].x = 1024 * rand() / (RAND_MAX + 1.0f);cloud_a[i].y = 1024 * rand() / (RAND_MAX + 1.0f);cloud_a[i].z = 1024 * rand() / (RAND_MAX + 1.0f);}// 根据参数初始化 cloud_b 或 n_cloud_bif (strcmp(argv[1], "-p") == 0){// "-p" 模式:填充 cloud_b 的点数据(PointXYZ)for (std::size_t i = 0; i < cloud_b.size(); ++i){cloud_b[i].x = 1024 * rand() / (RAND_MAX + 1.0f);cloud_b[i].y = 1024 * rand() / (RAND_MAX + 1.0f);cloud_b[i].z = 1024 * rand() / (RAND_MAX + 1.0f);}}else{// "-f" 模式:填充 n_cloud_b 的法线数据for (std::size_t i = 0; i < n_cloud_b.size(); ++i){n_cloud_b[i].normal[0] = 1024 * rand() / (RAND_MAX + 1.0f);n_cloud_b[i].normal[1] = 1024 * rand() / (RAND_MAX + 1.0f);n_cloud_b[i].normal[2] = 1024 * rand() / (RAND_MAX + 1.0f);}}// 输出 cloud_a 的内容std::cerr << "Cloud A: " << std::endl;for (std::size_t i = 0; i < cloud_a.size(); ++i)std::cerr << " " << cloud_a[i].x << " " << cloud_a[i].y << " " << cloud_a[i].z << std::endl;// 输出 cloud_b 或 n_cloud_b 的内容std::cerr << "Cloud B: " << std::endl;if (strcmp(argv[1], "-p") == 0){for (std::size_t i = 0; i < cloud_b.size(); ++i)std::cerr << " " << cloud_b[i].x << " " << cloud_b[i].y << " " << cloud_b[i].z << std::endl;}else{for (std::size_t i = 0; i < n_cloud_b.size(); ++i)std::cerr << " " << n_cloud_b[i].normal[0] << " " << n_cloud_b[i].normal[1] << " " << n_cloud_b[i].normal[2] << std::endl;}// 开始点云拼接操作if (strcmp(argv[1], "-p") == 0){// "-p" 模式:数量叠加(点云字段一致,数量不同)cloud_c = cloud_a; // 将 cloud_a 赋值给 cloud_ccloud_c += cloud_b; // 将 cloud_b 拼接到 cloud_c 后面(点数增加)// 输出合并后的点云 cloud_cstd::cerr << "Cloud C (Concatenated Points): " << std::endl;for (std::size_t i = 0; i < cloud_c.size(); ++i)std::cerr << " " << cloud_c[i].x << " " << cloud_c[i].y << " " << cloud_c[i].z << std::endl;}else{// "-f" 模式:字段叠加(点云数量一致,字段不同)// 使用 PCL 提供的 concatenateFields 函数进行字段拼接pcl::concatenateFields(cloud_a, n_cloud_b, p_n_cloud_c);// 输出合并后的点云 p_n_cloud_c(包含坐标和法线)std::cerr << "Cloud C (Concatenated Fields): " << std::endl;for (std::size_t i = 0; i < p_n_cloud_c.size(); ++i)std::cerr << " "<< p_n_cloud_c[i].x << " " << p_n_cloud_c[i].y << " " << p_n_cloud_c[i].z << " "<< p_n_cloud_c[i].normal[0] << " " << p_n_cloud_c[i].normal[1] << " " << p_n_cloud_c[i].normal[2]<< std::endl;}return 0;
}