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个点的点云进行测试,下面是不用多线程的结果
pcl之open3d数据与pcl数据相互转换
主要做激光/影像三维重建,配准、分割等常用点云算法,技术交流、咨询可私信