最近想用matlab调用pcl(点云库),但是苦苦找寻,很多方法简单的C++代码可以实现,一旦涉及到第三方库就不行了,研究了一周,总结一下遇到的问题和解决方法。
首先介绍一个比较全面的书籍:https://download.youkuaiyun.com/download/Meet_csdn/12434403(若被删除,则搜索 精通matlab C/C++混合程序设计 第四版)
matlab版本为2017b,vs版本2015。
1.用MEX接口
这种方法是最常见的方法,相对来说也比较简单,主要涉及修改C++中入口函数和传递参数格式。
首先在matlab中输入
mex -setup
查看一下编译器的情况,我的会出现
然后先输入一些简单的代码测试是否能运行
test.cpp
#include "mex.h"
double add(double x, double y)
{
return x + y;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double *a;
double b, c;
plhs[0] = mxCreateDoubleMatrix(1, 1, mxREAL);
a = mxGetPr(plhs[0]);
b = *(mxGetPr(prhs[0]));
c = *(mxGetPr(prhs[1]));
*a = add(b, c);
}
输入 mex test.cpp,正常情况下就会出现由vs2015编译,没有报错。
但是我的vs会报错,我也很苦恼不知道为什么,换到另一台电脑matlab2017b+vs2013就没问题,错误如下,如有大佬知道原因还请不吝赐教。

虽然会报错,但是仍然能生成mexw64文件,也可以运行。
接下来对于由第三方库的代码,参见博客
https://blog.youkuaiyun.com/trueblue_/article/details/77834632
https://blog.youkuaiyun.com/trueblue_/article/details/77834632
不过我按照这种弄完以后没有成功,会出现 ERROR 2019 无法解析外部符号 的错误,可能是版本原因,待查。
2.用动态链接库dll
第二种方法是试验成功的,也是相对普遍的方法,不仅可以用在matlab上,还可以用在其他的接口调用上。
我的方法是先在vs里编译成dll文件,在把对应的.dll 和 .h文件复制到matlab工作文件夹,然后用loadlibrary的方法调用,下边先看一下简单的。
matlab_dll.cpp
#include "matlab_dll.h"
double add(double x, double y)
{ return (x+y);
}
matlab_dll.h
#ifndef MATLAB_DLL_H
#define MATLAB_DLL_H
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) double add(double x, double y); //*注意2个下划线*,编译器的宏定义
#ifdef __cplusplus
}
#endif
#endif
参见博客:https://www.jianshu.com/p/e910ca82b542
接下来是包含第三方库的文件
本文件是调用pcl中spin Image的库,对点云做局部特征描述,对opencv这样的库也同样适用。
工程文件:
si.h
#pragma once
#ifndef SI_H
#define SI_H
#ifdef __cplusplus
extern "C"
{
#endif
__declspec(dllexport) void spinImage(double *descriptor);
#ifdef __cplusplus
}
#endif
#endif
spinImage.cpp
// Feature_demo.cpp : 定义控制台应用程序的入口点。
//
#include "si.h"
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <pcl/io/ply_io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/spin_image.h>
//#include "spin_image.h"
//#include "spin_image.hpp"
//int main(int, char** argv)
void spinImage(double *descriptor)
{
std::string filename = "nonlocal_test_block.ply";
std::cout << "Reading " << filename << std::endl;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPLYFile <pcl::PointXYZ>(filename.c_str(), *cloud) == -1)
// load the file
{
PCL_ERROR("Couldn't read file");
//return (-1.0);
}
std::cout << "Loaded " << cloud->points.size() << " points." << std::endl;
// Compute the normals
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimation;
normal_estimation.setInputCloud(cloud);
pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
normal_estimation.setSearchMethod(kdtree);
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud< pcl::Normal>);
//normal_estimation.setRadiusSearch(30);
normal_estimation.setKSearch(8);
normal_estimation.compute(*normals);
// Setup spin image computation
pcl::SpinImageEstimation<pcl::PointXYZ, pcl::Normal, pcl::Histogram<153> > spin_image_descriptor(8, 0.5, 10);
spin_image_descriptor.setInputCloud(cloud);
spin_image_descriptor.setInputNormals(normals);
// Use the same KdTree from the normal estimation
spin_image_descriptor.setSearchMethod(kdtree);
pcl::PointCloud<pcl::Histogram<153> >::Ptr spin_images(new pcl::PointCloud<pcl::Histogram<153> >);
spin_image_descriptor.setRadiusSearch(8);
// Actually compute the spin images
spin_image_descriptor.compute(*spin_images);
std::cout << "SI output points.size (): " << spin_images->points.size() << std::endl;
// Display and retrieve the spin image descriptor vector for the first point.
//pcl::Histogram<153> descriptor = spin_images->points[0];
//std::cout << descriptor << std::endl;
for (int j = 0; j<spin_images->points.size(); j++)
for (int i=0;i<153;i++)
descriptor[j*153+i] = spin_images->points[j].histogram[i];
//return descriptor;
}
在vs中任意新建一个win32项目,输出改为dll文件,将spinImage.cpp和si.h放到项目中,生成即可。
动态链接库的方法虽然简单,但是它也有个大问题,就是参数传递很麻烦。
如上边我们是需要descriptor这个指针的,但是我们的返回值确实void,这是因为matlab会自动返回输入的指针参数,这也是为什么我们要输入指针的原因。当返回值是int double 等这些还有char * 时,可以正常返回。当然,它也可以返回指针,只是过程比较麻烦,我尝试了很多次返回double *类型的参数,但是返回到matlab以后只有一个lib.pointer 参数,没有值,我也很奇怪,还没有解决。
3.用可执行文件exe
这个方法也算是比较简单的,只要有.cpp文件,matlab里边的mbuild 方法可以生产exe文件。
如第一个方法中用到的test.cpp,不过它必须要有main函数才能执行,而且输出参数的话,我目前了解到的是原程序通过printf输出后,采集到matlab中,再做分析,我只试了比较简单的程序,是可以成功的。
主要涉及指令
mbuild test.cpp
[s,r] = dos('test')
返回的s是状态,0是成功,1是失败。
r就是printf里输出的值。本部分具体参见书籍:
本文详细介绍了如何在MATLAB中调用C++库,包括使用MEX接口、动态链接库DLL以及可执行文件exe的三种方法。在尝试调用第三方库如PCL时,作者分享了遇到的问题及解决方案,包括错误解析、参数传递等挑战。
453

被折叠的 条评论
为什么被折叠?



