用matlab调用C++库的三种方法(超全版)

本文详细介绍了如何在MATLAB中调用C++库,包括使用MEX接口、动态链接库DLL以及可执行文件exe的三种方法。在尝试调用第三方库如PCL时,作者分享了遇到的问题及解决方案,包括错误解析、参数传递等挑战。

最近想用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里输出的值。本部分具体参见书籍:

 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值