From 9e2e286251a291ae234769daeaae785e29471f01 Mon Sep 17 00:00:00 2001 From: 12345qiupeng Date: Sat, 12 Apr 2025 16:40:31 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=80=E7=A7=8D=E5=A4=8D=E6=9D=82?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 14 +++++- include/pcl_wrapper/filter.hpp | 33 +++++++++++++ include/pcl_wrapper/io.hpp | 25 ++++++++++ include/pcl_wrapper/kdtree.hpp | 37 ++++++++++++++ include/pcl_wrapper/pcl_wrapper_api.hpp | 24 +++++++++ include/pcl_wrapper/point_types.hpp | 19 ++++++++ pcl_wrapper.cpp | 65 ------------------------- src/filter.cpp | 32 ++++++++++++ src/io.cpp | 29 +++++++++++ src/kdtree.cpp | 24 +++++++++ wrapper.cpp | 64 ++++++++++++++++++++++++ 11 files changed, 299 insertions(+), 67 deletions(-) create mode 100644 include/pcl_wrapper/filter.hpp create mode 100644 include/pcl_wrapper/io.hpp create mode 100644 include/pcl_wrapper/kdtree.hpp create mode 100644 include/pcl_wrapper/pcl_wrapper_api.hpp create mode 100644 include/pcl_wrapper/point_types.hpp delete mode 100644 pcl_wrapper.cpp create mode 100644 src/filter.cpp create mode 100644 src/io.cpp create mode 100644 src/kdtree.cpp create mode 100644 wrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index df90f07..aa2fa24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,6 @@ project(pcl_wrapper) set(CMAKE_CXX_STANDARD 17) - # 获取 libomp 安装路径 execute_process( COMMAND brew --prefix libomp @@ -15,11 +14,22 @@ execute_process( find_package(PCL REQUIRED) # 添加 include 路径 +include_directories(include) +include_directories(include/pcl_wrapper) include_directories(${PCL_INCLUDE_DIRS} "${LIBOMP_PREFIX}/include") add_definitions(${PCL_DEFINITIONS}) # 添加库 -add_library(pclwrapper SHARED pcl_wrapper.cpp) +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 +) # 指定 OpenMP 和 PCL 库 target_compile_options(pclwrapper PRIVATE -Xpreprocessor -fopenmp) diff --git a/include/pcl_wrapper/filter.hpp b/include/pcl_wrapper/filter.hpp new file mode 100644 index 0000000..37e38a9 --- /dev/null +++ b/include/pcl_wrapper/filter.hpp @@ -0,0 +1,33 @@ +#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 new file mode 100644 index 0000000..77e82eb --- /dev/null +++ b/include/pcl_wrapper/io.hpp @@ -0,0 +1,25 @@ +// +// Created by QP on 2025/4/12. +// + +#ifndef PCL_WRAPPER_IO_HPP +#define PCL_WRAPPER_IO_HPP + +// io.hpp +#pragma once +#include +#include +#include "point_types.hpp" + +namespace pcl_wrapper { + + template + typename pcl::PointCloud::Ptr loadPCD(const std::string& filename); + + template + void savePCD(const std::string& filename, const typename pcl::PointCloud::Ptr& cloud); + +} + + +#endif //PCL_WRAPPER_IO_HPP diff --git a/include/pcl_wrapper/kdtree.hpp b/include/pcl_wrapper/kdtree.hpp new file mode 100644 index 0000000..42c4a2c --- /dev/null +++ b/include/pcl_wrapper/kdtree.hpp @@ -0,0 +1,37 @@ +// +// 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 new file mode 100644 index 0000000..df6e01f --- /dev/null +++ b/include/pcl_wrapper/pcl_wrapper_api.hpp @@ -0,0 +1,24 @@ +// +// Created by QP on 2025/4/12. +// + +#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); + + + +#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 new file mode 100644 index 0000000..36dbb92 --- /dev/null +++ b/include/pcl_wrapper/point_types.hpp @@ -0,0 +1,19 @@ +// +// 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/pcl_wrapper.cpp b/pcl_wrapper.cpp deleted file mode 100644 index 80623dd..0000000 --- a/pcl_wrapper.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include - -using PointType = pcl::PointXYZ; - -class PclPointCloud { -public: - pcl::PointCloud::Ptr cloud; - - PclPointCloud() : cloud(new pcl::PointCloud) {} -}; - -class PclVoxelGrid { -public: - pcl::VoxelGrid filter; -}; - -extern "C" { - -void* create_point_cloud() { - return new PclPointCloud(); -} - -void delete_point_cloud(void* ptr) { - delete static_cast(ptr); -} - -int load_point_cloud(void* ptr, const char* path) { - auto* cloud = static_cast(ptr); - return pcl::io::loadPCDFile(path, *cloud->cloud); -} - -int save_point_cloud(void* ptr, const char* path) { - auto* cloud = static_cast(ptr); - return pcl::io::savePCDFileBinary(path, *cloud->cloud); -} - -void* create_voxel_filter() { - return new PclVoxelGrid(); -} - -void delete_voxel_filter(void* ptr) { - delete static_cast(ptr); -} - -void set_voxel_leaf_size(void* ptr, float lx, float ly, float lz) { - auto* vf = static_cast(ptr); - vf->filter.setLeafSize(lx, ly, lz); -} - -void set_voxel_input_cloud(void* vf_ptr, void* cloud_ptr) { - auto* vf = static_cast(vf_ptr); - auto* cloud = static_cast(cloud_ptr); - vf->filter.setInputCloud(cloud->cloud); -} - -void* apply_voxel_filter(void* vf_ptr) { - auto* vf = static_cast(vf_ptr); - auto* result = new PclPointCloud(); - vf->filter.filter(*result->cloud); - return result; -} - -} diff --git a/src/filter.cpp b/src/filter.cpp new file mode 100644 index 0000000..b87f070 --- /dev/null +++ b/src/filter.cpp @@ -0,0 +1,32 @@ +// 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 new file mode 100644 index 0000000..5869ca9 --- /dev/null +++ b/src/io.cpp @@ -0,0 +1,29 @@ + +// 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 new file mode 100644 index 0000000..d00f5b0 --- /dev/null +++ b/src/kdtree.cpp @@ -0,0 +1,24 @@ + +// 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 new file mode 100644 index 0000000..5145c80 --- /dev/null +++ b/wrapper.cpp @@ -0,0 +1,64 @@ + +// pcl_wrapper/src/wrapper.cpp +#include "filter.hpp" +#include "point_types.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 SetInputCloudXYZ(void* obj, const float* points, int count) { + static_cast(obj)->setInput(points, count); +} + +void ApplyVoxelGridXYZ(void* obj, float** outPoints, int* outCount) { + static_cast(obj)->getFiltered(outPoints, outCount); +} + +void FreeVoxelGridXYZ(void* obj) { + delete static_cast(obj); +} + +} // extern C