基础的点云转换

简介: 对于点云处理而言,最简单也逃不过的就是点云转换了,我们就从点云转换开始,来一步步完成点云加速的学习。点云基础转换是3D点云处理中的一个重要步骤。它的主要目的是将点云从一个坐标系转换到另一个坐标系中,通常是为了方便后续处理或者显示。在实际应用中,点云基础转换通常包括平移、旋转、缩放等操作。这里对应了pcl::transformPointCloud这种方法1. CUDA与Thrust使用CUDA和Thrust进行点云基础转换可以大大提高处理效率,特别是当点云数据量较大时。CUDA是一种并行计算架构,可以利用GPU的计算能力来加速计算,而Thrust是CUDA的C++模板库,提供了许多与ST

对于点云处理而言,最简单也逃不过的就是点云转换了,我们就从点云转换开始,来一步步完成点云加速的学习。点云基础转换是3D点云处理中的一个重要步骤。它的主要目的是将点云从一个坐标系转换到另一个坐标系中,通常是为了方便后续处理或者显示。在实际应用中,点云基础转换通常包括平移、旋转、缩放等操作。这里对应了pcl::transformPointCloud这种方法

1. CUDA与Thrust

使用CUDA和Thrust进行点云基础转换可以大大提高处理效率,特别是当点云数据量较大时。CUDA是一种并行计算架构,可以利用GPU的计算能力来加速计算,而Thrust是CUDA的C++模板库,提供了许多与STL相似的算法和容器,可以方便地在CUDA中使用。

在点云基础转换中,最基本的操作是平移,即将点云沿x、y、z三个方向上移动一定的距离。这可以通过遍历点云中每个点,然后将其坐标加上平移向量来实现。使用CUDA和Thrust可以将这个操作并行化,提高处理效率。

另一个常见的操作是旋转,即将点云绕x、y、z三个方向上旋转一定的角度。这可以通过矩阵乘法来实现。具体来说,我们可以先将旋转矩阵乘以点云中每个点的坐标,然后将结果保存到一个新的点云中。同样,使用CUDA和Thrust可以将这个操作并行化,提高处理效率。

2. CUDA代码完成加速

下面这段代码是一个CUDA kernel函数,用于将点云数据按照给定的转换矩阵进行变换。该函数会在每个线程索引小于点云数的情况下,通过矩阵乘法将输入的点云数据进行转换,并将转换后的数据存储到原始的点云数据中。函数中使用了CUDA的并行计算能力,通过设置线程块和线程数,使得每个线程可以并行地处理一个点云数据的转换,从而加快了程序的运行速度。函数中也包括了同步操作,确保所有的线程都完成了转换操作后才能继续执行下一步操作。

__global__ void kernel_cudaTransformPoints(pcl::PointXYZ *d_point_cloud, int number_of_points, float *d_matrix)
{
  int ind = blockIdx.x * blockDim.x + threadIdx.x; // 线程索引
  if (ind < number_of_points) // 线程索引小于点云数
  {
    float vSrcVector[3] = {d_point_cloud[ind].x, d_point_cloud[ind].y, d_point_cloud[ind].z};             // 点云数据
    float vOut[3];                                                    // 点云数据
    vOut[0] = d_matrix[0] * vSrcVector[0] + d_matrix[4] * vSrcVector[1] + d_matrix[8] * vSrcVector[2] + d_matrix[12]; // 矩阵乘法,用于计算点云数据的转换
    vOut[1] = d_matrix[1] * vSrcVector[0] + d_matrix[5] * vSrcVector[1] + d_matrix[9] * vSrcVector[2] + d_matrix[13];
    vOut[2] = d_matrix[2] * vSrcVector[0] + d_matrix[6] * vSrcVector[1] + d_matrix[10] * vSrcVector[2] + d_matrix[14];
    d_point_cloud[ind].x = vOut[0]; // 将转换后的点云数据存储到原来的点云数据中
    d_point_cloud[ind].y = vOut[1];
    d_point_cloud[ind].z = vOut[2];
  }
}
cudaError_t cudaTransformPoints(int threads, pcl::PointXYZ *d_point_cloud, int number_of_points, float *d_matrix)
{
  kernel_cudaTransformPoints<<<number_of_points / threads + 1, threads>>>(d_point_cloud, number_of_points, d_matrix); // 设置线程块和线程数,并调用kernel来完成transform转换
  cudaDeviceSynchronize(); // 同步
  return cudaGetLastError();
}

下面我们来看看如何调用这部分代码,这部分代码定义了一个名为CCudaWrapper的类,该类包含了一个名为transform的函数,用于对点云进行变换。该函数的输入参数包括一个点云对象和一个4x4的变换矩阵。该函数首先设置了设备为第一个设备(cudaSetDevice(0)),然后通过调用getNumberOfAvailableThreads函数获取可用的线程数。接着,该函数将变换矩阵数据从主机复制到设备,并为点云数据和变换矩阵数据分配了设备内存。然后,调用了上述的cudaTransformPoints的函数,将变换应用于点云。最后,该函数将变换后的点云数据从设备复制到主机,并释放了设备内存。该函数的返回值为布尔值,表示变换是否成功。这里支持我们可以传pcl::PointCloud<pcl::PointXYZ>

