ICP算法加速优化--多线程和GPU

news2025/7/31 2:07:55

LZ之前的文章ICP算法实现(C++) 用C++实现了基础的ICP算法,由于该算法是一种迭代的优化算法,里面含有大量循环操作以及矩阵运算,可以通过使用多线程或者GPU硬件来进行加速,具体分别可以通过OpenMP和CUDA编程实现。这里给出的代码是根据github地址:https://github.com/alex-van-vliet/icp的代码改写的。原作者的代码质量还是不错的,有许多值得借签和学习的地方。但是考虑到使用的第三方库太多不便于配置和使用,LZ把这份代码重构了一下。原作者在代码里造了很多轮子,比如自己实现了Point3D、matrix以及vp-tree(也是一种搜索树,比原PCL中的kd-tree出现时间略晚)的数据结构,但是SVD分解还是调用了Eigen库(可能他也觉得底层实现太麻烦了吧~),LZ把这里面的矩阵结构统一用Eigen库实现了。另外去掉了一些不方便编译的第三方库,并简化了CmakeLists的内容以及程序的结构。如果只编译libcpu库只需依赖Eigen,编译libgpu库的话需要CUDA。

该工程的运行效果如下所示:
lib_icp.exe line1.pcd line2.pcd --cpu 100 1e-6 32 0ms
lib_icp.exe line1.pcd line2.pcd --cpu 100 1e-6 32 2ms(OpenMP)
lib_icp.exe line1.pcd line2.pcd --gpu 100 1e-6 1024 81ms
lib_icp.exe bunny1.pcd bunny2.pcd --cpu 100 1e-6 32 1407ms
lib_icp.exe bunny1.pcd bunny2.pcd --cpu 100 1e-6 32 246ms(OpenMP)
lib_icp.exe bunny1.pcd bunny2.pcd --gpu 100 1e-6 1024 156ms
lib_icp.exe horse1.pcd horse2.pcd --cpu 100 1e-6 32 12585ms
lib_icp.exe horse1.pcd horse2.pcd --cpu 100 1e-6 32 1603ms(OpenMP)
lib_icp.exe horse1.pcd horse2.pcd --gpu 100 1e-6 1024 363ms
测试平台为Windows10系统,内存32G,CPU是i7-12700(20线程),GPU是NVIDIA GeForce RTX 3070 Laptop GPU(8G);修改后的代码在linux系统也能编译,本人在WSL(Ubuntu20.04)的docker中测试过和Windows本地差别不大,但是调用CUDA版本代码计算结果有误。其中line1.pcd和line2.pcd点数为10,bunny1.pcd和bunny2.pcd点数为35947,horse1.pcd和horse2.pcd点数为193940。可以看出多核和GPU的加速作用随着点云点数增加优势还是非常明显的,但是点数非常少的话,GPU由于需要和CPU进行数据传输,此时运算速度会不太理想。

自己写了测试main函数,可以直接读取.pcd格式的点云文件(读取二进制储存的pcd文件更为高效,原作者代码是读.txt文件),并添加了时间计算部分和可视化部分,需要另外配置PCL库。

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/common/transforms.h>

#ifdef _WIN32
	#include <ctime>
	#include <pcl/visualization/pcl_visualizer.h>
#endif

#ifdef __linux__
	#include <sys/time.h>
#endif

#include "libcpu/icp.h"
#include "libgpu/icp.h"


