Autoware中的点云3D聚类算法,保姆级算法阅读注释,一看就懂,非常详细!

news2025/1/11 15:05:14

综述

五大模块,看完等于点云入门~(dog)
在这里插入图片描述

实际步骤

  1. 输入激光雷达获得的点云

    1. pcl::PointCloud<pcl::PointXYZ>::Ptr

      header:
      	seq:序列长度
          stamp:获取点云的时刻
          frame_id:坐标系名称
      points:保存点云的容器,类型为std::vector
      width:类型为uint32_t,表示点云的宽度,即一行点云的数量
      height:类型为uint32_t,若为1,代表无序点云,则width代表点云数量;大于1,则有序
      is_dense:bool类型,若点云中数据是有限的,则为true;否则为false
      
  2. 剔除距离激光雷达过近的点云(水平方向,XY平面,360度剔除)

    1. 通过点云中(x,y)坐标到原点的距离判断当前点云是否满足要求
  3. 对点云进行体素下采样操作

    1. 点云体素下采样代码

      pcl::VoxelGrid<pcl::PointXYZ> sor;   //设置下采样滤波器
      sor.setInputCloud(in_cloud_ptr);     //输入点云数据(指针)
      sor.LeafSize((float) in_leaf_size, (float) in_leaf_size, (float) in_leaf_size);                      //设置体素栅格大小(长、宽、高)
      sor.filter(*out_cloud_ptr);         //设置输出点云容器(非指针)
      
    2. 操作步骤

      1. 绘制体素包围盒,包裹住所有点云
        • 使用AABB包围盒,即根据x、y、z三轴的最大值和最小值创建包围盒
      2. 在包围盒内生成体素栅格,栅格大小作者设定,单位是米
      3. 计算每个栅格中包含所有点云的质心,并输出。即每个栅格只输出一个点云,大幅度缩减了点云数量。
      4. 实现点云体素下采样
  4. 剔除距离激光雷达过低或过高的点云(垂直方向,Z轴,360度剔除)

    1. 通过点云的Z坐标判断当前点云是否满足要求,通常取 -1.3 <= Z <= 0.5
    2. 激光雷达的安装高度已足够高,再加半米足以检测到大多数车辆
  5. 剔除距离激光雷达左右两侧过远的点云

    1. 通过点云的Y坐标是否满足限制条件判断,通常取 -1.5 <= Y <= 1.5

    2. 应用函数pcl::PointIndices::Ptrpcl::ExtractIndices<pcl::PointXYZ>

      • pcl:PointIndices::Ptr 保存点云索引,用于后续点云查找、提取、删除等操作

        • 普通数组也可以保存点云索引,但是无法应用pcl库中其他函数直接对索引进行处理,所以还是需要利用pcl::PointIndices::Ptr记录点云索引

        • 该函数最主要的部分indices成员变量,类型为std::vector

          pcl::PointIndices::Ptr far_indices(new pcl::PointIndices);
          far_indices->indices.push_back((unsigned int)index);
          
      • pcl::ExtractIndices 根据作者的设置,输出是否位于索引内的点云 ——>滤波器

        pcl::ExtractIndices<pcl::PointXYZ> extract;
        extract.setInputCloud(in_cloud_ptr);    //输入点云指针
        extract.setIndices(far_indices);        //输入待处理的点云索引
        
        //设置为true,则去掉索引值代表的点云再进行输出;设置为false,则直接输出索引值代表的点云
        extract.setNegative(true);              
        extract.filter(*out_cloud_ptr);        //输出点云(非指针)
        
  6. 进行地面点云滤波(去除地面点云)

    1. 总体流程

      设置RANSAC算法参数
      地面点云分割
      获取地面点云索引
      根据地面点云索引去除点云
      实现地面点云滤波
    2. 重要部分:地面点云分割——>几何分割方法(RANSAC:随机采样一致算法),

      1. 算法步骤原理如下:

        1. 随机选择点云集合中的三个点,拟合平面模型
        2. 判断该平面模型法线与Z轴的夹角是否小于0.1弧度。若否,则不考虑,返回步骤1
        3. 计算其他点云到该平面模型的距离
          1. 若距离小于0.2(通常选取),则认定该点云是平面模型的内点,并统计内点个数
        4. 重复迭代,选择内点个数最多的平面模型作为最佳模型,并记录平面模型的点云索引
        5. 通过点云索引去掉地面点云,完成点云滤波
      2. 代码设置函数 为何设置迭代次数为100,链接:

        pcl::SACSegmentation<pcl::PointXYZ> seg;   //pcl库中自带的采样一致分割算法,即几何分割算法
        pcl::PointIndices::Ptr inliers(new Pcl::PointIndices); //创建点云索引指针
        pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients); //创建模型参数
        
        seg.setOptimizaCoefficients(true);      //进行参数优化
        
        //============对要分割的平面模型进行设置============
        seg.setModelType(pcl::SACMODEL_PERPENDICULAR_PLANE); //设置分割模型,此时设置的分割模型为垂直于轴线的平面模型
        seg.setAxis(Eigen::Vector3f(0 ,0, 1));  //设置分割模型垂直的轴线。因此要对地面进行滤波,所以此处平面模型设置为垂直于Z轴
        seg.setEpsAngle(0.1);                   //允许平面模型法线与Z轴的最大偏差为0.1弧度,也就是说大于0.1弧度的平面模型不考虑
        //==============================================
        
        seg.setMethodType(pcl::SAC_RANSAC);     //设置分割方法为随机采样一致算法
        seg.setMaxIteration(100);               //设置最大迭代次数为100
        seg.setDistanceThreshold(0.2);          //设置点云到平面的最大距离阈值。若小于该阈值,则认定为内点
        seg.setOptimizeCoefficients(true);      //再次进行参数优化
        seg.setInputCloud(in_cloud_ptr);        //输入待处理点云集合
        seg.segment(*inliers, *coefficients);   //向分割算法中输入模型参数,输出分割模型的点云索引对象
        
  7. 滤除特征不明显的点云

    1. 判定特征是否明显的原理:点云曲率越大,对应弧的弯曲程度越大,采样点越多,特征越明显;反之,特征越不明显

    2. 核心操作:去除曲率小于0.5的点云数据

    3. 操作流程:

      建立点云数据KD树
      KD树搜索每个点云在大半径下的邻近点
      计算每个点云在大半径下的法向量
      基于法向量微分的点云分割
      获得每个点云的法向量和曲率
      利用条件滤波滤除不满足条件的点云,条件指曲率大于0.5
      KD树搜索每个点云在小半径下的邻近点
      计算每个点云在小半径下的法向量
      • 核心函数:

        1. 建立KD搜索树对象:pcl::search::KdTree<pcl::PointXYZ> tree

        2. 建立KD搜索树:tree->setInputCloud(int_cloud_ptr)

        3. 进行法向量粗估计(OMP代表多线程估计,更快):pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::PointNormal> normal_estimation

          1. 设置输入
          2. 设置搜索方式:normal_estimation.setSearchMethod(tree)
          3. 设置视点(用于统一法线方向):normmal_estimation.setViewPoint(0, 0, 0)
          4. 设置搜索半径,进行KD树半径R邻域搜索:normal_estimation.setRadiusSearch(3)
          5. 拟合平面,并计算点云法向量:normal_estimation.compute(*normal_point_ptr)
        4. 进行法向量精估计:基于法向量微分的点云分割(对点云的大小半径做差)–>pcl::DiffenceOfNormalEstimation<pcl::PointXYZ, pcl::PointNormal, pcl::PointNormal> diffnormals_estimator

          1. diffnormals_estimator中的PointXYZPointNormalPointNormal分别代表待分割的点云数据、大半径点云法向量、小半径点云法向量
          2. 输入点云、大半径法向量、小半径法向量
            1. diffnormals_estimator.setInputCloud(in_cloud_ptr)
            2. diffnormals_estimator.setNormalScaleLarge(normal_large_ptr)
            3. diffnormals_estimator.setNormalScaleSmall(normal_small_ptr)
          3. 初始化计算:diffnormals_estimator.initcompute()
          4. 计算点云法向量:diffnormals_estimator.computeFeature(*out_cloud_ptr)
            1. 更新out_cloud_ptr中的法线和曲率,其数据类型为:PointNormal
        5. 构建点云条件滤波对象:pcl::ConditionalRemoval<pcl::PointNormal> cond_remove

          1. 构建滤波条件对象:pcl::ConditionOr<pcl::PointNormal>::ptr range_cond(new pcl::ConditionOr<pcl::PointNormal>())

          2. 构建条件滤波(点云曲率大于0.5保留):range_cond->addComparison(pcl::FieldComparison<pcl::PointNormal>::ConstPtr(new pcl::FieldComparison<pcl::PointNormal>("curvature", pcl::ComparisonOps::GT, 0.5))

            在这里插入图片描述

        6. 点云数据复制

          pcl::PointCloud<pcl::PointNormal>::ptr diffnormals_cloud(new pcl::PointCloud<pcl::PointNormal>)
          pcl::copyPointCloud<pcl::PointXYZ, pcl::PointNormal>(*in_cloud_ptr, *diffnormals_cloud) //将in_cloud_ptr中的点云XYZ数据复制到diffnormals_cloud中点云pcl::PointNormal的XYZ上
          
  8. 点云欧式聚类,获得聚类信息

    1. 简述欧式聚类原理:

      1. 构建点云空间的KD树,便于后续点云半径邻域搜索
      2. 随机选取点云空间内的某个点云p1作为初始点,并以该点云p1为中心进行半径(人为设定)邻域搜索,获得领域点云集合P1
      3. 在点云集合P1中去除点云p1,再随机挑选一个点云p2进行邻域搜索,获得邻域点云集合P2,并将P2集合中有而P1集合中没有的点云补充到P1集合中,即 P 1 = P 1 ∪ P 2 P1=P1\cup P2 P1=P1P2,P1不断扩大。
      4. 不断循环上述3步骤,直到遍历完P1集合中的所有点云,此时点云集合P1即为聚类得到的某个物体。
      5. 重新在点云空间中随机选取某个不属于点云集合P1的点云,进行上述步骤2、3、4,获得聚类物体。
      6. 当点云空间中没有单独的点云时,聚类结束,完成点云聚类。
    2. 实际流程:

      1. 获取点云的二维信息,即x,y坐标,进行二维空间的点云欧式聚类

      2. 利用二维空间的点云聚类结果找到对应的三维点云,即不考虑点云z坐标,只要点云(x,y)坐标属于一个聚类物体,那个该三维点云就属于同一个聚类物体。

        • 从该部分可以看出3D聚类的结果存在瑕疵。如果现有两个物体,其(x,y)坐标相同,而高度z不同,按照该方法聚类,只会聚成一个物体,后续需改进
      3. 根据聚类物体的三维点云坐标获取聚类物体的信息

        • 聚类物体的长宽高

          • 长:length = max_x - min_x
          • 宽:width = max_y - min_y
          • 高:height = max_z - min_z
        • 聚类物体的顶点

          • 注:聚类结果显示为矩形。上下顶点只有Z坐标不同(只需求出上顶点或下顶点即可)

          • 上下顶点的计算使用凸包算法获得

            • 利用凸包算法获得聚类物体在二维平面中的凸点,如下所示,即将最外层点连接

              在这里插入图片描述

            • 根据上述凸包,计算凸包的最小内接矩形,得到如下图所示,则紫色矩形的4个顶点,即为聚类物体的顶点,加上高度信息,即得到了聚类物体的8个顶点。

              在这里插入图片描述

        • 聚类物体的姿态

          1. 类物体的姿态等于聚类物体相对于激光雷达坐标系的偏航角
          • 利用凸包算法计算得到内接矩阵的angle,如下图所示,angle应该为 θ 1 \theta_1 θ1.angle选择两个角度中绝对值较小的角度

            在这里插入图片描述

          • 创造聚类物体的四元数tf::createQuaternionFromRPY(0.0, 0.0, θ1),完成聚类物体的姿态获取

  9. 将过近的聚类物体合并成一个聚类物体

    1. 合并流程:
      1. 第一次合并:
        1. 计算聚类物体的质心
        2. 如果两个质心的距离小于一定阈值,则将两个质心对应的聚类物体合并
      2. 第二次合并:
        1. 重复第一次合并操作
    2. 两次合并的原因:防止第一次合并后出现物体过近的情况

romRPY(0.0, 0.0, θ1)`,完成聚类物体的姿态获取

  1. 将过近的聚类物体合并成一个聚类物体

    1. 合并流程:
      1. 第一次合并:
        1. 计算聚类物体的质心
        2. 如果两个质心的距离小于一定阈值,则将两个质心对应的聚类物体合并
      2. 第二次合并:
        1. 重复第一次合并操作
    2. 两次合并的原因:防止第一次合并后出现物体过近的情况
  2. 输出聚类结果,完成点云3D聚类

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

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

相关文章

大小端的判断

1.关于进制 1.1 进制数与位数 n进制数中&#xff0c;一位最多表示到数字n-1 十进制中1位最多能表示9个数字 满则溢&#xff0c;溢则进位。 拿我们最常用的是10 进制来举例说明&#xff0c; 构成十进制的最小单位数: 1 2 3 4 5 6 7 8 9 0 十进制(其实只有从9到0这几个数字,1…

OSPF笔记(四):OSPF五种报文和五种常见LSA

一、OSPF五种报文 (使用IP承载&#xff0c;可靠&#xff09; 1.1 hello&#xff1a; 发现和维护邻居关系 &#xff0c;以太网10s一次 1.2 DBD&#xff1a; 发送链路状态数据库摘要 1.3 LSR&#xff1a; 请求发送特定的链路状态信息&#xff08;请求包&#xff09; 1.4 LSU&…

Pr2023(Premiere Pro)中文版软件下载「附带安装教程」

Premiere Pro 23.0 版专为帮助编辑人员制作创意内容而设计&#xff0c;提供了出色的字幕工具组合。借助改进功能&#xff08;如批量编辑时间轴中的标题剪辑、灵活的对齐控件等&#xff09;简化您的标题和图形工作流程。此版本包含稳定性和性能方面的基础改进&#xff0c;包括更…

用 Flutter 轻松做个红包封面

前言 在 Flutter 的开发中&#xff0c;最常见的就是层层的组件嵌套&#xff0c;因此不可避免会遇到子组件如何适配父组件的问题。比如&#xff0c;按钮的可点击区域是否要占满整个父组件&#xff1f;图片是居中还是居左&#xff1f;这些问题可以通过 Flutter 提供的FittedBox …

Rancher - 更换Linux发行版

Rancher - 更换Linux发行版 时间&#xff1a;2022年11月20日21:24:29 推荐&#xff1a;Linux CentOS7.9 一、为什么要更换/升级&#xff1f; CentOS7.9 停止维护时间 2024年06月30日 AnolisOS8 阿里云推出的Linux发行版&#xff0c;支持多计算架构&#xff0c;也面向云端场景…

公众号免费搜题系统搭建

公众号免费搜题系统搭建 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xff08;…

算法篇-------贪心2

文章目录题目1-------活动选择题目2-----无重叠区间题目3------最多可以参加的会议数目题目4-------去除重复字母题目5------移掉K位数字题目6-----拼接最大数题目1-------活动选择 有n个需要在同一天使用同一个教室的活动a1, a2, …, an&#xff0c;教室同一时刻只能由一个活…

MapReduce基础

MapReduce入门 理解MapReduce的思想 MapReduce的思想核心是先分再合&#xff0c;分而治之所谓的分而治之&#xff0c;就是把一个复杂的问题&#xff0c;按照一定的分解方法分为等价的规模的若干部分&#xff0c;然后捉个解决&#xff0c;分别找出各个部分的结果没然后将各个部…

【学习笔记】mac安装maven与idea自带maven

一、安装Maven 1.1 场景一&#xff1a;mac安装Maven step1: 下载maven 到 maven官网下载压缩包&#xff0c;这里下载 apache-maven-3.8.6-bin.zip 压缩包&#xff1a; step2: 解压安装 解压maven压缩包&#xff0c;将解压得到的maven文件夹 “apache-maven-3.8.6” 放到合适…

Ubuntu22.04系统安装Unreal Engine 5.1.0

1.实现目标 在Ubuntu22.04系统上从源码构建安装Unreal Engine 5.1.0。 2.实现过程 2.1 正常流程 (1)从github上下载最新的release版本的源代码:5.1.0 release。 (2)解压缩代码,并打开终端,执行 ./Setup.sh,下载所需的各项依赖,文件大小约20GB,需下载2-3小时。 (…

【每日一题Day33】LC799香槟塔 | 动态规划

香槟塔【LC799】 我们把玻璃杯摆成金字塔的形状&#xff0c;其中 第一层 有 1 个玻璃杯&#xff0c; 第二层 有 2 个&#xff0c;依次类推到第 100 层&#xff0c;每个玻璃杯 (250ml) 将盛有香槟。 从顶层的第一个玻璃杯开始倾倒一些香槟&#xff0c;当顶层的杯子满了&#xff…

springmvc-day01

springmvc-day01 第一节 SpringMVC概述 1. SpringMVC 优势 SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后&#xff0c;目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首…

pytest集成allure报告(allure安装及配置以及如何实现集成)

一、allure安装及环境变量配置 1、先保证本地已装jdk1.8 首先安装JDK1.8&#xff0c;添加到环境变量path。 具体可以查看文章&#xff1a;https://blog.csdn.net/weixin_40608713/article/details/116103153?ops_request_misc%257B%2522request%255Fid%2522%253A%2522166892…

07_通信过程

知识点1【给路由器添加一块网卡】 知识点2【演示浏览器访问web服务器】 知识点2【局域网的划分】&#xff08;补充&#xff09; 知识点3【跨外网的不同局域网通信过程】&#xff08;补充&#xff09; 知识点4【LInux下的防火墙】&#xff08;了解&#xff09; 防火墙的分类…

【虚幻引擎UE】UE4/UE5 GIS相关插件推荐及使用介绍

一、Cesium for Unreal&#xff08;Cesium插件&#xff09; 二、SuperMap Scene SDKs_Unreal Engine&#xff08;超图地图插件&#xff09; 提供了从SuperMap平台或其他开放在线地图访问真实世界地理空间3D数据的功能。 三、Vitruvio CityEngine Plugin&#xff08;CityEngine…

Python图像处理笔记

文章目录一. Pillow处理图片1.1 Pillow安装1.2 Pillow基本使用二. Matplotlib包中的图像模块2.1 简介2.2 API简介三. ndarray图像操作练习3.1 旋转图片3.2 图片打码3.3 图片拼接3.4 图片切割四. 图像灰度化4.1 简介4.2 灰度化方法五. OpenCV使用入门5.1 简介5.2 OpenCV基本使用…

Android TextView富文本SpannableStringBuilder的使用详解

背景&#xff1a; 在android开发过程中&#xff0c;做内容的时候&#xff0c;不仅只有字符&#xff0c;基本都是图文混排&#xff0c;甚至还会对内容中某段文字进行特殊处理&#xff0c;比如&#xff1a;字体加粗、字体变大、改变字体颜色、对某一段文字新增点击事件&#xff…

Redis缓存——快速入门

目录 1、Redis概述 1.1、NoSQL 1.2、缓存的需求 2、Redis简介及安装 2.2、redis的特点 2.3、redis下载 2.4、window安装 2.5、linux安装 3、Redis操作 3.1、多数据库 3.2、选择数据库 3.3、清空数据库 3.4、基本命令 4、五种数据类型 4.1、字符串&#xff08;st…

论文笔记:Ontology-enhanced Prompt-tuning for Few-shot Learning

论文来源&#xff1a;WWW 2022 论文地址&#xff1a;https://arxiv.org/pdf/2201.11332.pdfhttps://arxiv.org/pdf/2201.11332.pdf 论文代码&#xff1a;暂未公开 笔记仅供参考&#xff0c;撰写不易&#xff0c;请勿恶意转载抄袭&#xff01; Abstract 小样本学习旨在基于…

【数据结构】队列

1.啥是队列 2.队列实现 3.Queue接口的介绍以及队列的使用 4.相关队列的例子 &#xff08;1&#xff09;啥是队列 我们之前讲解了栈&#xff0c;栈和队列是有点区别的 我们说过栈是一种先进后出的数据结构&#xff0c;你可以把它想象成羽毛球筒&#xff1b;然而队列属于一种先…