open3d和pcl点云转换及多线程加速

news2024/10/10 18:25:28

目录

  • 写在前面
  • 准备
  • 转换源码
  • 编译
  • 运行
    • 结果
  • 参考

写在前面

1、本文内容
open3d和pcl点云互转,并使用多线程加速

2、平台/环境
通过cmake构建项目,跨平台通用;open3d,pcl
3、转载请注明出处:
https://blog.csdn.net/qq_41102371/article/details/131891685

准备

编译open3d 参考:
open3d0.17.0
https://blog.csdn.net/qq_41102371/article/details/131891820
open3d0.13:
https://blog.csdn.net/qq_41102371/article/details/121014372
pcl1.10.0
https://blog.csdn.net/qq_41102371/article/details/107312948
pcl1.8
https://blog.csdn.net/qq_41102371/article/details/106176870

转换源码

创建文件夹

mkdir open3d2pcl
cd open3d2pcl
mkdir src

open3d2pcl/CMakeLists.txt

cmake_minimum_required(VERSION 3.18)

project(pcd_convert)

find_package(PCL 1.5 REQUIRED)

option(STATIC_WINDOWS_RUNTIME "Use static (MT/MTd) Windows runtime" 
if(STATIC_WINDOWS_RUNTIME)
  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
else()
  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL")
endif()

find_package(Open3D REQUIRED)
include_directories(
  ${Open3D_INCLUDE_DIRS}
  ${PROJECT_SOURCE_DIR}
)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_subdirectory(pcd_converter)

add_executable(convert_test convert_test.cpp)
target_link_libraries(convert_test ${Open3D_LIBRARIES})
target_link_libraries(convert_test pcd_converter)

open3d2pcl/convert_test.cpp

#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#include "pcd_converter/pcd_converter.h"

int main(int argc, char *argv[])
{

    int num_thread = open3d::utility::GetProgramOptionAsInt(argc, argv, "--num_thread", 5);
    std::string path_pcd = "";
    path_pcd = open3d::utility::GetProgramOptionAsString(argc, argv, "--path_pcd", "");
    if (path_pcd.empty())
    {
        open3d::utility::LogError("path_pcd is empty, please use --path_pcd specific a correct path", path_pcd);
    }
    open3d::utility::LogInfo("num_thread: {}, path_pcd: {}", num_thread, path_pcd);

    std::shared_ptr<open3d::geometry::PointCloud> pcd_o3d(new open3d::geometry::PointCloud);
    pcl::PointCloud<pcl::PointXYZ>::Ptr pcd_pcl(new pcl::PointCloud<pcl::PointXYZ>);
    open3d::io::ReadPointCloud(path_pcd, *pcd_o3d);
    if (nullptr == pcd_o3d || pcd_o3d->IsEmpty())
    {
        open3d::utility::LogError("can not read pointcloud from file: {}", path_pcd);
    }
    else
    {
        open3d::utility::LogInfo("read {} points from {}", pcd_o3d->points_.size(), path_pcd);
    }

    for (int i = 0; i < 5; ++i)
    {
        std::cout << "\n\n"
                  << std::endl;
        open3d::visualization::DrawGeometries({pcd_o3d}, "pcd_o3d_origin");
        auto cvt2pcl_s = std::chrono::high_resolution_clock::now();
        pcd_pcl = pcd_converter::CvtO3DToPCL(pcd_o3d, num_thread);
        auto cvt2pcl_e = std::chrono::high_resolution_clock::now();
        double cvt2pcl_cost = std::chrono::duration_cast<std::chrono::microseconds>(cvt2pcl_e - cvt2pcl_s).count() / 1000;
        open3d::utility::LogInfo("convert {} points to pcl, cost {} ms", pcd_o3d->points_.size(), cvt2pcl_cost);

        auto cvt2o3d_s = std::chrono::high_resolution_clock::now();
        pcd_o3d = pcd_converter::CvtPCLToO3D(pcd_pcl, num_thread);
        auto cvt2o3d_e = std::chrono::high_resolution_clock::now();
        double cvt2o3d_cost = std::chrono::duration_cast<std::chrono::microseconds>(cvt2o3d_e - cvt2o3d_s).count() / 1000;
        open3d::utility::LogInfo("convert {} points to open3d, cost {} ms", pcd_pcl->points.size(), cvt2o3d_cost);
        open3d::visualization::DrawGeometries({pcd_o3d}, "form pcl");
    }
    return 0;
}

open3d2pcl/src/CMakeLists.txt

cmake_minimum_required(VERSION 3.18)

find_package(Open3D REQUIRED)

add_library(pcd_converter pcd_converter.cpp)
target_link_libraries(pcd_converter ${Open3D_LIBRARIES})

open3d2pcl/src/pcd_converter.h

#pragma once
#include <iostream>
#include <string>
#include <thread>
#include <vector>

#include <open3d/Open3D.h>

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>

namespace pcd_converter
{
    /// @brief 将open3d点云转为pcl点云
    /// @param pc
    /// @param num_thread 使用的线程数量
    /// @return
    pcl::PointCloud<pcl::PointXYZ>::Ptr
    CvtO3DToPCL(std::shared_ptr<open3d::geometry::PointCloud> pc,
                int num_thread = 5);

    /// @brief 将pcl点云转为open3d
    /// @param pc
    /// @param num_thread 使用的线程数量
    /// @return
    std::shared_ptr<open3d::geometry::PointCloud>
    CvtPCLToO3D(pcl::PointCloud<pcl::PointXYZ>::Ptr pc,
                int num_thread = 5);

    inline bool CompareIndicesSize(std::vector<std::size_t> a,
                                   std::vector<std::size_t> b)
    {
        return a.size() >= b.size();
    }
    void ThreadAssignment(int num_thread, int data_size, std::vector<int> &data_in_each_thread);
} // namespace pcd_converter

open3d2pcl/src/pcd_converter.cpp

#include "pcd_converter.h"

namespace pcd_converter
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr CvtO3DToPCL(std::shared_ptr<open3d::geometry::PointCloud> pc,
                                                    int num_thread)
    {
        // 给线程分配数据
        std::vector<int> data_in_each_thread;
        ThreadAssignment(num_thread, pc->points_.size(), data_in_each_thread);

        pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ptr(new pcl::PointCloud<pcl::PointXYZ>);
        cloud_ptr->resize(pc->points_.size());

        auto convert_thread = [&](int id, std::vector<int> data)
        {
            // std::cout << "id: " << id << " data[i]: " << data[id] << std::endl;
            for (std::size_t i = id * data[0]; i < id * data[0] + data[id]; ++i)
            {
                cloud_ptr->points[i].x = pc->points_[i].x();
                cloud_ptr->points[i].y = pc->points_[i].y();
                cloud_ptr->points[i].z = pc->points_[i].z();
            }
        };

        std::vector<std::thread> vec_convert_thread;

        for (std::size_t i = 0; i < data_in_each_thread.size(); ++i)
        {
            vec_convert_thread.push_back(std::thread(convert_thread, i, data_in_each_thread));
        }

        for (std::size_t i = 0; i < vec_convert_thread.size(); ++i)
        {
            vec_convert_thread[i].join();
        }
        return cloud_ptr;
    }
    std::shared_ptr<open3d::geometry::PointCloud> CvtPCLToO3D(pcl::PointCloud<pcl::PointXYZ>::Ptr pc,
                                                              int num_thread)
    {
        // 给线程分配数据
        std::vector<int> data_in_each_thread;
        ThreadAssignment(num_thread, pc->points.size(), data_in_each_thread);

        auto open3d_cloud_ptr = std::make_shared<open3d::geometry::PointCloud>();
        open3d_cloud_ptr->points_.resize(pc->points.size());

        auto convert_thread = [&](int id, std::vector<int> data)
        {
            // std::cout << "id: " << id << " data[i]: " << data[id] << std::endl;
            for (std::size_t i = id * data[0]; i < id * data[0] + data[id]; ++i)
            {
                open3d_cloud_ptr->points_[i][0] = pc->points[i].x;
                open3d_cloud_ptr->points_[i][1] = pc->points[i].y;
                open3d_cloud_ptr->points_[i][2] = pc->points[i].z;
            }
        };

        std::vector<std::thread> vec_convert_thread;

        for (std::size_t i = 0; i < data_in_each_thread.size(); ++i)
        {
            vec_convert_thread.push_back(std::thread(convert_thread, i, data_in_each_thread));
        }

        for (std::size_t i = 0; i < vec_convert_thread.size(); ++i)
        {
            vec_convert_thread[i].join();
        }
        return open3d_cloud_ptr;
    }
    void ThreadAssignment(int num_thread, int data_size, std::vector<int> &data_in_each_thread)
    {

        // 为每个线程分配的数据量
        // std::vector<int> data_N;
        // 如果数据量小于线程数,每个线程只用处理一个数据
        if (data_size <= num_thread)
        {
            data_in_each_thread = std::vector<int>(data_size, 1);
            return;
        }
        data_in_each_thread.clear();
        if (0 == data_size % num_thread)
        {
            data_in_each_thread = std::vector<int>(num_thread, data_size / num_thread);
        }
        else
        {
            data_in_each_thread = std::vector<int>(num_thread, data_size / num_thread + 1 - (num_thread > 10 ? 1 : 0));
            data_in_each_thread[num_thread - 1] = data_size - (data_size / num_thread + 1 - (num_thread > 10 ? 1 : 0)) * (num_thread - 1);
        }
    }

} // namespace pcd_converter

