PCL系列——拼接两个点云

本文详细介绍了如何使用PCL库拼接不同点云的点与领域(包括点和法向量),提供了拼接操作的完整代码示例,并展示了拼接不同点云的点和领域的方法。通过实例演示了如何在VS2010中实现拼接功能,为三维重构、计算机视觉等领域提供技术支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

博客新址: http://blog.xuezhisd.top
邮箱:xuezhisd@126.com


PCL系列

说明

通过本教程,我们将会学会:

  • 如何拼接两个不同的点云的点,约束条件是两个数据集中的域的数量和类型必须相等。* 如何拼接两个不同点云的域,约束条件是连个数据集中的点的数量必须相等。

操作

  • 在VS2010 中新建一个文件 concatenate_clouds.cpp,然后将下面的代码复制到文件中。
  • 参照之前的文章,配置项目的属性。设置包含目录和库目录和附加依赖项。
#include <iostream> //标准输入输出流
#include <pcl/io/pcd_io.h> //PCL的PCD格式文件的输入输出头文件
#include <pcl/point_types.h> //PCL对各种格式的点的支持头文件
//比如,你的程序遇到调用栈用完了的威胁。你说,你到什么地方借内存,
//存放你的错误信息?cerr的目的,就是在你最需要它的紧急情况下,
//还能得到输出功能的支持。 缓冲区的目的,就是减少刷屏的次数