3. Thrust代码完成加速

这段代码实现了一个基于Thrust算法库的点云变换函数TransformPointCloud。该函数接受一个变换矩阵和一个原始的点云数据,返回经过变换后的点云数据。变换过程中使用了PointCloudTransformFunctor结构体作为变换函数,其中对每个点进行了仿射变换。函数中使用了Thrust算法库中的transform函数,对每个点进行变换,并将结果存储在transformed_points中,最终将变换后的点云数据返回。这段代码没有使用CUDA,而是完全依赖于Thrust算法库实现的。

// 纯thrust算法,不使用cuda。对应了上面的transform内容
#pragma once
#include <pcl/common/transforms.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <stdio.h>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/random.h>
#include <thrust/scan.h>
#include <thrust/sequence.h>
#include <thrust/transform.h>
#include <iostream>
#include <iterator>
#include <pcl/point_types.h>
#include <thrust/device_vector.h>
// 定义点云结构体
struct PointXYZ
{
  float x, y, z;
};
struct PointCloudTransformFunctor
{
  float *transform;
  PointCloudTransformFunctor(float *transform)
    : transform(transform) {}
  __host__ __device__ pcl::PointXYZ operator()(const pcl::PointXYZ &pt) const
  {
    PointXYZ transformed_pt;
    transformed_pt.x = transform[0] * pt.x + transform[1] * pt.y +
               transform[2] * pt.z + transform[3];
    transformed_pt.y = transform[4] * pt.x + transform[5] * pt.y +
               transform[6] * pt.z + transform[7];
    transformed_pt.z = transform[8] * pt.x + transform[9] * pt.y +
               transform[10] * pt.z + transform[11];
    return transformed_pt;
  }
};
thrust::device_vector<PointXYZ>
TransformPointCloud(float *transform,
          const thrust::device_vector<PointXYZ> &orig_points)
{
  thrust::device_vector<PointXYZ> transformed_points;
  transformed_points.resize(orig_points.size());
  thrust::transform(orig_points.begin(), orig_points.end(),
            transformed_points.begin(), transformed_points.begin(),
            PointCloudTransformFunctor(transform));
  return transformed_points;
}

4. 结果显示

相关文章
|
7月前
|
人工智能 UED
DynamiCrafter:可实现任意类型静态图像转化为逼真动态视频
【2月更文挑战第17天】DynamiCrafter:可实现任意类型静态图像转化为逼真动态视频
361 1
DynamiCrafter:可实现任意类型静态图像转化为逼真动态视频
|
数据挖掘 计算机视觉 Python
Python数据分析中图像处理的实用技术点:图像加载与保存、图像转换与增强、特征提取与描述
Python数据分析中图像处理的实用技术点:图像加载与保存、图像转换与增强、特征提取与描述
93 1
Python数据分析中图像处理的实用技术点:图像加载与保存、图像转换与增强、特征提取与描述
|
2月前
|
Serverless 计算机视觉
语义分割笔记(三):通过opencv对mask图片来画分割对象的外接椭圆
这篇文章介绍了如何使用OpenCV库通过mask图像绘制分割对象的外接椭圆。首先,需要加载mask图像,然后使用`cv2.findContours()`寻找轮廓,接着用`cv2.fitEllipse()`拟合外接椭圆,最后用`cv2.ellipse()`绘制椭圆。文章提供了详细的代码示例,展示了从读取图像到显示结果的完整过程。
58 0
语义分割笔记(三):通过opencv对mask图片来画分割对象的外接椭圆
|
7月前
|
前端开发 计算机视觉 C++
【OpenCV】—分离颜色通道、多通道图像混合
【OpenCV】—分离颜色通道、多通道图像混合
|
7月前
|
传感器 数据采集 编解码
基于EinScan-S的编码结构光方法空间三维模型重建
基于EinScan-S的编码结构光方法空间三维模型重建
|
7月前
|
定位技术 Python
R语言raster包批量拼接、融合大量栅格图像
R语言raster包批量拼接、融合大量栅格图像
152 1
|
7月前
[Halcon&图像] 图像、区域和轮廓相互转化
[Halcon&图像] 图像、区域和轮廓相互转化
293 1
|
7月前
|
算法 机器人
[3D&Halcon] 3D鞋点胶的点云边界提取
[3D&Halcon] 3D鞋点胶的点云边界提取
499 0
|
7月前
[3D&Halcon] 3D重要算子及简单处理点云模型求高度示例讲解
[3D&Halcon] 3D重要算子及简单处理点云模型求高度示例讲解
572 0
|
7月前
|
算法 计算机视觉 芯片
[Halcon&定位] 二维仿射变换原理与算子解析
[Halcon&定位] 二维仿射变换原理与算子解析
344 0