作者 | 点云PCL

点击下方卡片,关注“自动驾驶之心”公众号

ADAS巨卷干货,即可获取

点击进入→自动驾驶之心【点云处理】技术交流群

本文只做学术分享,如有侵权,联系删文

前言

在这篇文章将介绍如何使用CUDA-PCL处理点云来获得最佳性能,由于PCL无法充分利用Jetson上的CUDA,NVIDIA开发了一些具有与PCL相同功能的基于CUDA的库。代码地址:https://github.com/NVIDIA-AI-IOT/cuPCL.git(只有动态库和头文件,作者说源码将在未来开源)。

cuPCL包含一些用于使用CUDA处理点云的库,以及用于它们的使用示例。项目中有几个子文件夹,每个子文件夹都包含:由CUDA实现的库以及库用法并通过将其输出与PCL的输出进行比较来检查性能和准确性的示例代码,该库支持Xavier、Orin和Linux x86。

作者介绍

Lei Fan,NVIDIA的高级CUDA软件工程师。他目前与NVIDIA的中国技术支持工程师团队合作,开发通过CUDA优化软件性能的解决方案。

Lily Li,正在NVIDIA的机器人团队担任开发者关系工作。她目前致力于开发Jetson生态系统中的机器人解决方案,以帮助创建最佳实践。

主要内容

许多Jetson用户选择激光雷达用于定位和感知的主要传感器,激光雷达将车辆周围的空间环境描述为一组三维点,称为点云,点云对周围对象的表面进行采样,具有远距离和高精度的特点,非常适合用于高级障碍物感知、地图制作、定位和规划算法。

b5505912de126cd57c650ee67c90f439.jpeg

在这篇文章中介绍了CUDA-PCL 1.0,其这里主要介绍三个CUDA加速的PCL库:

1.CUDA-ICP

2.CUDA-Segmentation

3.CUDA-Filter

3a3794d6438972291d4fa256feea7675.png

CUDA-ICP 

在迭代最近点(ICP)中,一个点云目标或参考点云被固定,而源点被变换以最佳匹配参考点。该算法迭代地计算所需的变换矩阵,以最小化误差度量,这通常是来自源点到参考点云的距离,例如匹配对坐标之间的平方差之和。ICP是在给定刚性变换所需的初始猜测位姿的情况下对齐三维模型的广泛使用的算法之一。ICP的优点包括高精度匹配结果,对不同初始化具有强鲁棒性等。然而它消耗大量计算资源。为了改进Jetson上的ICP性能,NVIDIA发布了基于CUDA的ICP,它可以替代点云库(PCL)中的原始ICP版本。以下代码示例是CUDA-ICP示例。可以实例化该类,然后直接执行cudaICP.icp()。

cudaICP icpTest(nPCountM, nQCountM, stream);
    icpTest.icp(cloud_source, nPCount,
            float *cloud_target, int nQCount,
            int Maxiterate, double threshold,
            Eigen::Matrix4f &transformation_matrix, stream);

ICP计算两个点云之间的变换矩阵:

source(P)* transformation =target(Q)

因为激光雷达提供了具有固定数量的点云,我们可以得到最大点数。nPCountM和nQCountM都用于为ICP分配缓存。

class cudaICP
{
public:
    /*       nPCountM and nQCountM are the maximum of count for input clouds.
       They are used to pre-allocate memory.
    */
    cudaICP(int nPCountM, int nQCountM, cudaStream_t stream = 0);
    ~cudaICP(void);
    /*
    cloud_target = transformation_matrix *cloud_source
    When the Epsilon of the transformation_matrix is less than threshold,
    the function returns transformation_matrix.
    Input:
        cloud_source, cloud_target: Data pointer for the point cloud.
        nPCount: Point number of the cloud_source.
        nQCount: Point number of the cloud_target.
        Maxiterate: Threshold for iterations.
        threshold: When the Epsilon of the transformation_matrix is less than
            threshold, the function returns transformation_matrix.
    Output:
        transformation_matrix
    */
    void icp(float *cloud_source, int nPCount,
            float *cloud_target, int nQCount,
            int Maxiterate, double threshold,
            Eigen::Matrix4f &transformation_matrix,
            cudaStream_t stream = 0);
    void *m_handle = NULL;
};

