PCL 求八叉树的体素中心

news2024/11/14 23:28:09

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

2.1.1 八叉树构建

2.1.2 获取体素中心

2.2完整代码

三、实现效果


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

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


一、概述

        在三维点云处理中,八叉树 是一种常用的数据结构,用来对三维空间进行递归划分。在 PCL 中,八叉树不仅可以用于搜索和变化检测,还可以用于计算每个体素(Voxel)的中心点,这对于空间划分、点云简化等应用十分有用。

1.1原理

        八叉树通过递归地将三维空间划分为多个子区域(体素),每个体素的边界由其最小和最大坐标定义,体素的中心是该最小和最大边界的中点。通过计算体素的中心点,可以获得该体素的空间位置,用于后续的点云处理。

1.2实现步骤

  1. 读取点云数据。
  2. 使用 pcl::octree::OctreePointCloud 创建八叉树并构建体素。
  3. 遍历八叉树中的每个体素,获取其最小和最大边界。
  4. 计算每个体素的中心点,存储并可视化体素中心点。

1.3应用场景

  1. 空间划分可视化:通过计算体素的中心点,展示空间的分布。
  2. 点云简化:使用体素中心点作为简化后的点云代表点。
  3. 邻域搜索:通过体素中心点快速找到空间中的目标区域。

二、代码实现

2.1关键函数

2.1.1 八叉树构建

        通过 pcl::octree::OctreePointCloud 构建八叉树,并根据点云数据生成体素。

#include <pcl/octree/octree_pointcloud.h>

// 设置八叉树分辨率
float resolution = 0.05f;  // 分辨率决定了体素的大小
pcl::octree::OctreePointCloud<pcl::PointXYZ> octree(resolution);

// 构建八叉树
octree.setInputCloud(cloud);  // cloud 是输入点云
octree.addPointsFromInputCloud();  // 生成八叉树

2.1.2 获取体素中心

        通过 getVoxelBounds 获取每个体素的最小和最大边界,并计算其中心点。

Eigen::Vector3f min_pt, max_pt;  // 用于存储体素的最小和最大边界
std::vector<Eigen::Vector3f> voxel_centers;  // 存储体素中心点

// 遍历八叉树的每个叶子节点(体素)
for (auto it = octree.leaf_begin(); it != octree.leaf_end(); ++it)
{
    octree.getVoxelBounds(it, min_pt, max_pt);  // 获取体素的边界

    // 计算体素中心点
    Eigen::Vector3f center = (min_pt + max_pt) / 2.0f;
    voxel_centers.push_back(center);  // 将中心点存储起来
}

2.2完整代码

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

// 封装的可视化函数
void visualizePointCloudsWithOctree(
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud,  // 原始点云
    pcl::PointCloud<pcl::PointXYZ>::Ptr voxel_center_cloud)  // 体素中心点云
{
    // 创建可视化窗口
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Dual PointCloud Viewer"));

    // 设置视口1,显示原始点云
    int vp_1;
    viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp_1);  // 左侧窗口
    viewer->setBackgroundColor(1.0, 1.0, 1.0, vp_1);  // 白色背景
    viewer->addText("Original PointCloud", 10, 10, "vp1_text", vp_1);  // 标题
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color_handler(cloud, 0, 255, 0);  // 绿色
    viewer->addPointCloud(cloud, cloud_color_handler, "original_cloud", vp_1);

    // 设置视口2,显示体素中心点云
    int vp_2;
    viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp_2);  // 右侧窗口
    viewer->setBackgroundColor(1.0, 1.0, 1.0, vp_2);  // 白色背景
    viewer->addText("Voxel Center PointCloud", 10, 10, "vp2_text", vp_2);  // 标题
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> voxel_center_color_handler(voxel_center_cloud, 255, 0, 0);  // 红色
    viewer->addPointCloud(voxel_center_cloud, voxel_center_color_handler, "voxel_center_cloud", vp_2);

    // 设置点的大小
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "original_cloud", vp_1);
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 4, "voxel_center_cloud", vp_2);

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

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

