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

这篇具有很好参考价值的文章主要介绍了ICP算法加速优化--多线程和GPU。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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 (CPU单核,0ms)
lib_icp.exe line1.pcd line2.pcd --cpu 100 1e-6 32 (CPU多核,2ms)
lib_icp.exe line1.pcd line2.pcd --gpu 100 1e-6 1024 (GPU,81ms)
lib_icp.exe bunny1.pcd bunny2.pcd --cpu 100 1e-6 32 (CPU单核,1407ms)
lib_icp.exe bunny1.pcd bunny2.pcd --cpu 100 1e-6 32 (CPU多核,246ms)
lib_icp.exe bunny1.pcd bunny2.pcd --gpu 100 1e-6 1024 (GPU,156ms)
lib_icp.exe horse1.pcd horse2.pcd --cpu 100 1e-6 32 (CPU单核,12585ms)
lib_icp.exe horse1.pcd horse2.pcd --cpu 100 1e-6 32 (CPU多核,1603ms)
lib_icp.exe horse1.pcd horse2.pcd --gpu 100 1e-6 1024 (GPU,363ms)
Release模式下编译,测试平台为Windows10系统,内存32G,CPU是i7-12700(20线程),GPU是NVIDIA GeForce RTX 3070 Laptop GPU(显存8G,每个block最大线程数为1024),计算的运行时间为三次求平均值。修改后的代码在linux系统也能编译,本人在WSL(Ubuntu20.04)的docker中测试过和Windows本地差别不大,但是调用CUDA版本代码计算结果有误。line1.pcd和line2.pcd点数为10,bunny1.pcd和bunny2.pcd点数为35947,horse1.pcd和horse2.pcd点数为193940;另外LZ调用PCL库计算这三组点云ICP配准耗时分别为0ms,758ms,30550ms。可以看出多核和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;
}

工程结构如下:
多线程icp怎么实现,CUDA,PCL,6D pose estimation,点云,ICP算法,OpenMP,CUDA

运行结果截图:
多线程icp怎么实现,CUDA,PCL,6D pose estimation,点云,ICP算法,OpenMP,CUDA多线程icp怎么实现,CUDA,PCL,6D pose estimation,点云,ICP算法,OpenMP,CUDA
附:调用PCL库ICP配准API的测试代码:

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/registration/icp.h>


int main(int argc, char* argv[])
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_src(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_tgt(new pcl::PointCloud<pcl::PointXYZ>);

	pcl::io::loadPCDFile(argv[1], *cloud_src);
	pcl::io::loadPCDFile(argv[2], *cloud_tgt);

	clock_t start = clock();

	pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp;
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_icp_registration(new pcl::PointCloud<pcl::PointXYZ>);
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree1(new pcl::search::KdTree<pcl::PointXYZ>);
	pcl::search::KdTree<pcl::PointXYZ>::Ptr tree2(new pcl::search::KdTree<pcl::PointXYZ>);
	tree1->setInputCloud(cloud_src);
	tree2->setInputCloud(cloud_tgt);
	icp.setSearchMethodSource(tree1);
	icp.setSearchMethodTarget(tree2);
	icp.setInputSource(cloud_src);
	icp.setInputTarget(cloud_tgt);
	icp.setEuclideanFitnessEpsilon(1e-6);
	icp.setMaximumIterations(100);
	Eigen::Matrix4f transformation = Eigen::MatrixXf::Identity(4, 4);
	icp.align(*cloud_icp_registration, transformation);

	clock_t end = clock();
	std::cout << end - start << "ms" << std::endl;

	Eigen::Matrix4f transformation_icp = icp.getFinalTransformation();
	std::cout << transformation_icp << std::endl;
	std::cout << "ICP has converged:" << icp.hasConverged() << " score: " << icp.getFitnessScore() << std::endl;

	pcl::transformPointCloud(*cloud_src, *cloud_icp_registration, transformation_icp);
	pcl::io::savePCDFileBinary("icp.pcd", *cloud_icp_registration);

	return 0;
}

代码和数据集下载地址如下:
工程下载链接文章来源地址https://www.toymoban.com/news/detail-705946.html

