背景
MATLAB有强大的矩阵运算能力以及丰富的函数库,可以用于算法的仿真以及快速验证某些算法思路。MATLAB的UI层是利用基于JVM利用Java实现的,而部分算法的底层则是封装了C/C++以及Intel提供的汇编指令集。因此MATLAB在用于计算时的速度是非常之快的。但是有的时候我们经常看到,虽然一些论文或者文章中描述了算法,并且作者也在个人主页上po处了源代码。但是这些算法的细节我们的是看不到的,可能是由于专利的原因,也可能是算法中的某些参数是经过了大量验证而作者并不想公布的。因此,对于很多图像类的算法,作者们都是采用了将算法的核心部分利用MATLAB自带的C编译器mexcc封装为一个.mexw64(64位系统)或.mexw32(32位系统)文件,然后在MATLAB的.m文件中通过函数名直接调用这些封装的函数。这样既保证了算法的速度,又可以保留必要的细节。那么如何实现这个呢?其实很简单,下文会详细介绍
方法
之前写过一篇关于如何在VS中调用MATLAB函数的方法,既要安装MATLAB RUNTIME COMPILER又要设置工程的附加库和包含目录,同时C和C++文件调用MATLAB还有区别,非常的麻烦。但是如果发过来,通过MATLAB来调用C/C++函数就相对而言过程简化了很多。
1. C++端的代码
为了方便,我们用一个简单的demo来举例子。假设我们需要封装原来的C++函数:
// Arithmetic_Operation.cpp
// 本函数实现了两个double型参数输入的四则运算,并保存在res数组中,顺序为加减乘除
#include
void Arithmetic_Operation( double* res, double a, double b )
{
res[0] = a + b;
res[1] = a - b;
res[2] = a * b;
res[3] = ( b == 0 ? 0 : a / b ) ; // check whether divide is zero
return;
}
我们要将Arithmetic_Operation函数封装为一个.mexw64文件并在MATLAB中调用,具体的做法是:
新建一个.cpp文件,这里需要注意的是:
cpp文件名就是在MATLAB中编译了之后以供调用的函数名,所以请不要随意命名需要编译的cpp文件。
我们将文件名为ArithmeticOp.cpp
也就是说,在编译好了之后在MATLAB中调用方式是:
[ res ] = ArithmeticOp(a, b);
下面是ArithmeticOp.cpp文件的实现:
/* ArithmeticOp.cpp */
#include "mex.h" //一定要包含这个头文件,这个头文件是MATLAB为MEX编译专门提供的头文件
#include
// 被封装的函数声明
void Arithmetic_Operation( double* res, double a, double b );
/*
* 请注意下面的这个mexFunction函数,如果需要使用mex编译C++函数,一定要使用这个函数
* mexFunction就像#include "mex.h"一样是必须的,相当于是MATLAB和C++的一个接口函数
* 这个函数的四个参数都是有用的,它们分别代表的意思是:
* nlhs: 输入参数个数(MATLAB调用语句中,等号左边的参数个数) plhs: 输入参数列表
* nrhs: 输出参数个数(MATLAB调用语句中,等号右边的参数个数) prhs: 输处参数列表
*/
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, mxArray *prhs[] )
{
if (nlhs != 1 || nrhs != 2 )// 判断调用参数数量是否正确
{
printf("Invalid Argument Usage!\n");
exit(0);
}
// get input data
double* a = mxGetPr(prhs[0]); // 输入参数列表,下标0是第一个输入参数
double* b = mxGetPr(prhs[1]); // 类似于C++ main函数的两个参数(int argc, char** argv)的使用
double* result = (double *)malloc(4*sizeof(double));
// invoke
Arithmetic_Operation(result, *a, *b);
// output data
plhs[0] = mxCreateDoubleMatrix(4, 1, mxREAL);// 用于创建一个double型的矩阵,三个参数分别是矩阵的行,列,类型
double* output = (double *)mxGetPr(plhs[0]); // mexGetPr()函数是mex.h中提供的用于获取输入输出参数地址的函数
for (int i = 0; i < 4; i++)
output[i] = result[i];
free(result);
return;
}
/* 被封装的函数 */
void Arithmetic_Operation( double* res, double a, double b )
{
res[0] = a + b;
res[1] = a - b;
res[2] = a * b;
res[3] = ( b == 0 ? 0 : a / b ) ; // check whether divide is zero
return;
}
// end of implementation
这样,一个简单的MATLAB调用C++函数的demo就写好了,如果读者需要使用并修改功能,就是直接修改mexFunction中的内容即可。更复杂的功能和函数都是可以的。
2. MATLAB端
上面复杂的C++代码都已经写好了,剩下的MATLAB的部分就相对容易了。
使用mexcc编译有一个必要的条件就是安装了VS编译器。
我的配置环境是MATLAB 2011b + VS2010 ultimate + win7-64bit
然后打开MATLAB的 Command Window
输入
然后选择选择y
选择编译器1
再选择y ...
接下来就配置好了的。
接着我们编译刚才写好的ArithmeticOp.cpp文件
在MATLAB中输入
这样就会生成相应的ArithmeticOp.mexw64文件(根据系统位数决定)
然后复制一份.mexw64文件在MATLAB中的工作目录下,就可以正常的在MATLAB Command Window或者.m文件中调用了
几点注意事项
1. MATLAB和C++的交互中,接口的调用都是Double型的
2. plhs和prhs使用mxCreateDoubleMatrix()分配的内存是不用回收的,因为接口部分的内存信息是需要传递的
3. 在保持mexFunction()不变的情况下,其他所有的C/C++的功能与特性都是支持的。