写在前面的话:建议先看完本专栏的前三篇文章再看这篇

本文将介绍如何了查找点云中每个点的邻近点并统计个数

取点云文件

我给了个demo文件,在input文件夹下面,其每行为一个点,每行分别有4个数:index, x, y, z

0 0.190818 2.151146 1.516178
1 0.182662 2.208185 1.506151
2 0.212130 2.120995 1.519654
3 0.195404 2.216945 1.554745
4 0.177847 2.420602 1.464208
5 0.108176 2.408980 1.471528
6 0.285591 2.271129 1.526475
...........................
82881 2.856293 4.802210 0.886675
82882 2.893785 4.858056 0.938935

读取函数如下:

float* read_pc(string filename, float xyz[]){ifstream fin;fin.open(filename);if(!fin) {cout << filename << " file could not be opened\n";exit(0);}int idx;float x, y, z;while(!fin.eof()) {fin >> idx >> x >> y >> z;xyz[idx*3 + 0] =x;xyz[idx*3 + 1] =y;xyz[idx*3 + 2] =z;}return xyz;
}

主函数

主函数中我们需要设置计算邻近点的辐射距离,如下代码中所示,与所选点距离小于0.2m的即可以视为所选点的邻近点

int main() {string inputFileName = "/home/bruno/Documents/Clion_Project/cuda_demo/demo3_AdjacentPoint/input/pc.txt";const int point_num = 82883;const float radius = 0.2;float xyz[point_num*3];read_pc(inputFileName, xyz);checkNearPoints(point_num, xyz, radius);return 0;
}

检查临近点

首先我们要清楚我们的输入是什么: 点云个数,点云坐标,以及辐射距离; 其次我们要理清楚如何去利用cuda加速计算。最简单的想法:我们有多少个点就开启多少个线程,这样一次就可以把所有的点的临近点算出来。该函数的编写思路与前面几篇文章总结的一样,这里不多说。