int main(int argc, char** argv)
{
    // -----------------------------读取点云数据---------------------------------
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("bunny.pcd", *cloud) == -1)
    {
        PCL_ERROR("Couldn't read the PCD file!\n");
        return -1;
    }

    // -----------------------------构建八叉树---------------------------------
    float resolution = 0.01f;  // 八叉树分辨率
    pcl::octree::OctreePointCloud<pcl::PointXYZ> octree(resolution);

    octree.setInputCloud(cloud);  // 设置输入点云
    octree.addPointsFromInputCloud();  // 生成八叉树

    // -----------------------------计算体素中心---------------------------------
    Eigen::Vector3f min_pt, max_pt;  // 用于存储体素的最小和最大边界
    pcl::PointCloud<pcl::PointXYZ>::Ptr voxel_center_cloud(new pcl::PointCloud<pcl::PointXYZ>);  // 存储体素中心点云

    // 遍历八叉树的每个叶子节点(体素)
    for (auto it = octree.leaf_begin(); it != octree.leaf_end(); ++it)
    {
        octree.getVoxelBounds(it, min_pt, max_pt);  // 获取体素的边界
        pcl::PointXYZ point;
        point.x = (min_pt.x() + max_pt.x()) / 2.0f;  // 计算中心点
        point.y = (min_pt.y() + max_pt.y()) / 2.0f;
        point.z = (min_pt.z() + max_pt.z()) / 2.0f;
        voxel_center_cloud->points.push_back(point);  // 将中心点添加到点云
    }

    voxel_center_cloud->width = voxel_center_cloud->points.size();
    voxel_center_cloud->height = 1;
    voxel_center_cloud->is_dense = true;

    // -----------------------------可视化---------------------------------
    visualizePointCloudsWithOctree(cloud, voxel_center_cloud);

    return 0;
}

三、实现效果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2165827.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

注意力机制篇 | YOLOv8改进之在C2f模块引入EffectiveSE注意力模块 | 基于SE注意力

前言:Hello大家好,我是小哥谈。EffectiveSE(Effective Squeeze-Excitation) 是一种改进的通道注意力模块,其目的是在保持模型性能的同时减少计算复杂性和信息丢失。它基于原始的 Squeeze-Excitation (SE) 模块,但通过一些关键的改进来提高效率。🌈 目录 🚀1.基…

前端——flex布局

flex布局——弹性布局 传统布局: 浮动 定位 行内块等 1. flex布局 方法简单 不需要计算 能自动分配父级里面的子元素排版 对齐方式等等 >flex布局 可以适应不同屏幕布局 2. flex布局使用 - 给父级盒子 display: flex 开启弹性盒模型 - 子元素就会默…

栈的基本概念和及具体实现

今天给大家介绍一下栈的基本概念及实现&#xff01;话不多说&#xff0c;立即开始&#xff01; 1.栈的概念&#xff1a; 一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈 顶&#xff0c;另一端称为栈底。栈中的…

计算机网络--TCP、UDP抓包分析实验

计算机网络实验 目录 实验目的 实验环境 实验原理 1、UDP协议 2、TCP协议 实验具体步骤 实验目的 1、掌握使用wireshark工具对UDP协议进行抓包分析的方法&#xff0c;掌握UDP协议的报文格式&#xff0c;掌握UDP协议校验和的计算方法&#xff0c;理解UDP协议的优缺点&am…

vant van-pull-refresh + van-list实现list列表支持搜索和下拉刷新

1 介绍 在使用 van-pull-refresh van-list实现list列表下拉刷新时遇到几个问题在这里进行一个总结。 2 出现的问题 问题一&#xff1a;当van-pull-refresh van-list组合使用时&#xff0c;下拉刷新会调用两个加载图标。 解答&#xff1a;去除van-pull-refresh加载图标&…

leetcode-189:轮转数组

给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4…

快讯:腾讯轻量服务器四周年,最低一折续费,还有免费升配

最近腾讯云轻量服务器四周年庆开始了&#xff0c;免费升级配置&#xff0c;续费服务器最低一折。 最低一折续费&#xff1a; 持有多久的轻量服务器决定续费几折&#xff0c;已经持有四年就是一折&#xff0c;三年1.5折以此类推。 免费升级配置&#xff1a; 2-4-5免费升级到…

String类常用的方法

源代码&#xff1a; 输出结果&#xff1a;

Linux 之 logrotate 【日志分割】

简介 logrotate 是一个用于管理日志文件的工具。它可以自动对日志文件进行轮转、压缩、删除等操作&#xff0c;以防止日志文件无限增长占用过多磁盘空间。logrotate 通常作为一个守护进程定期运行&#xff0c;也可以通过 cron 任务来调度执行 工作原理 按照配置文件中的规则…

