【点云处理】点云法向量估计及其加速(5)

news2025/2/27 14:01:40

        在上一篇文章【点云处理】点云法向量估计及其加速(4)中我们尝试对pcl自带的KDTree的k近邻搜索过程使用OpenMP加速,效果比较明显,有将近1倍的提速。在这篇文章中我们暂时放弃pcl自带的KDTree,转而使用另一大杀器nanflann库提供的KDTree。nanoflann是一个c++11标准库,用于构建具有不同拓扑(R2,R3(点云),SO(2)和SO(3)(2D和3D旋转组))的KD树。nanoflann 算法对fastann进行了改进,效率以及内存使用等方面都进行了优化,而且代码十分轻量级且开源。nanoflann不需要编译或安装,你只需要在你的代码中加入#include <nanoflann.hpp>即可方便快捷地使用它。好了,下面使用nanoflann对我们的代码进行改写。

#include <time.h>
#include <cmath>
#include <functional>
#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl/console/time.h>
#include <pcl/gpu/features/features.hpp>
#include <omp.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl_conversions/pcl_conversions.h>
#include <spdlog/spdlog.h>
#include "KDTreeTableAdaptor.h"

int main(int argc, char** argv) {
    ros::init(argc, argv, "n_lidar_gpu_normal");
    ros::NodeHandle node;
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
 
    const boost::function<void (const boost::shared_ptr<sensor_msgs::PointCloud2 const>&)> callback =[&](sensor_msgs::PointCloud2::ConstPtr msg_pc_ptr) {
        pcl::fromROSMsg(*msg_pc_ptr, *cloud);
        size_t cloud_size = cloud->size();
        int dim=3,k=10; 
        float* points = new float[cloud_size*dim];
        for (int i=0; i<cloud_size; i++) {
            float* p = points + i*dim;
            p[0] = cloud->points[i].x;
            p[1] = cloud->points[i].y;
            p[2] = cloud->points[i].z;
        }

        auto t1 = std::chrono::steady_clock::now();
        KDTreeTableAdaptor<float,float>  kdtree(cloud_size, dim, points, 64);
        std::vector<std::vector<int>> neighbors_all(cloud_size,std::vector<int>(k));
        std::vector<int> sizes(cloud_size,k);

        for (int i=0; i<cloud_size; i++) {
            std::vector<size_t> out_ids(k);
            std::vector<float> out_dists_sqr(k);
            nanoflann::KNNResultSet<float> result_set(k);
            result_set.init(&out_ids[0], &out_dists_sqr[0]);
            kdtree.index->findNeighbors(result_set, &points[i*dim], nanoflann::SearchParams(k));
            for (int j=0; j<k; j++) {
                neighbors_all[i][j] = out_ids[j];
            }
        } 

        auto t2 = std::chrono::steady_clock::now();
        delete []points;
 
        std::vector<int> flatten_neighbors_all(k * cloud_size);
        pcl::gpu::PtrStep<int> ps(&flatten_neighbors_all[0], k * pcl::gpu::PtrStep<int>::elem_size);
	    for (size_t i=0; i<cloud_size; ++i) {
		    std::copy(neighbors_all[i].begin(), neighbors_all[i].end(), ps.ptr(i));
        }
 
        pcl::gpu::NeighborIndices gpu_neighbor_indices;
        pcl::gpu::NormalEstimation::PointCloud gpu_cloud;
        gpu_cloud.upload(cloud->points);
        gpu_neighbor_indices.upload(flatten_neighbors_all, sizes, k);
 
        pcl::gpu::NormalEstimation::Normals gpu_normals;
	    pcl::gpu::NormalEstimation::computeNormals(gpu_cloud, gpu_neighbor_indices, gpu_normals);
	    pcl::gpu::NormalEstimation::flipNormalTowardsViewpoint(gpu_cloud, 0.f, 0.f, 0.f, gpu_normals);
        auto t3 = std::chrono::steady_clock::now();
        auto compute_normal_time = std::chrono::duration<double,std::milli>(t3 - t2);
 
	    std::vector<pcl::PointXYZ> normals;
	    gpu_normals.download(normals);
        auto t4 = std::chrono::steady_clock::now();
        
        auto knn_time = std::chrono::duration<double,std::milli>(t2-t1);
        auto total_time = std::chrono::duration<double,std::milli>(t4-t1);
        spdlog::info("cloud size:{:d}, knn_time:{:.3f} ms,compute_normal_time:{:.3f} ms, total_time:{:.3f} ms", cloud->size(), knn_time.count(), compute_normal_time.count(), total_time.count());
    };
    ros::Subscriber pc_sub = node.subscribe<sensor_msgs::PointCloud2>("/BackLidar/lslidar_point_cloud", 1, callback);
    ros::spin();
    return 0;
}