void checkNearPoints(const int point_num, float xyz[], const float radius){dim3 blocks(DIVUP(point_num, THREADS_PER_BLOCK));dim3 threads(THREADS_PER_BLOCK);int * ptsCnt_h;ptsCnt_h = (int *)malloc(point_num * sizeof(int));// define gpu variableint * point_num_d;float * xyz_d;float * radius_d;int * ptsCnt_d; //mark the number of adjacent pointsint * adj_point_d; //mark the adjacent points, 1 is true,0 is false//generate gpu ramCUDA_ERR_CHK( cudaMalloc((void **) &point_num_d, sizeof(int)));CUDA_ERR_CHK(cudaMalloc((void **) &xyz_d, 3*point_num*sizeof(float)));CUDA_ERR_CHK(cudaMalloc((void **) &radius_d, sizeof(float)));CUDA_ERR_CHK(cudaMalloc((void **) &ptsCnt_d, point_num*sizeof(int)));// copy host to deviceCUDA_ERR_CHK(cudaMemcpy(point_num_d, &point_num, sizeof(int), cudaMemcpyHostToDevice));CUDA_ERR_CHK(cudaMemcpy(xyz_d, xyz, 3*point_num*sizeof(float), cudaMemcpyHostToDevice));CUDA_ERR_CHK(cudaMemcpy(radius_d, &radius, sizeof(float), cudaMemcpyHostToDevice));// start device kernelcheckNearPoints_cuda<<<blocks, threads>>>(point_num_d, xyz_d, radius_d, ptsCnt_d);// copy device to hostCUDA_ERR_CHK(cudaMemcpy(ptsCnt_h, ptsCnt_d, point_num*sizeof(float), cudaMemcpyDeviceToHost));// release gpu ramCUDA_ERR_CHK(cudaFree(point_num_d));CUDA_ERR_CHK(cudaFree(xyz_d));CUDA_ERR_CHK(cudaFree(radius_d));CUDA_ERR_CHK(cudaFree(ptsCnt_d));for (int i =0; i< point_num; i++){printf("index: %d adjacent point number: %d \n",i, ptsCnt_h[i]);}}

CUDA检查函数

由于我们直接调用CUDA的函数(cudaMencpy cudaMalloc 等),其不会直接返回准确的报错信息,所以我们需要写一个报错检索函数,这样我们可以知道出错的原因:

// https://stackoverflow.com/a/14038590
#define CUDA_ERR_CHK(code) { cuda_err_chk((code), __FILE__, __LINE__); }
inline void cuda_err_chk(cudaError_t code, const char *file, int line, bool abort = true) {if (code != cudaSuccess) {fprintf(stderr, "\tCUDA ERROR: %s %s %d\n", cudaGetErrorString(code), file, line);if (abort) exit(code);}
}

添加后我们可以看到如下报错:直接告诉我们在65行,内存溢出了。(说明你的GPU卡内存不够,可以换卡, 或者对点进行下采样)

核函数

核函数利用线程ID做检索,通过for循环去遍历所选点外的每一个点。通过计算每个点与所选距离,再与辐射距离进行比较,小于辐射距离的视为邻近点。

__global__ void checkNearPoints_cuda(int *point_num_d, float *xyz_d, float *eps_d, int *ptsCnt_d){int th_index = blockIdx.x*blockDim.x + threadIdx.x;if (th_index >= *point_num_d) return ;ptsCnt_d[th_index] = 0;  // the number of adjacent pointsfloat o_x = xyz_d[th_index * 3 + 0];float o_y = xyz_d[th_index * 3 + 1];float o_z = xyz_d[th_index * 3 + 2];for (int k =0; k< *point_num_d; k++){if(th_index==k) continue;float k_x = xyz_d[k * 3 + 0];float k_y = xyz_d[k * 3 + 1];float k_z = xyz_d[k * 3 + 2];float l2 = sqrt((k_x-o_x)*(k_x-o_x)+(k_y-o_y)*(k_y-o_y)+(k_z-o_z)*(k_z-o_z));if (l2 <= *eps_d) {ptsCnt_d[th_index]= ptsCnt_d[th_index] + 1;}}
}

CmakeList

Cmakelist我这次给出了一个通用的模板,基本每个demo都可以用,还解决了无法核嵌套的问题。注意要根据自己CUDA安装路径小小更改下下面的代码。

cmake_minimum_required(VERSION 3.19)
project(AdjacentPoint)set(CMAKE_CXX_STANDARD 14)# packages
find_package(CUDA REQUIRED)if(${CUDA_FOUND})set(CUDA_SOURCE_PROPERTY_FORMAT OBJ)set(CUDA_SEPARABLE_COMPILATION ON)include_directories(${CUDA_INCLUDE_DIRS})set(CUDA_PROPAGATE_HOST_FLAGS OFF)#    set(CUDA_VERBOSE_BUILD ON)SET(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-gencode arch=compute_75,code=sm_75;-std=c++14; -rdc=true;  -lcudadevrt)link_directories(/usr/local/cuda/lib64)MESSAGE(STATUS "found cuda")
else(${CUDA_FOUND})MESSAGE(STATUS "cuda not found!")
endif(${CUDA_FOUND})file(GLOB CURRENT_SOURCES  *.cpp *.cu)
file(GLOB_RECURSE CURRENT_HEADERS  *.h *.hpp *.cuh)source_group("Source" FILES ${CURRENT_SOURCES})
source_group("Include" FILES ${CURRENT_HEADERS})CUDA_ADD_EXECUTABLE(AdjacentPoint ${CURRENT_HEADERS} ${CURRENT_SOURCES} ${CUDA_INCLUDE_DIRS})
target_link_libraries(AdjacentPoint /usr/local/cuda/lib64/libcudadevrt.a)

打印结果

结果如下图所示。 如果想知道邻近点的索引,可以查看adj_point_d变量,该变量很占内存,如果不需要还是注释掉。

最后,完整代码以及其他demo可以在我的github中获取(不定期更新):

GitHub - weiguangzhao/cuda_demo: CUDA DEMOhttps://github.com/weiguangzhao/cuda_demo

CUDA编程--邻近点查询相关推荐

  1. CUDA刷新器:CUDA编程模型

    CUDA刷新器:CUDA编程模型 CUDA Refresher: The CUDA Programming Model CUDA,CUDA刷新器,并行编程 这是CUDA更新系列的第四篇文章,它的目标是 ...

  2. CUDA 编程实例:计算点云法线

    程序参考文章:http://blog.csdn.net/gamesdev/article/details/17535755  程序优化2 简介:CUDA ,MPI,Hadoop都是并行运算的工具.CU ...

  3. cuda编程_CUDA刷新器:CUDA编程模型

    CUDA刷新器:CUDA编程模型 CUDA Refresher: The CUDA Programming Model CUDA,CUDA刷新器,并行编程 这是CUDA更新系列的第四篇文章,它的目标是 ...

  4. 【转载】cuda编程入门

    目录 1.什么是CUDA 2.为什么要用到CUDA 3.CUDA环境搭建 4.第一个CUDA程序 5. CUDA编程 5.1. 基本概念 5.2. 线程层次结构 5.3. 存储器层次结构 5.4. 运 ...

  5. cuda编程思想和opencv_gpu图像处理

    CUDA编程 https://github.com/Ewenwan/ShiYanLou/tree/master/CUDA CUDA(Compute Unified Device Architectur ...

  6. CUDA编程: GPU与CPU之间使用全局统一内存的完整代码及编译

    CUDA编程: GPU与CPU之间使用全局统一内存的完整代码及编译 最近碰到一个应用场景,需要从GPU访问host上创建的,一个很大的布隆过滤器(准确说是改进后的布谷鸟过滤器).由于GPU卡上的显存有 ...

  7. NVIDIA GPU SM和CUDA编程理解

    SM硬件架构基础 不同架构的变化可以参考: ​​​​​​从AI系统角度回顾GPU架构变迁--从Fermi到Ampere(V1.2) - 知乎 英伟达GPU架构演进近十年,从费米到安培 - 知乎 Vol ...

  8. cuda C 编程权威指南 Grossman 第2章 CUDA编程模型

    2.1 CUDA编程模型概述 CUDA编程模型提供了一个计算机架构抽象作为应用程序和其可用硬件之间的桥梁. 通信抽象是程序与编程模型实现之间的分界线,它通过专业的硬件原语和操作系统的编译器或库来实现. ...

  9. 6.CUDA编程手册中文版---附录AB

    附录A 支持GPU设备列表 更多精彩内容,请扫描下方二维码或者访问https://developer.nvidia.com/zh-cn/developer-program 来加入NVIDIA开发者计划 ...

最新文章

  1. 【转】GLSL资料收集
  2. Docker极简入门
  3. discuz x2.5 广告位开发学习(第二步:制作)
  4. 转:Java并发编程与高并发解决方案(一)
  5. 51nod 1009 数字1的数量
  6. Linux命令行学习日志-ps ax
  7. 屏幕提词器Presentation Prompter for Mac
  8. 数据分析入门——深入浅出数据分析
  9. VISIO输出黑白色电路图
  10. 企业需要关注的零信任 24 问
  11. 变焦和对焦_在Randonautica内部,该应用程序可带领变焦器发现彩虹,尸体和隐藏的宝藏
  12. Unity升级到URP渲染管线,
  13. 网络项目实践与设备管理教程-毛正标
  14. APP定制开发:APP软件开发的语言和开发环境
  15. Google Gmail 使用 Outlook2003
  16. 落地,请开手机李小晚【转】
  17. 小新700linux网卡驱动,小新Air14网卡驱动2024.0.2.101/12.0.0.725版下载,适用于Win10-64-驱动精灵...
  18. 张艾迪(创始人):年少创业与干净的我
  19. 自建Alist共享网盘网站
  20. CodeChef MONOPLOY Gangsters of Treeland

热门文章

  1. 数字IC验证:Hands-on Coding之Harness Interface与内部的Interfaces
  2. 桌面应用程序UI框架有哪些
  3. 【Python基础】字典dict和集合set
  4. 腾讯云轻量应用服务器大陆地区新套餐上线了
  5. ChatGPT版必应疑似「发疯」?微软紧急限制回答数目
  6. 分类模型评价指标说明
  7. 蓝牙智能门锁现状分析
  8. 人到中年,越活越抠,越活越卑微
  9. 工作5年左右的程序员如何在职业瓶颈期内快速提升自己的身价?提升后如何有效变现自己的高质量技能?
  10. [Error]cannot convert 'float'tot float for argument 1to floa