【Mysql多数据源实现读写分离的几种方案】

文章目录 一.什么是MySQL 读写分离二.读写分离的几种实现方式(手动控制)1.基于Spring下的AbstractRoutingDataSource1.yml2.Controller3.Service实现4.Mapper层5.定义多数据源6.继承Spring的抽象路由数据源抽象类&#xff0c;重写相关逻辑7. 自定义注解WR&#xff0c;用于指定当…

客户端数JSON据库SQL操作功能实现代码-———未来之窗行业应用跨平台架构

一、前端json结构化查询优点 以下是前端本地化查询的一些优点&#xff1a; 1. 快速响应&#xff1a;无需通过网络请求从服务器获取数据&#xff0c;查询结果能够立即返回&#xff0c;提供了几乎零延迟的用户体验&#xff0c;使应用更加流畅和响应迅速。 2. 离线可用性&#x…

9.4 Linux_I/O_访问目录、文件属性

访问目录 1、打开关闭目录 打开目录函数声明如下&#xff1a; //1.直接打开指定路径的目录文件 DIR *opendir(const char *name); //2.先用open打开目录文件&#xff0c;再用该函数访问目录文件 DIR *fdopendir(int fd); 返回值&#xff1a;成功返回指向打开的目录文件的结…

ELK-05-skywalking监控SpringCloud服务日志

文章目录 前言一、引入依赖二、增加日志配置文件三、打印日志四、skywalking网页查询链路五、日志收集5.1 修改logback-spring.xml5.2 重启SpringCloud服务并请求test接口5.3 查看skywalking网页的Log 总结 前言 基于上一章节&#xff0c;现在使用skywalkin监控SpringCloud服务…

JWT令牌技术介绍及使用

一、JWT介绍 JWT是JSON Web Token的缩写&#xff0c;即JSON Web令牌&#xff0c;是一种自包含令牌。 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。 JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息&#xff0c;以便于从资源服务…

D. Determine Winning Islands in Race (cf div2,dp、图论最短路)

D. Determine Winning Islands in Race 思路: bfs找到E到达每个点的最短时间t[i]。 如果E要超过B&#xff0c;那么一定要借助辅助桥&#xff0c;从而获胜。 假设有u->v的辅助桥&#xff0c;E能通过这个桥超过B的条件是: s>u 且 t[v] < v-s 即 s的取值要为[u1,v-t[v]-…

C++核心编程和桌面应用开发 第七天(运算符重载 智能指针)

目录 1.数组类 2.运算符重载 2.1加号运算符 2.1.1成员函数实现 2.1.2全局函数实现 2.1.3加号重载 2.2左移运算符 2.3递增运算符 2.4指针运算符 2.5赋值运算符 1.数组类 //默认构造函数 MyArray::MyArray() {m_Size 0;m_Capacity 100;pAddress new int[m_Capacity]…

【有啥问啥】深度解析迁移学习(Transfer Learning)

深度解析迁移学习&#xff08;Transfer Learning&#xff09; 在机器学习领域&#xff0c;迁移学习&#xff08;Transfer Learning&#xff09;作为一种强大的技术&#xff0c;正广泛应用于各种实际场景中。本文将详细解析迁移学习的基本概念、原理、分类、应用场景以及具体实…

vue3中storeToRefs让store中的结构出来的数据也能变成响应式

1、首先需要安装pinia 具体安装和使用教程参考 2、创建 src/stores/counter.js 文件&#xff0c;其内容如下&#xff1a; import {defineStore} from "pinia"; import {ref} from "vue";export const useCounterStore defineStore(counter,()>{const…

C语言程序设计题目十九:编写一万年历系统

文章目录 题目十九&#xff1a;编写一万年历系统calendar.hcalendar.ctest.c 题目十九&#xff1a;编写一万年历系统 要求&#xff1a; 模仿现实中的挂历&#xff0c;显示当前月的每一天及星期几&#xff0c;当系统日期变为下一个月时&#xff0c;自动翻页到下一个月。 calend…

【第3期】INFINI Easysearch 免费认证培训开放报名

探索 Easysearch 的无限可能&#xff0c;与 INFINI Labs 共赴搜索技术前沿&#xff01; 随着数字化转型的加速&#xff0c;搜索技术已成为企业数据洞察的核心。INFINI Labs 作为搜索创新技术的引领者&#xff0c;诚邀所有对 Easysearch 搜索引擎感兴趣的开发者、技术爱好者及合…