【问题标题】:Converting a C++ library into MATLAB mex将 C++ 库转换为 MATLAB mex
【发布时间】:2014-11-08 19:41:38
【问题描述】:

我有一个很大的 C++ 代码,我想将它集成到 MATLAB 中,以便我可以在我的 matlab 代码中使用它。如果它是一个单一的代码,制作它的 mex 文件将是最好的选择。但是由于现在它是一个需要编译和构建才能运行的代码,我不知道如何使用该代码中的函数。
为整个代码制作 mex 文件是唯一的选择还是有其他解决方法?另外,我想了解如何为整个代码制作 mex 文件然后构建它。

为了更深入地了解,这是我试图在 matlab http://graphics.stanford.edu/projects/drf/densecrf_v_2_2.zip 中集成的代码。谢谢!

【问题讨论】:

  • Mex 函数无济于事,因为它们不允许基于类和对象的编程。我的建议是翻译成托管的 .NET 语言,如 C#。您可以通过NET.addAssembly() 直接使用代码。然后,您将拥有可在 MATLAB 内外工作的代码。请参阅此链接中的信息:mathworks.com/help/matlab/using-net-libraries-in-matlab.html
  • @Juderb:将库从 C++ 移植到 C# 需要做很多工作,更不用说你会失去各种优化(上述库使用 SSE 指令等)! MATLAB 通过使用 MEX 函数轻松允许使用外部库
  • 你是对的@amro。

标签: c++ matlab integration mex


【解决方案1】:

首先,您需要编译库(静态或动态链接)。以下是我在 Windows 机器上执行的步骤(我有 Visual Studio 2013 作为 C++ 编译器):

  • 使用 CMake 生成 Visual Studio 项目文件,如 README 文件中所述。
  • 启动VS,编译densecrf.sln解决方案文件。这将产生一个静态库densecrf.lib

接下来修改示例文件dense_inference.cpp 使其成为 MEX 函数。我们将 main 函数替换为:

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
..
}

我们不会在argc/argv 中接收参数,而是从输入mxArray 中获取参数。所以像:

if (nrhs<3 || nlhs>0)
    mexErrMsgIdAndTxt("mex:error", "Wrong number of arguments");

if (!mxIsChar(prhs[0]) || !mxIsChar(prhs[1]) || !mxIsChar(prhs[2]))
    mexErrMsgIdAndTxt("mex:error", "Expects string arguments");

char *filename = mxArrayToString(prhs[0]);
unsigned char * im = readPPM(filename, W, H );
mxFree(filename);

//... same for the other input arguments
// The example receives three arguments: input image, annotation image,
// and output image, all specified as image file names.

// also replace all error message and "return" exit points
// by using "mexErrMsgIdAndTxt" to indicate an error

最后,我们编译修改后的 MEX 文件(将编译后的 LIB 放在同一 example 文件夹中):

>> mex -largeArrayDims dense_inference.cpp util.cpp -I. -I../include densecrf.lib

现在我们从 MATLAB 内部调用 MEX 函数:

>> dense_inference im1.ppm anno1.ppm out.ppm

得到的分割图像:

【讨论】:

  • 我忘了提到,如果您在 Windows 中工作,您必须在 src/permutohedral.h 中注释几行(显然 round 函数在第 50 行被不必要地重新定义)跨度>
  • 我一回到我的机器就试试这个。非常感谢。虽然我使用的是 linux 机器,但我希望大多数步骤都是相似的。如果没有,你能给出一些明确的步骤吗?
  • @diggy:显然您不能直接在 MATLAB 中创建 C++ 对象,您必须为要在 MATLAB 中使用的任何功能编写包装函数层(作为 MEX 文件)。这里的一种常见技术是实现 switchyard 模式,其中 MEX 函数接收命令“字符串”作为参数,确定要执行的操作,例如 newdeletecallSomeMethod等等。这个想法是创建存储在全局范围内的 C++ 对象,并返回某种指向它们的序列化指针。 C++ 对象将在对 MEX 文件的调用之间保持不变。
  • ... 在 FEX 上查看这个示例以了解有关我描述的这种模式的更多信息:mathworks.com/matlabcentral/fileexchange/…(提到的discussion thread 也很有用)。至于与共享库的链接错误,需要使用语法:mex ... -L. -ldensecrf
  • @diggy:链接语法基本上是GCC的语法:指定-lfoo链接到libfoo.so,并使用-L/path/to/libs告诉它在哪里寻找共享库(小心事情的顺序很重要)。同样从错误消息中,我看到您正在使用 Eigen 库,因此您还需要将路径添加到其头文件...
【解决方案2】:

另一种方法是将大型 C++ 代码编译为 shared library(.dll 或 .so,具体取决于您的操作系统),然后使用 loadlibrary 在 Matlab 中加载此库。
加载库后,您可以使用 calllib 调用其每一个 API 函数。


示例:假设您在 Linux 环境中工作,并且您的 c++ 代码在文件 myLib.cpp 和头文件 myLib.h,那么您可以使用 g++ 创建共享图书馆

$ g++ -fPic -c myLib.cpp
$ g++ -shared -o myLib.so myLib.o

现在,在 Matlab 中,您可以加载库(假设 .so 文件和 .h 文件在您的 matlab 路径中)

>> loadlibrary( 'myLib', 'myLib.h' );

【讨论】:

  • 我可以将整个库编译成一个 .so 文件吗?如果是,如何?我有这个疑问,因为我正在查看共享库文档,但我不知道该怎么做。非常感谢您的帮助。
  • @Shai:实际上这在 OP 的情况下不起作用;有问题的库公开了 C++ 类,因此您将无法使用loadlibrary。您必须编写一个 MEX 函数来调用类方法。
  • 正如@amro 所说,您无法使用loadlibrary 在Matlab 中访问C++ 类。此链接描述了其他限制和解决方法:mathworks.com/help/matlab/matlab_external/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-05
  • 1970-01-01
  • 2014-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多