int main(int argc, char* argv[])
{
	std::cout << "\033[31mUsage:	.exe <source .pcd> <target .pcd> --cpu|gpu <iterations> <error> <capacity>\n"
		<< "for example:	./lib_icp.exe bunny1.pcd bunny2.pcd  --gpu 100 1e-6 1024\033[0m" << std::endl;

	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_src(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::io::loadPCDFile(argv[1], *cloud_src);

	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_tgt(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::io::loadPCDFile(argv[2], *cloud_tgt);

	bool use_gpu = (std::string(argv[3]) == "--gpu");
	if (use_gpu)	std::cout << "use gpu" << std::endl;
	else	std::cout << "use cpu" << std::endl;

	size_t iterations = std::atoi(argv[4]);
	std::cout << "max iterations:" << iterations << std::endl;

	float error = std::atof(argv[5]);
	std::cout << "error:" << error << std::endl;

	int capacity = std::atoi(argv[6]);
	std::cout << "capacity:" << capacity << std::endl;

	std::vector<Eigen::Vector3f> p(cloud_src->size());
	std::vector<Eigen::Vector3f> q(cloud_tgt->size());
	for (size_t i = 0; i < cloud_src->size(); i++)
	{
		p[i] = cloud_src->points[i].getVector3fMap();
	}
	for (size_t i = 0; i < cloud_tgt->size(); i++)
	{
		q[i] = cloud_tgt->points[i].getVector3fMap();
	}

#ifdef _WIN32
	clock_t start = clock();
#endif

#ifdef __linux__
	struct timeval start, end;
	gettimeofday(&start, 0);
#endif

	auto [transformation, new_p] = (use_gpu ? libgpu::icp(q, p, iterations, error, capacity): libcpu::icp(q, p, iterations, error, capacity));


#ifdef _WIN32
	clock_t end = clock();
	std::cout << "time cost:" << end - start << "ms" << std::endl;
#endif

#ifdef __linux__
	gettimeofday(&end, 0);
	std::cout << "time cost:" << (1000000.0 * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec) / 1000.0 << "ms" << std::endl;
#endif
	
	std::cout << "transformation matrix: \n" << transformation << std::endl;

	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_icp(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::transformPointCloud(*cloud_src, *cloud_icp, transformation);
	pcl::io::savePCDFile("cloud_icp.pcd", *cloud_icp);

#ifdef _WIN32
	pcl::visualization::PCLVisualizer viewer("registration Viewer");
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(cloud_src, 0, 255, 0); 	//原始点云绿色
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h(cloud_tgt, 255, 0, 0); 	//目标点云红色
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> final_h(cloud_icp, 0, 0, 255); 	//匹配好的点云蓝色

	viewer.setBackgroundColor(0, 0, 0);
	viewer.addPointCloud(cloud_src, src_h, "source cloud");
	viewer.addPointCloud(cloud_tgt, tgt_h, "target cloud");
	viewer.addPointCloud(cloud_icp, final_h, "result cloud");
	while (!viewer.wasStopped())
	{
		viewer.spinOnce(100);
	}
#endif

	return 0;
}

工程结构如下:
在这里插入图片描述

运行结果截图:
在这里插入图片描述在这里插入图片描述

代码和数据集下载地址如下:
工程下载链接

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

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

相关文章

六、【React基础】组件实例三大核心属性之三 refs + 事件处理

文章目录1、字符串形式的ref&#xff08;过时/不推荐&#xff09;2、回调形式的ref&#xff08;推荐&#xff01;&#xff01;&#xff01;&#xff09;● 回调ref中回调次数的问题3、createRef创建ref容器&#xff08;最新最推荐&#xff09;4、事件处理理解&#xff1a;组件内…

Web3D应用开发在线IDE【中文版】

nunuStudio 是一个Web 3D应用程序的集成开发环境&#xff0c;它提供用于在 3D 世界中创建和编辑对象的工具&#xff0c;支持JavaScript和Python对3D场景进行二次开发。nunuStudio中文版 由 BimAnt 提供。 如果你曾经使用过其他类似的框架&#xff08;unity、playcanvas、godot …

Spring Boot 3.0 正式发布了!一个超重要的版本!!

首发于 JavaGuide (「Java学习面试指南」一份涵盖大部分 Java 程序员所需要掌握的核心知识。准备 Java 面试&#xff0c;首选 JavaGuide&#xff01;) 紧跟着 Spring Framework 6.0 的正式发布&#xff0c;就在昨天&#xff0c;Spring Boot 3.0 也正式发布了&#xff01; 这是一…

供应多臂PEG衍生物4-Arm PEG-Azide,4-Arm PEG-N3,四臂-聚乙二醇-叠氮

1、名称 英文&#xff1a;4-Arm PEG-Azide&#xff0c;4-Arm PEG-N3 中文&#xff1a;四臂-聚乙二醇-叠氮 2、CAS编号&#xff1a;N/A 3、所属分类&#xff1a;Azide PEG Multi-arm PEGs 4、分子量&#xff1a;可定制&#xff0c;四臂-PEG 2000-叠氮、4-Arm PEG-N3 20000、…

深入分析序列化和反序列化原理,终于知道serialVersionUID到底有什么用了

一个问题引发的思考 下面是一个简单的socket通信demo。 通信数据类&#xff1a; package com.zwx.serialize.demo; public class SocketUser { public SocketUser(String id, String name) {this.id id;this.name name; }private String id; private String name;public St…

ADAU1860调试心得(2)硬件和软件的详细说明

硬件 一台64位的PC&#xff0c;一块ADAU1860EVB开发板&#xff0c;一个LARK-1860专用仿真器&#xff0c;音频线若干&#xff0c;mini USB线一根&#xff0c;一个到三个输入音源&#xff0c;可以是PC或者手机或者其他模拟音频输入设备&#xff0c; 一个输出音源设备&#xff0c;…

什么是DCS系统?DCS和SCADA的区别

如果你在工业自动化的企业环境中操作&#xff0c;可能听说过分布式控制系统 (DCS) 和监控和数据采集 (SCADA) 系统。 DCS系统和SCADA系统有很多共同点&#xff0c;因为它们都被称为受控计算机系统&#xff0c;接收和评估合法数据以实现远程访问监控和管理。 DCS(分布式控制系…

Python实现BP神经网络ANN单隐层分类模型项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 BP(back propagation)神经网络是1986年由Rumelhart和McClelland为首的科学家提出的概念&#xff0c;是一…

内外通、效益增 | 数商云•瓴犀产品3.0开启全方位精准精细化协同模式

今年以来&#xff0c;芯片短缺、原材料价格飙升、集装箱价格高企等现象再次将国内外供应链问题推到了聚光灯下。在这种背景下&#xff0c;供应链协同的重要性日益凸显&#xff0c;供应链协同的趋势正在加速。一方面&#xff0c;随着电子商务、直播等前端消费场景的多样化&#…

The Sandbox 与韩流 Web 3.0 初创企业 Modhaus 达成合作

此合作关系旨在与韩流女团「tripleS」一起开展元宇宙业务。 简要概括 创建一个粉丝参与的社交中心并举办各种活动。 发布 tripleS NFT、人物化身的可穿戴设备和数位收藏品。 Modhaus 和 The Sandbox 将创建一个社交中心&#xff0c;让粉丝参与在元宇宙举办的活动&#xff0c;以…

基于MxNet实现目标检测-FasterRCNN【附部分源码及模型】

文章目录前言目标检测发展史及意义一、数据集的准备1.标注工具的安装2.数据集的准备3.标注数据4.解释xml文件的内容二、网络结构的介绍三、代码实现0.工程目录结构如下1.导入库2.配置GPU/CPU环境3.数据加载器4.模型构建5.模型训练1.学习率设置2.优化器设置3.损失设置4.循环训练…

流程编排、如此简单-通用流程编排组件JDEasyFlow介绍

作者&#xff1a;李玉亮 JDEasyFlow是企业金融研发部自研的通用流程编排技术组件&#xff0c;适用于服务编排、工作流、审批流等场景&#xff0c;该组件已开源(https://github.com/JDEasyFlow/jd-easyflow)&#xff0c;目前在部门的内部业务系统和科技输出系统中广泛应用&…

项目经理年终夜话:我的“第二年状态”

近日&#xff0c;网络热词“第二年状态”又引发了网友们的热议&#xff0c;是指最初的热情消磨后&#xff0c;幻想破灭&#xff0c;在理想与现实巨大落差面前&#xff0c;陷入迷茫与彷徨。 而“如何度过第二年状态&#xff1f;”这一话题也被大家讨论和分享。其中&#xff0c;贾…

分布式文件系统HDFS实践及原理详解part3

HDFS原理 说明&#xff1a;3.5开头目录是因为和上篇文章内容同属一章&#xff0c;所以开头使用了3.5 3.5 HDFS核心设计 3.5.1 心跳机制 1、 Hadoop 是 Master/Slave 结构&#xff0c;Master 中有 NameNode 和 ResourceManager&#xff0c;Slave 中有 Datanode 和 NodeManag…

Milvus 2.2 版本发布!

经过了 4 个月的打磨&#xff0c;Milvus 2.2.0 于 11 月 18 日正式发版&#xff01;2.2 版本推出了包括基于磁盘的近似最近邻&#xff08;ANN&#xff09;索引算法、从文件批量导入数据、基于角色的访问控制等新特性。进一步提升了向量搜索的稳定性、搜索速度和灵活的扩缩容能力…

新建 ASP.NET MVC 三层项目 | 新建 ASP.NET MVC 项目

打开Visual Studio 2019、 点击创建新项目、 在列表中找到:ASP.NET Web应用程序(.NET Framework):用于创建ASP.NET应用程序的项目模板。你可以创建ASP.NET Web Forms、MVC或Web API应用程序,并可以在ASP.NET中添加许多其他功能、 输入项目名称、输入存储位置、输入解决方…

挂耳式蓝牙耳机哪家的好用,列举五款舒适度极佳的耳机分享

谈到骨传导耳机&#xff0c;相信大家都会想到不入耳的佩戴设计&#xff0c;因为这个特性让骨传导耳机迅速席卷整个年轻一代的圈子&#xff0c;相比于传统式的耳机&#xff0c;骨传导耳机在一定程度上是对耳道是具有一定的保护&#xff0c;这也就是为什么骨传导耳机深受群众喜爱…

深入理解Linux网络技术内幕(九)——中断和网络驱动程序

文章目录前言决策和流量方向接收到帧时通知驱动程序轮询中断在中断期间处理多帧定时器驱动的中断事件组合范例中断处理函数下半部函数存在的原因下半部解决方案并发和上锁抢占功能下半部函数微任务软IRQ初始化未决软IRQ的处理__do_softirq函数依体系结构处理软IRQksoftirqd内核…

优维EasyOps,打造新一代运维新方式

数字经济时代&#xff0c;数字技术与企业业务深度融合&#xff0c;越来越多企业开始认识到&#xff0c;IT正在从内部的支撑工具转变为企业发展的核心竞争力。然而&#xff0c;面对信息建设不断深化、系统架构日趋复杂、新兴技术快速迭代等诸多挑战&#xff0c;企业如何在复杂的…

mini-Imagenet处理

由于imagenet-1k 数据集太大&#xff0c;在验证模型方面耗时太久&#xff0c;特意研究了一下mini-Imagenet&#xff0c;用来代替imageNet-1K数据集。 2016年google DeepMind团队从Imagnet数据集中抽取的一小部分&#xff08;大小约3GB&#xff09;制作了Mini-Imagenet数据集&a…