编译

windows: open3d2pcl/compile.bat

cmake -DCMAKE_BUILD_TYPE=Release ^
-DPCL_DIR="D:/carlos/install/PCL 1.10.0/cmake" ^
-DOpen3D_ROOT="D:/carlos/install/open3d141" ^
-S ./src -B ./build
cmake --build ./build --config Release --parallel 8 --target ALL_BUILD

linux: open3d2pcl/compile.sh

cmake -DCMAKE_BUILD_TYPE=Release \
-DPCL_DIR="your pcl path" \
-DOpen3D_ROOT="your open3d path" \
-S ./src -B ./build
cmake --build ./build --config Release --parallel 8

运行

windows: open3d2pcl/run.bat

.\build\Release\convert_test.exe ^
--path_pcd D:\data\xxx.ply ^
--num_thread 5

linux:

./build/convert_test.exe \
--path_pcd .../.../xxx.ply \
--num_thread 5

结果

读取18509670个点的点云进行测试,下面是不用多线程的结果
在这里插入图片描述

使用5个线程的结果:
在这里插入图片描述

参考

pcl之open3d数据与pcl数据相互转换

主要做激光/影像三维重建,配准、分割等常用点云算法,技术交流、咨询可私信

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

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

相关文章

【Visual Studio】VS调用tensorflow C++API的配置(无需编译)