对于for循环遍历查找k近邻索引部分我们先不加"# pragma omp parallel for",编译运行。

  哇,加速效果明显,8w点云knn时间从400ms降到150ms左右。比pcl自带KDTree使用上OpenMP并行加速还要快。

要是能利用OpenMP做并行加速,岂不是要起飞??!!加上OpenMP加速试一试。

# pragma omp parallel for
        for (int i=0; i<cloud_size; i++) {
            std::vector<size_t> out_ids(k);
            std::vector<float> out_dists_sqr(k);
            nanoflann::KNNResultSet<float> result_set(k);
            result_set.init(&out_ids[0], &out_dists_sqr[0]);
            kdtree.index->findNeighbors(result_set, &points[i*dim], nanoflann::SearchParams(k));
            for (int j=0; j<k; j++) {
                neighbors_all[i][j] = out_ids[j];
            }
        } 

 编译运行,测试结果如下:

哇,虽然有波动,但常能在50ms左右徘徊,相比曾几何时的400ms提速了8倍。 多核算力分配也很均衡,完美!

 所以,knn加速哪家强,nanoflann+OpenMP当称王!!!

【参考文献】

在C++中使用openmp进行多线程编程_线上幽灵的博客-CSDN博客_c++ omp

PCL GPU实现计算法线和曲率 - 知乎

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

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

相关文章

玩链子游戏

一 游戏描述 有一条链子&#xff0c;上面有 n 颗钻石&#xff0c;钻石编号为 1&#xff5e;n 。可以对该链子执行两种操作&#xff1a; ① CUT a b c &#xff08;区间切割操作&#xff09; 切下从第 a 颗钻石到第 b 颗钻石的链子&#xff0c;把它插在剩余链子的第 c 颗钻石…

【食品加工技术】第五章 烘烤食品加工技术 笔记

【食品加工技术】第五章 烘烤食品加工技术 笔记5.1 焙烤食品概述烘烤食品的分类按发酵和膨化程度分类安装生产工艺分类烘烤食品的原料面粉糖蛋品乳及乳制品膨松剂烘烤设备常用设备恒温设备常用工具5.2 面包加工工艺和关键技术面包的分类面包的发酵原理面包的工艺流程一次发酵二…

uboot引导应用程序

uboot默认是支持执行应用程序的&#xff0c;就像引导内核一样&#xff0c;我们也可以自己写一个应用程序&#xff0c;让uboot启动时引导。 在uboot examples/standalone 目录下&#xff0c;有hello_world.c文件&#xff0c;编译uboot的时候&#xff0c;会自动编译hello_world.…

详解 InnoDB Cluster 主机名问题

详解 InnoDB Cluster 主机名问题 文章目录详解 InnoDB Cluster 主机名问题导言测试过程结论导言 因在写 【InnoDB Cluster】修改已有集群实例名称及成员实例选项 时发现主机名这块有一些问题&#xff0c;在其中进行了部分测试&#xff0c;但为使其内容精简&#xff0c;故将此部…

程序员必知的三款在线绘图工具

文章目录2.draw.io3.Lucidchart4.PrcessOn5.小结正所谓“一图胜千言”&#xff0c;无论是商务办公、PPT 演示、学习总结、技术交流、项目开发&#xff0c;我们常常都需要制作一些图表、流程图、架构图来更直观地呈现内容以及归类整理知识点。 今天就来说下程序员们常用的三款在…

【矩阵论】正规方程——生成子空间

5.1 子空间 5.1.1. 定义 设 W⊂CnW\subset C^nW⊂Cn &#xff0c;即子空间对线性组合封闭 若(1)对∀α,β∈W&#xff0c;有αβ∈W(对加法封闭)(2)对∀α∈W,∀k∈C&#xff0c;有kα∈W(对数乘封闭)\begin{aligned} 若 &(1)对\forall \alpha,\beta\in W&#xff0c;有\…

秋招失利,拿到这份“Java 高分指南(25 专题)”,金三银四翻盘有望

面试造火箭&#xff0c;工作拧螺丝&#xff01;金九银十灰溜溜地落榜&#xff0c;备受打击。正当准备明年金三银四之际&#xff0c;意外喜提朋友赠送的这“Java 高分指南&#xff08;25 专题&#xff09;”&#xff1a;Elasticsearch、微服务、Linux、JavaOOP、集合/泛型、Mysq…

Flutter高仿微信-第57篇-添加好友

Flutter高仿微信系列共59篇&#xff0c;从Flutter客户端、Kotlin客户端、Web服务器、数据库表结构、Xmpp即时通讯服务器、视频通话服务器、腾讯云服务器全面讲解。 详情请查看 效果图&#xff1a; 实现代码&#xff1a; /*** Author : wangning* Email : maoning20080809163.c…

ThreadLocal

