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

目录

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

写在前面

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$<$:Debug>")
else()
  set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$: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 
#include 
#include 
#include 
#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 
#include 
#include 
#include 

#include 

#include 
#include 

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 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个点的点云进行测试,下面是不用多线程的结果
open3d和pcl点云转换及多线程加速_第1张图片

使用5个线程的结果:
open3d和pcl点云转换及多线程加速_第2张图片

参考

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

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

你可能感兴趣的:(open3d,pcl,c++,cmake)