1. 首先下载并安装visual studio Visual Studio 2015 安装教程&#xff08;附安装包&#xff09;&#xff0c;按照博客中顺序来就可以 如果在安装过程中提示安装包损失或毁坏&#xff0c;参考VS2015安装过程中安装包丢失或损坏解决办法 卡在哪个搜索文件上就找到哪个文件再继…

不同编程语言复现ELO匹配机制与机制原理理解

本章概述 从数学角度分析 分别用c java python演示算法机制 数学理论 预期胜率计算公式 积分算法 为什么排位比以前更难&#xff1f; elo使玩家尽量其股相当 双方实力进来保证持平elo算法基于预先假设: 一名选手的当前实力受各种因素的影响会在一定范围内波动&#xff0c;…

【VUE】vue3 SFC方式实现九宫格效果

效果图 调用方式 <template><grid class"grid-demo" isScale><grid-item class"grid-demo-item">1</bg-grid-item><grid-item class"grid-demo-item">2</bg-grid-item><grid-item class"grid-demo…

索引的数据结构

索引的数据结构 部分资料来自B站尚硅谷-宋红康老师 1. 为什么使用索引 使用索引是为了加快数据库的查询速度和提高数据库的性能。索引是数据库表中的一种数据结构&#xff0c;它可以帮助数据库快速定位并检索所需的数据。 当数据库表中的数据量较大时&#xff0c;如果没有索…

Training-Time-Friendly Network for Real-Time Object Detection 论文学习

1. 解决了什么问题&#xff1f; 目前的目标检测器很少能做到快速训练、快速推理&#xff0c;并同时保持准确率。直觉上&#xff0c;推理越快的检测器应该训练也很快&#xff0c;但大多数的实时检测器反而需要更长的训练时间。准确率高的检测器大致可分为两类&#xff1a;推理时…

uni-app:实现账号密码登录,并且实现当页面登录过该账号在下次登录时无需再输入账号密码(本地缓存实现)

效果 前端代码 一、完整代码 <template><view><view class"all"><view class"title"><image :src"title_login" alt"图片损坏" /></view><form class"login-form" submit"fo…

JAVA面试总结-Redis篇章(二)——缓存击穿

JAVA面试总结-Redis篇章&#xff08;二&#xff09; 缓存击穿解决方案一&#xff1a;互斥锁解决方案二&#xff1a;逻辑过期![在这里插入图片描述](https://img-blog.csdnimg.cn/176dfab3e26044a9a730fabea4314e8e.png) 缓存击穿 解决方案一&#xff1a;互斥锁 解决方案二&…

SpringBoot-5

Spring Boot 的项目属性配置 在项目中很多时候需要用到一些配置的信息&#xff0c;这些信息可能在测试环境和生产环境下会有不同的配置&#xff0c;后面根据实际业务情况有可能还会做修改&#xff0c;针对这种情况不能将这些配置在代码中写死&#xff0c;最好就是写到配置文件…

Rust vs Go:常用语法对比(六)

