当前位置: 首页 > article >正文

PCL 用八叉树完成空间变化检测

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1八叉树构建与变化检测

2.1.2检测变化的点云

2.2完整代码

三、实现效果


PCL点云算法汇总及实战案例汇总的目录地址链接:

PCL点云算法与项目实战案例汇总(长期更新)


一、概述

        空间变化检测是点云处理中常见的任务之一,常用于监测不同时间点的点云数据集之间的变化。PCL 中可以通过 八叉树 来高效完成点云的空间变化检测。通过构建两组点云的八叉树,比较相同空间位置上的体素变化,快速检测出两组点云之间的空间变化。

1.1原理

        空间变化检测的核心思想是:将两组点云(例如不同时刻采集的数据)通过八叉树进行空间划分。每个八叉树节点(体素)代表空间中的一个区域。通过比较两个点云的八叉树节点,可以快速检测哪些体素中的点数或位置发生了变化,进而得出空间变化区域。

1.2实现步骤

  1. 读取两组点云数据。
  2. 使用 pcl::octree::OctreePointCloudChangeDetector 分别对两组点云进行八叉树构建。
  3. 比较两组点云的八叉树结构,检测变化的体素。
  4. 可视化检测结果,突出显示发生变化的区域。

1.3应用场景

  1. 监控变化:用于监测环境中物体的移动或消失。
  2. 场景重建:比较不同时间段的场景点云,检测物体位置变化。
  3. 质量检测:对比不同状态下的物体点云数据,发现差异。

二、代码实现

2.1关键函数

2.1.1八叉树构建与变化检测

        PCL 提供的 pcl::octree::OctreePointCloudChangeDetector 可以同时构建八叉树并完成空间变化检测。

#include <pcl/octree/octree_pointcloud_changedetector.h>

// 设置八叉树分辨率
float resolution = 0.05f;
pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ> octree(resolution);

// 构建八叉树并添加第一组点云数据
octree.setInputCloud(cloud1);  // cloud1 是第一组点云
octree.addPointsFromInputCloud();  // 添加第一组点云到八叉树

// 切换到第二组点云,重新构建八叉树并检测变化
octree.switchBuffers();  // 切换八叉树缓存,准备添加第二组点云
octree.setInputCloud(cloud2);  // cloud2 是第二组点云
octree.addPointsFromInputCloud();  // 添加第二组点云

2.1.2检测变化的点云

        使用 getPointIndicesFromNewVoxels 获取在两个点云之间发生变化的体素。

std::vector<int> newPointIdxVector;
octree.getPointIndicesFromNewVoxels(newPointIdxVector);  // 获取新体素中的点索引

2.2完整代码

#include <iostream>
#include <vector>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/octree/octree_pointcloud_changedetector.h>
#include <pcl/visualization/pcl_visualizer.h>

int main(int argc, char** argv)
{
    // -----------------------------读取两组点云数据---------------------------------
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud1(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud2(new pcl::PointCloud<pcl::PointXYZ>);

    if (pcl::io::loadPCDFile<pcl::PointXYZ>("cloud1.pcd", *cloud1) == -1 || 
        pcl::io::loadPCDFile<pcl::PointXYZ>("cloud2.pcd", *cloud2) == -1)
    {
        PCL_ERROR("Couldn't read the PCD files!\n");
        return -1;
    }

    // -----------------------------构建八叉树并检测变化---------------------------------
    float resolution = 0.05f;  // 八叉树的分辨率
    pcl::octree::OctreePointCloudChangeDetector<pcl::PointXYZ> octree(resolution);

    // 添加第一组点云到八叉树
    octree.setInputCloud(cloud1);
    octree.addPointsFromInputCloud();

    // 切换到第二组点云并检测变化
    octree.switchBuffers();  // 切换缓存
    octree.setInputCloud(cloud2);
    octree.addPointsFromInputCloud();  // 添加第二组点云

    // 获取变化的点索引
    std::vector<int> newPointIdxVector;
    octree.getPointIndicesFromNewVoxels(newPointIdxVector);

    // -----------------------------可视化变化结果---------------------------------
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Change Detection Viewer"));

    // 设置背景颜色为白色
    viewer->setBackgroundColor(1.0, 1.0, 1.0);  // 白色背景

    // 显示第一组点云(绿色)
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud1_color_handler(cloud1, 0, 255, 0);
    viewer->addPointCloud(cloud1, cloud1_color_handler, "cloud1");

    // 显示变化的点(红色)
    pcl::PointCloud<pcl::PointXYZ>::Ptr changed_points(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::copyPointCloud(*cloud2, newPointIdxVector, *changed_points);  // 将变化的点复制出来
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> changed_points_color_handler(changed_points, 255, 0, 0);
    viewer->addPointCloud(changed_points, changed_points_color_handler, "changed_points");

    // 设置点的大小
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "cloud1");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 4, "changed_points");

    // 添加坐标系
    viewer->addCoordinateSystem(1.0);
    viewer->initCameraParameters();

    // 可视化循环
    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
    }

    return 0;
}

三、实现效果


http://www.kler.cn/a/320055.html

相关文章:

  • 电商项目-基于ElasticSearch实现商品搜索功能(三)
  • 玩转随机数:用 JavaScript 掌控不可预测的魔力!
  • 基于go语言的驾考系统设计与实现
  • Java中对list数据进行手动分页(可直接复用版)
  • Java SpringBoot + Vue + Uniapp 集成JustAuth 最快实现多端三方登录!(QQ登录、微信登录、支付宝登录……)
  • C++并发编程之std::async的异常安全性
  • 【Android】页面启动耗时统计流程梳理
  • 操作系统知识4
  • Pr 入门系列之五:编辑 - 进阶篇(上)
  • ISP基本框架及算法介绍 ISP(Image Signal Processor)
  • css-functions伪类选择器系列一
  • SparkSQL-初识
  • 腾讯云平台实现本机远程连接和数据库mysql 8连接
  • 二十、微服务(基本概念与SOA的区别)
  • 安卓13删除下拉栏中的关机按钮版本2 android13删除下拉栏关机按钮
  • 决策树算法在机器学习中的应用
  • 【C语言】自定义类型——结构体
  • 腾讯云服务器配置免密登录
  • 问题记录:end value has mixed support, consider using flex-end instead
  • windows 驱动实例分析系列-COM驱动的I/O处理
  • C语言中的一些小知识(三)
  • uni-app vue3封装websocket,支持微信小程序
  • 《AI设计类工具系列之一——FigJam AI》
  • 深入理解及如何使用main函数参数
  • C++ VECTOR容器
  • 基于大数据可视化的化妆品推荐及数据分析系统