到了这里,关于ICP算法加速优化--多线程和GPU的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【PCL】—— 点云配准ICP(Iterative Closest Point)算法

    ​     由于三维扫描仪设备受到测量方式和被测物体形状的条件限制,一次扫描往往只能获取到局部的点云信息,进而需要进行多次扫描,然后每次扫描时得到的点云都有独立的坐标系,不可以直接进行拼接。在逆向工程、计算机视觉、文物数字化等领域中,由于点云的

    2024年02月13日
    浏览(37)
  • ICP + Apriltag 实现机器人自动接驳/充电

    感谢@Cuma Özavcı 提供的ros可用的开源ICP算法 如果感兴趣,可以去Pattern Matching on 2D Lidar Data看一下作者本人的描述 先描述一下大概的使用场景,我做这个是因为公司实际要用到这个模块,所以在主管的指导下看了这个包,然后改吧改吧,跟现有的一些东西做了结合,最终完成

    2024年02月11日
    浏览(28)
  • 【视觉SLAM入门】5.2. 2D-3D PNP 3D-3D ICP BA非线性优化方法 数学方法SVD DLT

    前置事项: 该问题描述为:当我们知道n 个 3D 空间点以及它们的投影位置时,如何估计相机所在的位姿 1.1.1 DLT(直接线性变换法) 解决的问题:已知空间点 P = ( X , Y , Z , 1 ) T P = (X, Y, Z, 1)^T P = ( X , Y , Z , 1 ) T 和它投影点 x 1 = ( u 1 , v 1 , 1 ) T x_1 = (u_1, v_1, 1)^T x 1 ​ = ( u 1 ​ , v 1

    2024年02月12日
    浏览(26)
  • ICM-42670-P 六轴运动传感器 & TDK ICP-10740 气压计实现运动监测

    ICM-42670-P 六轴运动传感器 TDK ICP-10740 气压计,配合 CyweeMotion 算法,实现了运动监测。CyweeMotion 算法不仅支持多种运动模式:如走路、跑步、瑜伽、椭圆机、游泳等等,同时包含睡眠检测及手势识别(抬腕)等丰富的智能手表必备运动监测模型。 针对行为识别,Cywee 活动感测

    2024年02月09日
    浏览(29)
  • matlab 点云精配准(1)——point to point ICP(点到点的ICP)

    本文由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 [1] BESL P J,MCKAY N D.A method for registration of 3-Dshapes[J].IEEE Transactions on Pattern Analysis and Machine Intelligence,1992,14( 2) : 239-256. [2]王明军,易芳,李乐,黄朝军.自适应局部邻域特征点

    2024年02月12日
    浏览(29)
  • 点云配准--对称式ICP

    对称式ICP 针对于局部平面不完美的情况,提出了一种对称式ICP目标函数,相较于传统的ICP方法,增大了收敛域,提高了收敛速度。论文理论说明不甚清楚,实验较少,但代码开源。 对称目标函数 在icp中对于一对对应点p,q:在点到法线的度量中: ( p − q ) ⋅ n q (3) (p-q) cd

    2024年02月06日
    浏览(35)
  • 个人申请阿里云ICP备案流程

    一、前期准备 1、阿里云备案前提 一台阿里云服务器 拥有一个域名 从这里进入ICP备案,开始备案流程 2、阿里云备案优势 支持APP备案 24小时急速初审(三小时内就已进入初审流程) 备案用时多久送多久(我这里送了16天) 二、提交审核 1、填写信息,这里需要填写主办人的

    2024年02月06日
    浏览(31)
  • Ubuntu 安装 CUDA 与 CUDNN GPU加速引擎

            NVIDIA显卡驱动可以通过指令 sudo apt purge nvidia* 删除以前安装的NVIDIA驱动版本,重新安装。         注意!在安装NVIDIA驱动以前需要禁止系统自带显卡驱动nouveau:可以先通过指令 lsmod | grep nouveau 查看nouveau驱动的启用情况,如果有输出表示nouveau驱动正在工作,如

    2024年02月07日
    浏览(32)
  • 自适应点云配准(RANSAC、ICP)

    完整代码:https://github.com/kang-0909/point-cloud-registration/tree/main,记得给个star~ 任务一:将两个形状、大小相同的点云进行配准,进而估计两个点云之间的位姿。 任务二:将一些列深度图反向投影得到点云,经过配准后,得到每个深度图之间的位姿变换,并将相应的点云融合到一

    2024年02月02日
    浏览(29)
  • 配置Tensorflow使用CUDA进行GPU加速(超详细教程)

    对于刚使用Tensorflow的友友来说配置环境并使用GPU进行加速也是件令人头疼的事情,纯自己折腾会遇到比较多的坑,所以这里详细介绍一下Tensorflow的环境配置 先进入官网查看Tensorflow依赖信息: 目前Tensorflow版本已经更新到2.16.1但是中文官网发布的最新经过测试的构建配置的

    2024年04月22日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包