// 程序拼接A和B到C
int main (int argc, char** argv)
{
  if (argc != 2) // 需要一个参数 -f 或 -p
  {
    std::cerr << "please specify command line arg '-f' or '-p'" << std::endl;
    exit(0);
  }
	// 用于拼接不同点云的点的变量
  pcl::PointCloud<pcl::PointXYZ> cloud_a, cloud_b, cloud_c; //创建点云(不是指针),存储点坐标xyz
	// 用于拼接不同点云的域(点和法向量)的变量
  pcl::PointCloud<pcl::Normal> n_cloud_b; //创建点云,储存法向量
  pcl::PointCloud<pcl::PointNormal> p_n_cloud_c; //创建点云,储存点坐标和法向量

  //填充点云数据
  cloud_a.width  = 5; //设置宽度
  cloud_a.height = cloud_b.height = n_cloud_b.height = 1; //设置高度
  cloud_a.points.resize (cloud_a.width * cloud_a.height); //变形,无序
  if (strcmp(argv[1], "-p") == 0) //根据输入参数,设置点云
  {
    cloud_b.width  = 3; //cloud_b用于拼接不同点云的点
    cloud_b.points.resize (cloud_b.width * cloud_b.height);
  }
  else{
    n_cloud_b.width = 5; //n_cloud_b用于拼接不同点云的域
    n_cloud_b.points.resize (n_cloud_b.width * n_cloud_b.height);
  }
  for (size_t i = 0; i < cloud_a.points.size (); ++i) //设置cloud_a中点的坐标(随机数)
  {
    cloud_a.points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
    cloud_a.points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
    cloud_a.points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
  }
  if (strcmp(argv[1], "-p") == 0)
    for (size_t i = 0; i < cloud_b.points.size (); ++i) //设置cloud_b中点的坐标(随机数)
    {
      cloud_b.points[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
      cloud_b.points[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
      cloud_b.points[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
    }
  else // -f
    for (size_t i = 0; i < n_cloud_b.points.size (); ++i) //设置n_cloud_b中点的坐标(随机数)
    {
      n_cloud_b.points[i].normal[0] = 1024 * rand () / (RAND_MAX + 1.0f);
      n_cloud_b.points[i].normal[1] = 1024 * rand () / (RAND_MAX + 1.0f);
      n_cloud_b.points[i].normal[2] = 1024 * rand () / (RAND_MAX + 1.0f);
    }

	// 打印拼接用的数据 A和B
  std::cerr << "Cloud A: " << std::endl;
  for (size_t i = 0; i < cloud_a.points.size (); ++i) //打印cloud_a的点坐标信息
    std::cerr << "    " << cloud_a.points[i].x << " " << cloud_a.points[i].y << " " << cloud_a.points[i].z << std::endl;

  std::cerr << "Cloud B: " << std::endl; //打印Cloud B
  if (strcmp(argv[1], "-p") == 0) //若输入参数是-p,打印cloud_b;
    for (size_t i = 0; i < cloud_b.points.size (); ++i)
      std::cerr << "    " << cloud_b.points[i].x << " " << cloud_b.points[i].y << " " << cloud_b.points[i].z << std::endl;
  else //若-f,打印n_cloud_b
    for (size_t i = 0; i < n_cloud_b.points.size (); ++i)
      std::cerr << "    " << n_cloud_b.points[i].normal[0] << " " << n_cloud_b.points[i].normal[1] << " " << n_cloud_b.points[i].normal[2] << std::endl;

  //复制点云中的点
  if (strcmp(argv[1], "-p") == 0)
  {
    cloud_c  = cloud_a;
    cloud_c += cloud_b; // cloud_a + cloud_b 意思是cloud_c包含了a和b中的点,c的点数 = a的点数+b的点数
    std::cerr << "Cloud C: " << std::endl; ////打印Cloud C
    for (size_t i = 0; i < cloud_c.points.size (); ++i) //打印Cloud C
      std::cerr << "    " << cloud_c.points[i].x << " " << cloud_c.points[i].y << " " << cloud_c.points[i].z << " " << std::endl;
  }
  else //若输入参数是-f
  {
    pcl::concatenateFields (cloud_a, n_cloud_b, p_n_cloud_c); //拼接(点)cloud_a和(法向量)n_cloud_b到p_n_cloud_c
    std::cerr << "Cloud C: " << std::endl;
    for (size_t i = 0; i < p_n_cloud_c.points.size (); ++i) //打印Cloud C
      std::cerr << "    " <<
        p_n_cloud_c.points[i].x << " " << p_n_cloud_c.points[i].y << " " << p_n_cloud_c.points[i].z << " " <<
        p_n_cloud_c.points[i].normal[0] << " " << p_n_cloud_c.points[i].normal[1] << " " << p_n_cloud_c.points[i].normal[2] << std::endl;
  }

  return (0);
}
  • 重新生成项目。
  • 到改项目的Debug目录下,按住Shift,同时点击鼠标右键,在当前窗口打开CMD窗口。
  • 在CMD窗口中,输入命令concatenate_clouds.exe -p,执行拼接不同点云的点。结果如下图所示。
    这里写图片描述
  • 在CMD窗口中,输入命令concatenate_clouds.exe -f,执行拼接不同点云的域(比如点和法向量)。结果如下图所示。
    这里写图片描述

参考

### 点云数据自动拼接概述 点云数据的自动拼接是指通过算法和技术手段将来自不同视角或不同时刻获取的数据集无缝连接在一起的过程。这一过程对于创建完整的三维环境模型至关重要,尤其是在建筑测量、自动驾驶等领域有着广泛应用。 PCL(Point Cloud Library)是一个开源项目,它为处理大规模3D点云提供了丰富的功能集合[^2]。利用PCL库实现多帧点云数据的拼接相对简单直观,只需向函数传递各点的空间位置及其色彩信息,便能完成图像间的自动化对接操作。 #### 使用PCL进行点云拼接的具体流程 为了更好地理解如何运用PCL来进行点云之间的配准与融合,下面给出了一段Python代码片段作为演示: ```python import pcl from pcl.registration import icp, gicp, ndt def align_point_clouds(source_cloud, target_cloud): # 初始化ICP算法实例 reg = icp.ICP() # 执行迭代最近点算法来计算两片点云的最佳变换矩阵 converged, transf, estimate, fitness_score = reg.register(source_cloud.to_array(), target_cloud.to_array()) if not converged: raise Exception("Alignment failed.") transformed_source = source_cloud.transform(transf) return transformed_source, fitness_score ``` 上述程序展示了采用ICP(Iterative Closest Point)方法对源点云(`source_cloud`)和目标点云(`target_cloud`)实施刚体转换的技术方案;当两者成功对齐后,则返回已调整过的源点云以及适应度评分(fitness score),后者可用于评估此次配准的效果优劣程度。 #### 提高点云拼接效率的方法 针对大型场景下的海量点云数据处理需求,除了依赖高效的编程框架外,还可以采取一些策略进一步提升工作效率。例如,在自动驾驶领域中提到的一种基于视觉辅助的方式——即结合激光雷达(LiDAR)捕捉到的距离信息同相机拍摄所得的画面相结合,从而达到更精准快速的目标识别目的[^3]。这种方法不仅有助于减少人工干预次数,同时也提高了整体作业的速度与质量。 #### 数据验证的重要性 最后值得注意的是,在完成了初步的点云拼接之后,还需要对其进行严格的质量检验以确保最终产物的真实性和可靠性。为此,可以借助专门设计用于检测LiDAR扫描结果之间差异性的软件工具,如TopoDOT所提供的全局自动化运算偏差分析服务,该平台能够自动生成详细的误差分布图表供用户审查确认[^4]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值