表2展示了CUDA-ICP与PCL-ICP的性能对比结果

ea01df1cc3f1e17f7b9713031ea3222f.png

在ICP之前两帧点云的状态

4c97493a50b9118e3b47bb5b3c095939.png

在ICP之后两帧点云的状态

857a753c59b09d891064602d09d8146b.png

CUDA-Segmentation

点云地图包含许多地面点,这不仅使整个地图看起来凌乱,还给后续障碍点云的分类、识别和跟踪带来了麻烦,因此需要首先将其删除。通过点云分割可以实现去除地面。该库使用随机抽样一致性(Ransac)拟合和非线性优化来实现这一目标。以下是CUDA-Segmentation的示例代码。首先实例化该类,初始化参数,然后直接调用 cudaSeg.segment 来执行地面去除。

//Now Just support: SAC_RANSAC + SACMODEL_PLANE
  std::vectorindexV;
  cudaSegmentation cudaSeg(SACMODEL_PLANE, SAC_RANSAC, stream);
  segParam_t setP;
  setP.distanceThreshold = 0.01;
  setP.maxIterations = 50;
  setP.probability = 0.99;
  setP.optimizeCoefficients = true;
  cudaSeg.set(setP);
  cudaSeg.segment(input, nCount, index, modelCoefficients);
  for(int i = 0; i < nCount; i++)
  {
    if(index[i] == 1)
    indexV.push_back(i);
  }

CUDA-Segmentation对具有nCount点数的输入进行分割,使用一些参数,index是输入的索引,代表目标平面,而modelCoefficients是平面的系数组。

typedef struct {
  double distanceThreshold;
  int maxIterations;
  double probability;
  bool optimizeCoefficients;
} segParam_t;
class cudaSegmentation
{
public:
    //Now Just support: SAC_RANSAC + SACMODEL_PLANE
    cudaSegmentation(int ModelType, int MethodType, cudaStream_t stream = 0);
    ~cudaSegmentation(void);
    /*
    Input:
        cloud_in: Data pointer for point cloud
        nCount: Count of points in cloud_in
    Output:
        Index: Data pointer that has the index of points in a plane from input
      modelCoefficients: Data pointer that has the group of coefficients of the plane
    */
    int set(segParam_t param);
    void segment(float *cloud_in, int nCount,
            int *index, float *modelCoefficients);
private:
    void *m_handle = NULL;
};

表3.展示了CUDA-Segmentation与PCL-Segmentation的性能对比。

24c437c269c50a2f3648774bd03b8fb1.png

图3和图4显示了原始点云数据,然后是仅保留障碍相关点云的处理版本。这个示例在点云处理中很典型,包括去除地面,删除一些点云和提取特征,以及对一些点云进行聚类。

0cd884a46ab5ce71290b5b15174919a4.png

图3. CUDA-Segmentation的原始点云

4725fb5ae9f04a07f69cb4f0d63026df.png

图4. 由CUDA-Segmentation处理的点云

CUDA-Filter

在点云进行分割、检测、识别等处理之前,滤波是最重要的预处理操作之一。通过滤波可以实现对点云的坐标约束,直接过滤点云的X、Y和Z轴,点云过滤可以仅对Z轴或三个坐标轴X、Y和Z进行约束。CUDA-Filter目前仅支持PassThrough,但以后将支持更多的方法。以下是CUDA-Filter示例的代码示例,创建该类的实例,初始化参数,然后直接调用cudaFilter.filter函数。

cudaFilter filterTest(stream);
  FilterParam_t setP;
  FilterType_t type = PASSTHROUGH;
  setP.type = type;
  setP.dim = 2;
  setP.upFilterLimits = 1.0;
  setP.downFilterLimits = 0.0;
  setP.limitsNegative = false;
  filterTest.set(setP);
  filterTest.filter(output, &countLeft, input, nCount);

