模拟是最需要的才能,从模仿中学习。
在c#中使用pcl的步骤
在pcl就使用这种方式了,因为CLR的方式行不通,CLR(中间语言支持库)需要知道源文件,而pcl的原文件超级复杂,并且不一定导出的时候就是CLR的那种导出方式,所以这里的关注点就是采用c语言形式导出动态库的方式,其他不用管。
一和二是导出不需要传复杂参数的方式,或者是之后不需要咋使用
一、c++库的静态库导出
导出动态库的时候好像不能在多处include头文件,不然会出现重定义,这与平时的运行程序会有点不一样。
步骤:define定义导入导出——>原本实现——>在原本实现基础上定义导出函数,在函数中调用“原本实现”的函数,以及传入相关的类参数
-
防止重定义的define
#ifndef PCLFUNC_EXPORT_H #define PCLFUNC_EXPORT_H //相关定义 #endif // !PCLFUNC_EXPORT_H
-
define定义导入导出
#ifndef DLL_IMPORT #define TESTDLL_API __declspec(dllexport) #else #define TESTDLL_API __declspec(dllimport)
-
原本实现
//主要写自己的实现 #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include<string> using namespace std; using namespace pcl::io; class PCLFuncExport { public: PCLFuncExport(); ~PCLFuncExport(); pcl::PointCloud<pcl::PointXYZ>::Ptr getPclPoint(); void setPclPint(string path); int readPcdFile(string path, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud); private: pcl::PointCloud<pcl::PointXYZ>::Ptr cloud; };
-
在原本实现基础上定义导出函数,在函数中调用“原本实现”的函数,以及传入相关的类参数
- 主要是通过我们自己写的方法去调用第三方库pcl库,不然我们不知道第三方库是怎么封装的,而且第三方库的封装可能也不符合我们的要求,所以这样封装调用是比较方便的,不过传递参数的类以及对象需要在c#中对应起来,这里通过开源的pcl c#包解决的
extern "C" TESTDLL_API PCLFuncExport* dllGetObj() { return new PCLFuncExport(); }; extern "C" TESTDLL_API int dllReadPcd(PCLFuncExport * pcl,string path, pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) { return pcl->readPcdFile(path, cloud); } extern "C" TESTDLL_API void dllSetPcl(PCLFuncExport * pcl, string path) { pcl->setPclPint(path); } extern "C" TESTDLL_API void dllDeletePclFuncExport(PCLFuncExport * pcl) { delete pcl; }
二、c#类库的封装调用
新建一个c# 类库项目,如图所示
[DllImport("PCLCppDll.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public extern static int dllReadPcd(IntPtr pcl, [MarshalAs(UnmanagedType.LPStr)] string path,IntPtr cloud);
- 约定好字符集以及调用栈和清空方式。
- 字符串采用
[MarshalAs(UnmanagedType.LPStr)] string path
- 数组以及类直接都是用
IntPtr
- 以公共、extern以及静态方式声明:
public extern static
类中以首字母大写的方式去调用其结果,这里和一般的方式一样,并不需要注意什么
public int ReadPcd(IntPtr pcl, string path, IntPtr cloud)
{
return dllReadPcd(pcl,path,cloud);
}
三、c#中对其的使用
将刚刚类库的包以及pcl的动态库进行导入,可以看到程序集增加进去了:
在程序中调用类库有的方法
//调用类库
使用pcl csharp包
导入包
//增添的命名空间
using PclSharp.IO;
using PclSharp;
将动态库以及类库包放入bin路径中
调用方法:
private void button1_Click(object sender, EventArgs e)
{
using (var cloud = new PointCloudOfXYZ())
using (var writer = new PCDWriter())
using (var pcdReader = new PCDReader())
{
if (pcdReader.Read("E:/pcl/test/saddle.pcd", cloud) < 0)
{
MessageBox.Show("没读取成功");
}
else
{
MessageBox.Show("点云数据读取成功");
}
}
}
完整源代码:
using System;
using System.Windows.Forms;
//增添的命名空间
using PclSharp.IO;
using PclSharp;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (var cloud = new PointCloudOfXYZ())
using (var writer = new PCDWriter())
using (var pcdReader = new PCDReader())
{
if (pcdReader.Read("E:/pcl/test/saddle.pcd", cloud) < 0)
{
MessageBox.Show("没读取成功");
}
else
{
MessageBox.Show("点云数据读取成功");
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
}