From 6e858135ce669def2b630e98670c0e9a6c9ef61a Mon Sep 17 00:00:00 2001 From: 12345qiupeng Date: Sat, 12 Apr 2025 17:21:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=E4=B8=A4=E7=A7=8D?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E6=A0=BC=E5=BC=8F=E7=9A=84=E4=BD=93=E7=B4=A0?= =?UTF-8?q?=E6=BB=A4=E6=B3=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 12 +- include/pcl_wrapper/cloud_handle.hpp | 25 +++++ include/pcl_wrapper/filter.hpp | 33 ------ include/pcl_wrapper/io.hpp | 23 ++-- include/pcl_wrapper/kdtree.hpp | 37 ------- include/pcl_wrapper/pcl_wrapper_api.hpp | 29 ++++- include/pcl_wrapper/point_types.hpp | 19 ---- include/pcl_wrapper/voxel_filter.hpp | 36 ++++++ src/filter.cpp | 32 ------ src/io.cpp | 29 ----- src/kdtree.cpp | 24 ---- wrapper.cpp | 140 +++++++++++++++--------- 12 files changed, 193 insertions(+), 246 deletions(-) create mode 100644 include/pcl_wrapper/cloud_handle.hpp delete mode 100644 include/pcl_wrapper/filter.hpp delete mode 100644 include/pcl_wrapper/kdtree.hpp delete mode 100644 include/pcl_wrapper/point_types.hpp create mode 100644 include/pcl_wrapper/voxel_filter.hpp delete mode 100644 src/filter.cpp delete mode 100644 src/io.cpp delete mode 100644 src/kdtree.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index aa2fa24..4a5c393 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,8 @@ project(pcl_wrapper) set(CMAKE_CXX_STANDARD 17) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) + # 获取 libomp 安装路径 execute_process( COMMAND brew --prefix libomp @@ -21,14 +23,10 @@ add_definitions(${PCL_DEFINITIONS}) # 添加库 add_library(pclwrapper SHARED wrapper.cpp - include/pcl_wrapper/point_types.hpp - include/pcl_wrapper/filter.hpp - include/pcl_wrapper/kdtree.hpp - include/pcl_wrapper/io.hpp include/pcl_wrapper/pcl_wrapper_api.hpp - src/filter.cpp - src/kdtree.cpp - src/io.cpp + include/pcl_wrapper/cloud_handle.hpp + include/pcl_wrapper/voxel_filter.hpp + include/pcl_wrapper/io.hpp ) # 指定 OpenMP 和 PCL 库 diff --git a/include/pcl_wrapper/cloud_handle.hpp b/include/pcl_wrapper/cloud_handle.hpp new file mode 100644 index 0000000..ee69536 --- /dev/null +++ b/include/pcl_wrapper/cloud_handle.hpp @@ -0,0 +1,25 @@ +// +// Created by QP on 2025/4/12. +// + +#ifndef PCL_WRAPPER_CLOUD_HANDLE_HPP +#define PCL_WRAPPER_CLOUD_HANDLE_HPP +#pragma once +#include +#include + +namespace pcl_wrapper { + + template + struct PclPointCloud { + using CloudPtr = typename pcl::PointCloud::Ptr; + CloudPtr cloud; + + PclPointCloud() : cloud(new pcl::PointCloud()) {} + }; + + using PointCloudXYZ = PclPointCloud; + using PointCloudXYZI = PclPointCloud; + +} // namespace pcl_wrapper +#endif //PCL_WRAPPER_CLOUD_HANDLE_HPP diff --git a/include/pcl_wrapper/filter.hpp b/include/pcl_wrapper/filter.hpp deleted file mode 100644 index 37e38a9..0000000 --- a/include/pcl_wrapper/filter.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef PCL_WRAPPER_FILTER_HPP -#define PCL_WRAPPER_FILTER_HPP -// filter.hpp -#pragma once -#include -#include "point_types.hpp" - -namespace pcl_wrapper { - - template - class FilterBase { - public: - virtual ~FilterBase() = default; - virtual void setInputCloud(typename pcl::PointCloud::Ptr cloud) = 0; - virtual typename pcl::PointCloud::Ptr getFilteredCloud() = 0; - }; - - // filter.hpp 中追加声明(不要写实现体) - template - class VoxelGridFilterImpl : public FilterBase { - public: - void setLeafSize(float ls); - void setInputCloud(typename pcl::PointCloud::Ptr cloud) override; - typename pcl::PointCloud::Ptr getFilteredCloud() override; - - private: - typename pcl::PointCloud::Ptr inputCloud; - float leafSize = 0.1f; - }; - -} // namespace pcl_wrapper - -#endif //PCL_WRAPPER_FILTER_HPP diff --git a/include/pcl_wrapper/io.hpp b/include/pcl_wrapper/io.hpp index 77e82eb..f3371f2 100644 --- a/include/pcl_wrapper/io.hpp +++ b/include/pcl_wrapper/io.hpp @@ -4,22 +4,27 @@ #ifndef PCL_WRAPPER_IO_HPP #define PCL_WRAPPER_IO_HPP - -// io.hpp #pragma once #include +#include "cloud_handle.hpp" #include -#include "point_types.hpp" namespace pcl_wrapper { - template - typename pcl::PointCloud::Ptr loadPCD(const std::string& filename); + bool loadPCD_XYZ(const std::string& filename, PointCloudXYZ& out) { + return pcl::io::loadPCDFile(filename, *out.cloud) == 0; + } - template - void savePCD(const std::string& filename, const typename pcl::PointCloud::Ptr& cloud); + bool loadPCD_XYZI(const std::string& filename, PointCloudXYZI& out) { + return pcl::io::loadPCDFile(filename, *out.cloud) == 0; + } + bool savePCD_XYZ(const std::string& filename, const PointCloudXYZ& cloud) { + return pcl::io::savePCDFileBinary(filename, *cloud.cloud) == 0; + } + + bool savePCD_XYZI(const std::string& filename, const PointCloudXYZI& cloud) { + return pcl::io::savePCDFileBinary(filename, *cloud.cloud) == 0; + } } - - #endif //PCL_WRAPPER_IO_HPP diff --git a/include/pcl_wrapper/kdtree.hpp b/include/pcl_wrapper/kdtree.hpp deleted file mode 100644 index 42c4a2c..0000000 --- a/include/pcl_wrapper/kdtree.hpp +++ /dev/null @@ -1,37 +0,0 @@ -// -// Created by QP on 2025/4/12. -// - -#ifndef PCL_WRAPPER_KDTREE_HPP -#define PCL_WRAPPER_KDTREE_HPP - -// kdtree.hpp -#pragma once -#include -#include "point_types.hpp" - -namespace pcl_wrapper { - - template - class KdTree { - public: - virtual ~KdTree() = default; - virtual void setInputCloud(typename pcl::PointCloud::Ptr cloud) = 0; - virtual std::vector radiusSearch(const PointT& pt, float radius) = 0; - }; - - template - class KdTreeFLANNWrapperImpl : public KdTree { - public: - void setInputCloud(typename pcl::PointCloud::Ptr cloud); - - std::vector radiusSearch(const PointT& pt, float radius); - - private: - pcl::KdTreeFLANN kdtree; - typename pcl::PointCloud::Ptr inputCloud; - }; -} - - -#endif //PCL_WRAPPER_KDTREE_HPP diff --git a/include/pcl_wrapper/pcl_wrapper_api.hpp b/include/pcl_wrapper/pcl_wrapper_api.hpp index df6e01f..9274551 100644 --- a/include/pcl_wrapper/pcl_wrapper_api.hpp +++ b/include/pcl_wrapper/pcl_wrapper_api.hpp @@ -4,21 +4,38 @@ #ifndef PCL_WRAPPER_PCL_WRAPPER_API_HPP #define PCL_WRAPPER_PCL_WRAPPER_API_HPP -// pcl_wrapper/include/pcl_wrapper/pcl_wrapper_api.hpp #pragma once #ifdef __cplusplus extern "C" { #endif -// 创建滤波器实例 -void* CreateVoxelGridXYZ(float leaf); -void SetInputCloudXYZ(void* filter, const float* points, int numPoints); -void ApplyVoxelGridXYZ(void* filter, float** outPoints, int* outCount); -void FreeVoxelGridXYZ(void* filter); +// ========== Cloud ========== +void* create_pointcloud_xyz(); +void* create_pointcloud_xyzi(); +void reserve_pointcloud_xyz(void* cloud, int count); +void set_point_xyz(void* cloud, int index, float x, float y, float z); +void set_point_xyzi(void* cloud, int index, float x, float y, float z, float intensity); +void delete_pointcloud(void* cloud); +// ========== Voxel Filter ========== + +void* create_voxel_filter_xyz(); +void* create_voxel_filter_xyzi(); +void set_voxel_leaf_size(void* filter, float lx, float ly, float lz); +void set_voxel_input_cloud(void* filter, void* cloud); +void* apply_voxel_filter_xyz(void* filter); +void* apply_voxel_filter_xyzi(void* filter); +void delete_voxel_filter(void* filter); + +// ========= IO ========== +bool load_pcd_xyz(const char* filename, void* out); +bool load_pcd_xyzi(const char* filename, void* out); +bool save_pcd_xyz(const char* filename, void* cloud); +bool save_pcd_xyzi(const char* filename, void* cloud); #ifdef __cplusplus } #endif + #endif //PCL_WRAPPER_PCL_WRAPPER_API_HPP diff --git a/include/pcl_wrapper/point_types.hpp b/include/pcl_wrapper/point_types.hpp deleted file mode 100644 index 36dbb92..0000000 --- a/include/pcl_wrapper/point_types.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// Created by QP on 2025/4/12. -// - -#ifndef PCL_WRAPPER_POINT_TYPES_HPP -#define PCL_WRAPPER_POINT_TYPES_HPP - -#pragma once -#include - -namespace pcl_wrapper { - - using PointXYZ = pcl::PointXYZ; - using PointXYZI = pcl::PointXYZI; - -} - - -#endif //PCL_WRAPPER_POINT_TYPES_HPP diff --git a/include/pcl_wrapper/voxel_filter.hpp b/include/pcl_wrapper/voxel_filter.hpp new file mode 100644 index 0000000..ffdfb13 --- /dev/null +++ b/include/pcl_wrapper/voxel_filter.hpp @@ -0,0 +1,36 @@ +// +// Created by QP on 2025/4/12. +// + +#ifndef PCL_WRAPPER_VOXEL_FILTER_HPP +#define PCL_WRAPPER_VOXEL_FILTER_HPP +#pragma once +#include + +namespace pcl_wrapper { + + template + struct VoxelGridWrapper { + pcl::VoxelGrid filter; + + void setInputCloud(typename pcl::PointCloud::Ptr cloud) { + filter.setInputCloud(cloud); + } + + void setLeafSize(float lx, float ly, float lz) { + filter.setLeafSize(lx, ly, lz); + } + + typename pcl::PointCloud::Ptr filterCloud() { + typename pcl::PointCloud::Ptr result(new pcl::PointCloud()); + filter.filter(*result); + return result; + } + }; + + using VoxelGridXYZ = VoxelGridWrapper; + using VoxelGridXYZI = VoxelGridWrapper; + +} // namespace pcl_wrapper + +#endif //PCL_WRAPPER_VOXEL_FILTER_HPP diff --git a/src/filter.cpp b/src/filter.cpp deleted file mode 100644 index b87f070..0000000 --- a/src/filter.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// pcl_wrapper/src/filter.cpp -#include "filter.hpp" -#include - -namespace pcl_wrapper { - -template -void VoxelGridFilterImpl::setLeafSize(float ls) { - leafSize = ls; -} - -template -void VoxelGridFilterImpl::setInputCloud(typename pcl::PointCloud::Ptr cloud) { - inputCloud = cloud; -} - -template -typename pcl::PointCloud::Ptr VoxelGridFilterImpl::getFilteredCloud() { - pcl::VoxelGrid voxel; - voxel.setInputCloud(inputCloud); - voxel.setLeafSize(leafSize, leafSize, leafSize); - typename pcl::PointCloud::Ptr filtered(new pcl::PointCloud()); - voxel.filter(*filtered); - return filtered; -} - -// 显式实例化 -template class VoxelGridFilterImpl; -template class VoxelGridFilterImpl; - - -} // namespace pcl_wrapper \ No newline at end of file diff --git a/src/io.cpp b/src/io.cpp deleted file mode 100644 index 5869ca9..0000000 --- a/src/io.cpp +++ /dev/null @@ -1,29 +0,0 @@ - -// pcl_wrapper/src/io.cpp -#include "io.hpp" - -namespace pcl_wrapper { - - template - typename pcl::PointCloud::Ptr loadPCD(const std::string& filename) { - typename pcl::PointCloud::Ptr cloud(new pcl::PointCloud()); - if (pcl::io::loadPCDFile(filename, *cloud) == -1) { - throw std::runtime_error("Failed to load PCD file: " + filename); - } - return cloud; - } - - template - void savePCD(const std::string& filename, const typename pcl::PointCloud::Ptr& cloud) { - if (pcl::io::savePCDFileBinary(filename, *cloud) == -1) { - throw std::runtime_error("Failed to save PCD file: " + filename); - } - } - -// 显式实例化 - template pcl::PointCloud::Ptr loadPCD(const std::string&); - template pcl::PointCloud::Ptr loadPCD(const std::string&); - template void savePCD(const std::string&, const pcl::PointCloud::Ptr&); - template void savePCD(const std::string&, const pcl::PointCloud::Ptr&); - -} // namespace pcl_wrapper diff --git a/src/kdtree.cpp b/src/kdtree.cpp deleted file mode 100644 index d00f5b0..0000000 --- a/src/kdtree.cpp +++ /dev/null @@ -1,24 +0,0 @@ - -// pcl_wrapper/src/kdtree.cpp -#include "kdtree.hpp" - -namespace pcl_wrapper { - -template -void KdTreeFLANNWrapperImpl::setInputCloud(typename pcl::PointCloud::Ptr cloud) { - inputCloud = cloud; - kdtree.setInputCloud(cloud); -} -template -std::vector KdTreeFLANNWrapperImpl::radiusSearch(const PointT& pt, float radius) { - std::vector indices; - std::vector sqrDistances; - kdtree.radiusSearch(pt, radius, indices, sqrDistances); - return indices; -} - -// 显式模板实例化 -template class KdTreeFLANNWrapperImpl; -template class KdTreeFLANNWrapperImpl; - - // namespace pcl_wrapper diff --git a/wrapper.cpp b/wrapper.cpp index 5145c80..229c866 100644 --- a/wrapper.cpp +++ b/wrapper.cpp @@ -1,64 +1,104 @@ - -// pcl_wrapper/src/wrapper.cpp -#include "filter.hpp" -#include "point_types.hpp" +#include "cloud_handle.hpp" +#include "voxel_filter.hpp" +#include "io.hpp" #include "pcl_wrapper_api.hpp" -#include -#include using namespace pcl_wrapper; -using CloudPtr = pcl::PointCloud::Ptr; - -class VoxelGridXYZBridge { -public: - VoxelGridXYZBridge(float leaf) { - filter.setLeafSize(leaf); - } - - void setInput(const float* points, int count) { - CloudPtr cloud(new pcl::PointCloud()); - cloud->resize(count); - for (int i = 0; i < count; ++i) { - (*cloud)[i].x = points[3 * i]; - (*cloud)[i].y = points[3 * i + 1]; - (*cloud)[i].z = points[3 * i + 2]; - } - filter.setInputCloud(cloud); - } - - void getFiltered(float** outPts, int* outCount) { - auto cloud = filter.getFilteredCloud(); - *outCount = cloud->size(); - *outPts = new float[*outCount * 3]; - for (int i = 0; i < *outCount; ++i) { - (*outPts)[3 * i + 0] = (*cloud)[i].x; - (*outPts)[3 * i + 1] = (*cloud)[i].y; - (*outPts)[3 * i + 2] = (*cloud)[i].z; - } - } - -private: - VoxelGridFilterImpl filter; -}; - - +// === 点云相关 === extern "C" { -void* CreateVoxelGridXYZ(float leaf) { - return new VoxelGridXYZBridge(leaf); +void* create_pointcloud_xyz() { + return new PointCloudXYZ(); } -void SetInputCloudXYZ(void* obj, const float* points, int count) { - static_cast(obj)->setInput(points, count); +void* create_pointcloud_xyzi() { + return new PointCloudXYZI(); } -void ApplyVoxelGridXYZ(void* obj, float** outPoints, int* outCount) { - static_cast(obj)->getFiltered(outPoints, outCount); +void reserve_pointcloud_xyz(void* cloud, int count) { + auto* pc = static_cast(cloud); + pc->cloud->resize(count); } -void FreeVoxelGridXYZ(void* obj) { - delete static_cast(obj); +void set_point_xyz(void* cloud, int index, float x, float y, float z) { + auto* pc = static_cast(cloud); + (*pc->cloud)[index].x = x; + (*pc->cloud)[index].y = y; + (*pc->cloud)[index].z = z; } -} // extern C +void set_point_xyzi(void* cloud, int index, float x, float y, float z, float intensity) { + auto* pc = static_cast(cloud); + (*pc->cloud)[index].x = x; + (*pc->cloud)[index].y = y; + (*pc->cloud)[index].z = z; + (*pc->cloud)[index].intensity = intensity; +} + +void delete_pointcloud(void* cloud) { + delete static_cast(cloud); // 可根据类型再区分 +} + +// === 滤波器相关 === + +void* create_voxel_filter_xyz() { + return new VoxelGridXYZ(); +} + +void* create_voxel_filter_xyzi() { + return new VoxelGridXYZI(); +} + +void set_voxel_leaf_size(void* filter, float lx, float ly, float lz) { + auto* vf_xyz = static_cast(filter); + vf_xyz->setLeafSize(lx, ly, lz); // 默认按XYZ处理 +} + +void set_voxel_input_cloud(void* filter, void* cloud) { + auto* vf = static_cast(filter); + auto* pc = static_cast(cloud); + vf->setInputCloud(pc->cloud); +} + +void* apply_voxel_filter_xyz(void* filter) { + auto* vf = static_cast(filter); + auto* out = new PointCloudXYZ(); + out->cloud = vf->filterCloud(); + return out; +} + +void* apply_voxel_filter_xyzi(void* filter) { + auto* vf = static_cast(filter); + auto* out = new PointCloudXYZI(); + out->cloud = vf->filterCloud(); + return out; +} + +void delete_voxel_filter(void* ptr) { + delete static_cast(ptr); // 可再细分 +} + +// === IO相关 === + +bool load_pcd_xyz(const char* filename, void* out) { + auto* pc = static_cast(out); + return loadPCD_XYZ(filename, *pc); +} + +bool load_pcd_xyzi(const char* filename, void* out) { + auto* pc = static_cast(out); + return loadPCD_XYZI(filename, *pc); +} + +bool save_pcd_xyz(const char* filename, void* cloud) { + auto* pc = static_cast(cloud); + return savePCD_XYZ(filename, *pc); +} + +bool save_pcd_xyzi(const char* filename, void* cloud) { + auto* pc = static_cast(cloud); + return savePCD_XYZI(filename, *pc); +} + +}