一、配置好pcl 的c++环境,添加cpp文件,添加如下函数:
#include "..\export.h"
#include "pcl\pcl_base.h"
#include "pcl\point_types.h"
#include <pcl/point_cloud.h>
#include <pcl/filters/approximate_voxel_grid.h>
#ifdef __cplusplus
extern "C" { // only need to export C interface if
// used by C++ source code
#endif
//对点云进行近似体素下采样
EXPORT(void) approximateVoxelDownSample(pcl::PointCloud<pcl::PointXYZ> * in_pc, double leaf_size,
pcl::PointCloud<pcl::PointXYZ> * out_pc)
{
pcl::ApproximateVoxelGrid<pcl::PointXYZ> avoxel;
avoxel.setInputCloud(in_pc->makeShared());
avoxel.setLeafSize(leaf_size, leaf_size, leaf_size);
avoxel.filter(*out_pc);
}
#ifdef __cplusplus
}
#endif
该示例为一个简单的近似体素滤波的封装函数,输入输出为点云数据类pcl::PointCloud<pcl::PointXYZ>的指针形式。
编译该代码生成相应的c++动态链接库
二、在c#中以DLLimport方式调用c++封装函数
[DllImport("xxxx.dll", CallingConvention= CallingConvention.Cdecl)]
private static extern void approximateVoxelDownSample(IntPtr input, double leaf_size, IntPtr out_cloud);
这里dll填入你自己的dll名称,函数名approximateVoxelDownSample不能输错,input,out_cloud为Inptr类型,对应c++函数中的点云指针
以下为c#调用代码:
PclSharp.PointCloudOfXYZ pointCloudOfXYZ = new PclSharp.PointCloudOfXYZ();
using (var reader = new PclSharp.IO.PCDReader())
{
reader.Read("./rabbit.pcd", pointCloudOfXYZ);
}
var pc = new PclSharp.PointCloudOfXYZ();
approximateVoxelDownSample(pointCloudOfXYZ.Ptr, 0.005, pc.Ptr);
PclSharp.Vis.Visualizer visualizer = new PclSharp.Vis.Visualizer("cloud");
int v1 = visualizer.CreateViewPort(0, 0, 0.5, 1);
//visualizer.SetBackgroundColor(0, 0, 1, v1);
int v2 = visualizer.CreateViewPort(0.5, 0, 1, 1);
// visualizer.SetBackgroundColor(0,1,0, v2);
visualizer.AddPointCloud(pointCloudOfXYZ,"c1",255,0,0,v1);
visualizer.AddPointCloud(pc, "c2",0,255,0, v2);
visualizer.SpinOnce();
运行效果:
这里就完成了c#调用c++pcl算法调用
三、封装原理
这个例子中我们只使用pclsharp封装库的PointCloudOfXYZ数据接口,这个类自动帮我们完成了c++点云数据的内存管理,无需我们进行资源的释放。查看PointCloudOfXYZ源码:
基类为UnmanagedObject:
public abstract class UnmanagedObject : DisposableObject
{
protected IntPtr _ptr;
public IntPtr Ptr => _ptr;
public static implicit operator IntPtr(UnmanagedObject obj)
{
return obj?._ptr ?? IntPtr.Zero;
}
}
其中_ptr成员为非托管资源指针,本库中为c++点云数据指针
该类实现IDisposable接口用于管理非托管资源。
查看 PointCloudOfXYZ的默认构造函数:
public PointCloudOfXYZ()
: this(Invoke.pointcloud_xyz_ctor())
{
}
pointcloud_xyz_ctor函数具体为
[DllImport("PclSharp.Extern.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr pointcloud_xyz_ctor();
对应c++实现为:
EXPORT(PointCloud<PointXYZ>*) pointcloud_xyz_ctor()
{
return new PointCloud<PointXYZ>();
}
用于创建点云对象,返回点云指针
而 PointCloudOfXYZ的DisposeObject函数负责资源的释放
protected override void DisposeObject()
{
if (!_suppressDispose)
{
Invoke.pointcloud_xyz_delete(ref _ptr);
}
}
其中pointcloud_xyz_delete的c++版本为:
EXPORT(void) pointcloud_xyz_delete(PointCloud<PointXYZ>** ptr)
{
delete *ptr;
*ptr = NULL;
}
其他类基本也是按这个形式封装,一般分为三步:pcl算法类的构造,调用,和释放。
注意pclsharp并没有封装pcl的所有算法,不过根据以上介绍的原理,不难实现其他算法的封装。