文章目录一、ThreadLocal是什么二、ThreadLocal作用三、ThreadLocal的设计结构早期:现在:四、ThreadLocal核心方法1. set方法2. get方法3. remove方法五、ThreadLocal内存泄漏六、使用场景七、参考资料前言&#xff1a; 再写博客时&#xff0c;遇到了如何处理保存用户的信息时出…

基于共享储能电站的工业用户 日前优化经济调度matlab程序(yalmip+cplex)(yalmip+gurobi)

基于共享储能电站的工业用户 日前优化经济调度matlab程序&#xff08;yalmipcplex&#xff09;&#xff08;yalmipgurobi&#xff09; 参考文献&#xff1a;基于共享储能电站的工业用户 日前优化经济调度 摘要: 文章提出一种基于共享储能电站的工业用户日前优化经济调度方法。…

nginx反向代理,负载均衡配置

文章目录一.nginx代理简介二.nginx配置简介三.nginx作为反向代理的配置四.nginx作为负载均衡的配置五.使用nginx代理的坑一.nginx代理简介 其实nginx作为代理有两种 正向代理: 隐藏客户端的信息;如科学上网 反向代理: 隐藏服务端的信息;如负载均衡 二.nginx配置…

11.26

目录 一.做题出错 1. 2.数组长度的一半 3.选择题 二.优先级队列(堆) 1.二叉树的顺序存储 1.1 存储方式 1.2下标关系 2.堆(heap) 2.1概念 2.2 操作-向下调整 三 建堆 四.优先级队列 1 概念 2 内部原理 3.操作-入队 offer() 4.操作-出队 五.计算糖果 一.做题出错…

docker如何下载国外镜像

目录背景解决方案1、创建阿里云镜像仓库2、使用https://labs.play-with-docker.com下载镜像3、将镜像上传到阿里云镜像仓库4、从阿里云镜像仓库中拉取镜像到我们linux系统中5、改变我们linux系统中拉取的镜像名称背景 今天在安装grafana和prometheus&#xff0c;但是在下载下面…

Java数据结构

目录 1、栈 2、队列 3、数组 4、链表 5、树 7、平衡二叉树 8、红黑树 1、栈 特点&#xff1a;先进后出&#xff0c;后进先出 数据进入栈模型的过程称为:压/进栈 数据离开栈模型的过程称为:弹/出栈 2、队列 特点&#xff1a;先进先出&#xff0c;后进后出 数据从后…

MyBatis-Plus中的更新操作(通过id更新和条件更新)

目录 前言 一、通过id更新 二、条件更新 2.1 使用QueryWrapper进行条件更新 2.2 使用UpdateWrapper进行条件更新 总结 前言 本文学习MP中的更新操作方法&#xff0c;带大家一起查看源码&#xff0c;了解更新操作的方法。学会熟练地去运用更新方法解决自己在项目中的问题…

Linus 文件处理(三)

目录 一、前言 二、扫描目录 1、opendir 2、readdir 3、telldir 4、seekdir 5、 closedir 6、A Directory-Scanning Program 三、Errors 1、strerror 2、perror 一、前言 本文将简单介绍Linux文件和目录&#xff0c;以及如何操作它们&#xff08;如何创建文件、打开…

独家 | 使用python马尔科夫链方法建模星巴克等待时长

作者&#xff1a;Piero Paialunga翻译&#xff1a;陈超校对&#xff1a;和中华本文约4200字&#xff0c;建议阅读11分钟本文使用马尔科夫链的方法对星巴克购买咖啡的等待时长进行建模。以下内容关于如何使用马尔科夫链计算你在星巴克咖啡的等待时长。图片来自Unplash&#xff0…

Spring - ApplicationContextInitializer 扩展接口

文章目录Preorg.springframework.context.ApplicationContextInitializer扩展点扩展接口扩展生效方式方式一 &#xff1a; Spring SPI扩展方式二 &#xff1a; 配置文件方式三 &#xff1a;启动类手工add测试结果Pre Spring Boot - 扩展接口一览 org.springframework.context.…

详解诊断数据库ODX-C

文章目录 前言一、ODX—C作用是什么?二、ODX-C数据库在工具ODXStudio的编辑方法总结前言 ODX是全球通用的一种诊断数据库格式,相比CDD文件(Vector公司私有的一种数据库格式),应用场景和范围更广,包含了不同的子类: ODX-C\-D\-V\-E\-F\-FD 今天这篇文章仅对ODX-C做一个…

开源物联网系统 ThingsBoard 上手

开源物联网系统 ThingsBoard 上手 centos yum 被占用问题解决&#xff1a; 描述&#xff1a;Another app is currently holding the yum lock; waiting for it to exit 参考&#xff1a;https://blog.csdn.net/Dan1374219106/article/details/112450922 查看yum占用&#xff1a…