CUDA-Filter使用参数筛选输入的nCount个点,然后通过CUDA过滤后,输出具有countLeft个点的结果。

typedef struct {
    FilterType_t type;
    //0=x,1=y,2=z
    int dim;
    float upFilterLimits;
    float downFilterLimits;
    bool limitsNegative;
} FilterParam_t;
class cudaFilter
{
public:
    cudaFilter(cudaStream_t stream = 0);
    ~cudaFilter(void);
    int set(FilterParam_t param);
    /*
    Input:
        source: data pointer for point cloud
        nCount: count of points in cloud_in
    Output:
        output: data pointer which has points filtered by CUDA
        countLeft: count of points in output
    */
    int filter(void *output, unsigned int *countLeft, void *source, unsigned int nCount);
    void *m_handle = NULL;
};

表4.展示了CUDA-Filter与PCL-Filter性能比较。

b6934377b4105abca11a8fa92f8dfb7a.png

图5和图6显示了通过在X轴上进行约束的PassThrough滤波器示例。

77a2bfd50ab2494baa2ab5e805aeee7d.png

图6. 原始点云。

bf2ec91d8d1024ef6e943a929c576f37.png

图6. 通过在X轴上进行约束滤波的点云。

其他模块对比

VoxelGrid

5970ed5bcd973e0bd25f6a1fcc35040a.png

cuOctree

11276a5cfca6c0b09227587e42de52ab.png

cuCluster

7d50bdce58503816ce74bc0538f58e6a.png

cuNDT

8f3b6ebf0054f8f17dacd80f2e68b603.png

相关链接

https://github.com/NVIDIA-AI-IOT/cuPCL.git

https://developer.nvidia.com/blog/accelerating-lidar-for-robotics-with-cuda-based-pcl/ 

https://developer.nvidia.com/blog/detecting-objects-in-point-clouds-with-cuda-pointpillars/

① 全网独家视频课程

BEV感知、毫米波雷达视觉融合多传感器标定多传感器融合多模态3D目标检测点云3D目标检测目标跟踪Occupancy、cuda与TensorRT模型部署协同感知语义分割、自动驾驶仿真、传感器部署、决策规划、轨迹预测等多个方向学习视频(扫码即可学习

f34e65fc6377af58b0db06fe594cd441.png 视频官网:www.zdjszx.com

② 国内首个自动驾驶学习社区

近2000人的交流社区,涉及30+自动驾驶技术栈学习路线,想要了解更多自动驾驶感知(2D检测、分割、2D/3D车道线、BEV感知、3D目标检测、Occupancy、多传感器融合、多传感器标定、目标跟踪、光流估计)、自动驾驶定位建图(SLAM、高精地图、局部在线地图)、自动驾驶规划控制/轨迹预测等领域技术方案、AI模型部署落地实战、行业动态、岗位发布,欢迎扫描下方二维码,加入自动驾驶之心知识星球,这是一个真正有干货的地方,与领域大佬交流入门、学习、工作、跳槽上的各类难题,日常分享论文+代码+视频,期待交流!

1dd9e7483b22452f37365650c9d75ad0.png

③【自动驾驶之心】技术交流群

自动驾驶之心是首个自动驾驶开发者社区,聚焦目标检测、语义分割、全景分割、实例分割、关键点检测、车道线、目标跟踪、3D目标检测、BEV感知、多模态感知、Occupancy、多传感器融合、transformer、大模型、点云处理、端到端自动驾驶、SLAM、光流估计、深度估计、轨迹预测、高精地图、NeRF、规划控制、模型部署落地、自动驾驶仿真测试、产品经理、硬件配置、AI求职交流等方向。扫码添加汽车人助理微信邀请入群,备注:学校/公司+方向+昵称(快速入群方式)

04693b65696556917c918a008954936d.jpeg

④【自动驾驶之心】平台矩阵,欢迎联系我们!

f204b8230d4956c2b487712ab183174e.jpeg

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