题图来自[1] 101. Load from HTTP GET request into a string Make an HTTP request with method GET to URL u, then store the body of the response in string s. 发起http请求 package mainimport ( "fmt" "io/ioutil" "net" "net/http…

Fiddler使用说明及中文绿化版

Fiddler是最常用的Web调试工具之一。 对于开发来说&#xff0c;前端可以通过fiddler代理来调试JS、CSS、HTML样式。后端可以通过fiddler查看请求和相应&#xff0c;定位问题。 对于测试来说&#xff0c;可以通过抓包方式修改前端请求参数和模拟后端返回&#xff0c;快速定位缺…

Pr LOGO平滑过渡效果

哈喽&#xff0c;各位小伙伴&#xff01;今天我们来学习一下如何制作LOGO平滑过渡效果&#xff1f; 准备工作 两个透明LOGO&#xff0c;一个水滴音效 ​新建序列 新建一个1920*1080的序列&#xff0c;将图片拖拽至轨道 CtrlR 图片时长设置为3SCtrlD 快速添加过渡效果右键…

【Python】生成md5码

目录 1 代码 2 运行结果 使用hashlib库来生成md5码。如下代码会生成Happy every day的md5哈希值。 1 代码 import hashlibdef generate_md5(string):md5 hashlib.md5()md5.update(string.encode(utf-8))return md5.hexdigest()if __name__ __main__:MD5 generate_md5(&qu…

测试开源C#人脸识别模块ViewFaceCore(3:人脸特征提取和对比)

ViewFaceCore模块的FaceRecognizer支持人脸特征提取和对比&#xff0c;将人脸中的关键信息转换为矢量信息&#xff0c;然后通过计算两个矢量的相似度以判断人脸的相似程序。   调用FaceRecognizer对比人脸相似度主要包括以下步骤&#xff1a;   1&#xff09;调用faceDetec…

第一百一十六天学习记录:C++提高:STL-string(黑马教学视频)

string基本概念 string是C风格的字符串&#xff0c;而string本质上是一个类 string和char区别 1、char是一个指针 2、string是一个类&#xff0c;类内部封装了char*&#xff0c;管理这个字符串&#xff0c;是一个char型的容器。 特点&#xff1a; string类内部封装了很多成员方…

idea社区版(2023.1)设置spring boot项目热启动

热启动 在开发过程中&#xff0c;当写完一个功能我们需要运行应用程序测试时需要重启服务器&#xff0c;一个最简单的项目也要花费10多秒&#xff0c;如果是更大的项目则耗时更多。SpringBoot提供了spring-boot-devtools&#xff0c;使得项目在发生改动时能够自动重启应用 id…

hadoop3编译安装

1.参考资料 官方的https://github.com/apache/hadoop/blob/trunk/BUILDING.txt 2.编译环境 Linux系统&#xff1a;Centos7.2 Jdk版本&#xff1a;jdk1.8 cmake版本&#xff1a;3.19 Hadoop版本&#xff1a;3.1.2 Maven版本&#xff1a;3.6.3 Protobuf版本&#xff1a;2…

【数据分析专栏之Python篇】二、Jupyer Notebook安装配置及基本使用

文章目录 前言一、Jupter Notebook是什么1.1 简介1.2 组成部分1.3 Jupyter Notebook的主要特点 二、为什么使用Jupyter Notebook?三、安装四、Jupyter Notebok配置4.1 基本配置4.2 配置开机自启与后台运行4.3 开启代码自动补全 五、两种键盘输入模式5.1 编辑模式5.2 命令模式5…

J2EE通用分页02

目录 一.重构-提取公用方法 1.为了进行公共方法的抽取&#xff0c;需要找出上面实习中的可通用部分&#xff0c;和差异化部分 2.公用方法封装思路 3. 具体实现 二.分页标签 2.1 准备一个Servlet 3.2 结果展示页面 三. 过滤器解决中文乱码问题 四.加入分页功能 四…

Qt Core学习日记——第七天QMetaObject(上)

每一个声明Q_OBJECT的类都具有QMetaObject对象 Q_OBJECT宏源代码&#xff1a; #define Q_OBJECT \ public: \ QT_WARNING_PUSH \ Q_OBJECT_NO_OVERRIDE_WARNING \ static const QMetaObject staticMetaObject; \ virtual const QMetaObject *metaObject() const; \ vir…

Rust vs Go:常用语法对比(五)

题图来自 Rust vs Go 2023[1] 81. Round floating point number to integer Declare integer y and initialize it with the rounded value of floating point number x . Ties (when the fractional part of x is exactly .5) must be rounded up (to positive infinity). 按规…