- 在线时间
- 332 小时
- 最后登录
- 2017-1-30
- 注册时间
- 2011-5-20
- 听众数
- 105
- 收听数
- 49
- 能力
- 90 分
- 体力
- 8076 点
- 威望
- 450 点
- 阅读权限
- 150
- 积分
- 9483
- 相册
- 0
- 日志
- 0
- 记录
- 1
- 帖子
- 1456
- 主题
- 90
- 精华
- 0
- 分享
- 48
- 好友
- 259
TA的每日心情 | 怒 2017-1-30 23:35 |
---|
签到天数: 318 天 [LV.8]以坛为家I 2010挑战赛参赛者 2011挑战赛参赛者 2012挑战赛参赛者 2013挑战赛参赛者
群组: 物联网工程师培训 群组: Matlab讨论组 群组: 2013认证赛C题讨论群组 群组: 数学建模 群组: 2013认证赛A题讨论群组 |
mex接口的结构:
//////////////////////////////////////////////
#include "mex.h"
///////////////////////////
// Computational Routine //
///////////////////////////
// interface & function declaration
return_type myFunc1(parameter1, parameter2, ...);
return_type myFunc2(parameter1, parameter2, ...);
...
// interface & function defination, implementation
void myMex(parameter1, parameter2, ...){
statements
}
return_type myFunc1(parameter1, parameter2, ...){
statements
}
return_type myFunc2(parameter1, parameter2, ...){
statements
}
...
/////////////////////
// Gateway Routine //
/////////////////////
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
...
myMex(parameter list);
}
//////////////////////////////////////////////
调用mex时,MATLAB将输入的数据通过入口子程序赋给输入参数指针,同时创建由输出参数指针指向的输出矩阵,然后将这些指针作为计算子程序的参数传递到计算子程序进行计算。
mexFunction在调用C函数时,直接使用指针传递参数是比较方便的,一方面需要计算的结果往往是一个矩阵而不是一个数,另一方面以值传递值返回的方式,同样需要赋值给mex接口的指针。
在mexFunction的参数中:
nlhs表示输出参数的个数
nrhs表示输入参数的个数
类型为mxArray的指针数组,用于指向输出的每个参数
类型为mxArray的指针数组,用于指向输入的每个参数
为了mex的正确执行,也是良好编程习惯的要求,需要对输入参数和输出参数进行个数和类型的检查:
mxGetClassID //获得指针所指变量类型
mxIsNumeric, mxIsCell等,检查指针所指变量是否为符合某种要求的变量类型。更多可查阅帮助。
参数检查过程中可使用mexErrMsgTxt输出错误信息。
mxGetM, mxGetN,获得矩阵的行数和列数
mxGetDimensions,获得矩阵维数
mxGetPr,mxGetPi,获得矩阵实数部分、虚数部分的指针
mxGetString, 获得字符串内容
mxGetElementSize, 获得存储矩阵元素所需要的字节数
mxCalloc,内存分配。用mxCalloc不用calloc和malloc,因为mxCalloc会自动释放内存,不需要手动free了。
mxCreateString, 创建1*N的字符串矩阵
mxCreateDoubleMatrix, 创建2维双精度浮点矩阵,可以是实数(mxREAL)或者复数(mxCOMPLEX)
mxCreateStructArray, 创建N维结构体矩阵
mxCreateCellMatrix, 创建二维单元矩阵
mxCreateNumericArray,创建n维数值矩阵
mexPrintf, 重新封装的printf
mxSetFiled, 设置结构体矩阵的域
mxSetCell, 设置单元矩阵的单元值
mxSetPr, 设置矩阵实数值
mxSetPi, 设置矩阵虚数值
mxCallMATLAB, 调用MATLAB中其他内建函数、自定义M文件、mex文件。
具体使用方法可查阅MATLAB帮助。
使用mex时的注意事项:
1.MATLAB调用mex接口时,将参数个数及参数指针传入接口子程序,由接口子程序完成指针和调用变量的赋值、输出数据的内存空间分配,接口子程序再将参数指针或经过赋值的变量作为参数传递给C的计算子程序,完成调用过程。调用时应注意指针所指对象的正确性,为处理正确最好做相应的强制类型转换。
2.mex并不便于调试,因此应在C的IDE中用测试集调试后再放入mex文件中。
3.MATLAB中指向二维及高维数组的指针递增方式是按行递增的,而C中是按列递增的,因此计算index时要注意位置。
下面给个我的例子:
/////////////////////////////
#include "mex.h"
int LSB(int pixel);
int tier_score(int s_1,int s_2,int x_1,int x_2);
int add_sub_select(int pixel_1,int pixel_2);
void cost_matrix_gen_c(double *output,double *x,double *len_x,double *y,double *len_y){
int i,j;
int s_1,s_2,x_1,x_2;
for (j=0;j<*len_y;j++){
x_1 = (int)*(y+j*2);
x_2 = (int)*(y+j*2+1);
for (i=0;i<*len_x;i++){
s_1 = (int)*(x+i*2);
s_2 = (int)*(x+i*2+1);
*(output++)=tier_score(s_1,s_2,x_1,x_2);
}
}
}
int tier_score(int s_1,int s_2,int x_1,int x_2){
int score;
if (s_1==LSB(x_1)){
if (s_2==add_sub_select(x_1,x_2)){
score = 20;
}
else{
score = 0;
}
}
else{
score = 0;
}
return score;
}
int LSB(int pixel){
return pixel%2;
}
int add_sub_select(int pixel_1,int pixel_2){
return LSB((int)pixel_1/2 + pixel_2);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]){
double *y,*x,*output,*len_x,*len_y;
int n_row,n_column;
if (nrhs != 4 || nlhs != 1){
mexErrMsgTxt("invalid number of input/output arguments!");
}
//参数个数检查
n_row = mxGetM(prhs[0])>mxGetN(prhs[0]) ? mxGetM(prhs[0]) : mxGetN(prhs[0]);
//获得输入向量元素个数
n_column = mxGetM(prhs[2])>mxGetN(prhs[2]) ? mxGetM(prhs[2]) : mxGetN(prhs[2]);
//获得输入向量元素个数
n_row = n_row/2;
n_column = n_column/2;
plhs[0] = mxCreateDoubleMatrix(n_row,n_column,mxREAL);
//建立n_row*n_column大小的输出矩阵
output = mxGetPr(plhs[0]);
x=mxGetPr(prhs[0]);
len_x=mxGetPr(prhs[1]);
y=mxGetPr(prhs[2]);
len_y=mxGetPr(prhs[3]);
//获得输入、输出指针
cost_matrix_gen_c(output,x,len_x,y,len_y);
//调用计算函数
}
以前我写过一篇文章,详细的介绍过MEX的格式,语法,编译,调试等。可惜记不清放在哪里了。而最近又用到MEX编程,所以只能重新温习一番。时间有限,只记下简要流程和注意事项,以便往后查询之需。
1. MEX的编写格式
写MEX程序其实就是写一个DLL程序,所以你可以使用C,C++,Fortran等多种编程语言来写。
编写MEX程序的编辑器可以使用MATLAB的代码编辑器,也可使用自己的C++编辑器,如VS2008等。
用MATLAB的编辑器的好处是,MEX函数会加粗高亮显示,这给程序编写带来便利,可惜无法动态调试。如用VC即可编译也可调试,比较方便。mex的编译结果实际上就是一个带输出函数mexFunction 的dll文件,所以会用VC编写和调试dll,就会用VC编写和调试MEX程序。
a. MEX文件格式
#include "mex.h"
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
}
四个参数分别用来输出和输入数据: nlhs 输出参数个数,plhs 输出参数指针 (nrhs和prhs是输入参数相关的)。
注意: 我们对输出和输入参数的操作都是通过指针的方式进行的。(这点很容易理解,因为我们的计算结果是需要传递给MATLAB的,实际上我们传递的不是数据,而是指针。MATLAB可以通过这些指针,访问内存中的数据。)
b. 操作输入数据
对输入数据进行操作,需要通过MEX函数mxGetPr 得到数据的指针地址。 mxGetM 和 mxGetN 得到矩阵数据的行和列 (返回整数)。对于实矩阵,我们可以定义 double *M; 来对实矩阵数据操作。如:
double *M;
int m,n;
// 指针指向第一个参数的数据地址
M = mxGetPr(prhs[0]);
m = mxGetM(prhs[0]);
n = mxGetN(prhs[0]);
需要注意的是,MATLAB矩阵数据的存储顺序是"从上到下,从左到右"的,这点和Fortran是一样的。也就是说对于MATLAB的m x n的矩阵A。 A(1,1) 就是 *M,A(2,1) 就是 *(M+1) ,以此类推,A(i,j) 就是 *(M + m*(j-1) + (i-1)).
注意: MATLAB的指标从1开始,C的指标从0开始。
c. 操作输出数据
对于输出数据,我们需要首先分配内存空间,有专门的mex函数可以使用,如:
plhs[0] = mxCreateDoubleMatrix(m,n, mxREAL); //生成m x n 的实矩阵。
同输入数据一样,要对输出数据操作,我们也需要一个指向数据的指针变量,如
double *A;
A = mxGetPr(plhs[0]);
下面介绍一下如何使用VS2008编写MEX并编译调试。
2. VC中编写MEX
打开VS2008, 新建项目, 选择MFC DLL.
a. 配置项目属性
打开项目属性配置页,C++ -> 附加包含目录 加入MATLAB安装目录下的 \extern\include 路径。
连接器 -> 附加库目录 加入MATLAB的 \extern\lib\win32\microsoft 路径。
连接器 -> 输入 -> 附加依赖项 输入libmx.lib libeng.lib libmat.lib libmex.lib 这四个lib文件。
b. 编辑输出函数
在项目源文件的. def 中EXPORTS段加入 mexFunction, 如:
EXPORTS
; 此处可以是显式导出
mexFunction
c. 编写MEX文件
项目文件中新建一个C++文件 如 mexproc.cpp,里面按前面介绍的格式编写代码即可。
d. VC编译MEX
像编译其他程序那样直接编译即可,成功会生成dll文件。如果编译链接时出错,根据错误提示,检查一下lib和h的路径是否正确,有无缺少lib文件,代码是否有语法错误等。
3. VC中调试MEX
要调试MEX程序就要先编译,再调用她。所以我们需要在MATLAB中调用这个函数,并在VC的MEX程序相应位置处下断点即可。调用的函数名就是dll的主文件名,你可以根据自己的需要改名。我们用mymexfun.dll为例,先在VC的 mexFunction 函数代码段开始处F9下断。然后Ctrl+Alt+P附加MATLAB.exe进程。这样就可以运行命令调试程序了。我们可以在MATLAB的命令行里输入命令:
[输出变量] = mymexfun(输入变量)
(如果命令找不到,检查一下matlab当前路径,和path路径。)
程序一旦被调用,就会被断在我们的断点处。接着你就可以像调试C++程序那样调试MEX程序了。
在MATLAB中编译MEX可以输入: mex 文件名.cpp
MATLAB上编译MEX时,你可以选择不同的编译器如lc, gcc等。也可以在编译时附加lib和h文件。关于mex的命令详解请参考MATLAB帮助文档。 |
|