一直想學習mex接口函數,可惜之前沒有用到過,於是沒特別在意。這次因爲跑別人的code,感覺還是搞出一個matlab wrapper,這樣會比較方便。但是這個涉及到mex混編以及調用opencv的問題。
於是乎,裏面涉及到很很多多的問題,包括配置的問題,編譯的問題,參數傳遞的問題,等等。但是,一旦你能掌握他,你就相當於結合了MATLAB的優點(容易上手,快速編程,不需要考慮定義變量)和C的優點(計算速度快)。
首先給出幾個學習mex文件的鏈接:
www.cnblogs.com/lidabo/archive/2012/08/24/2654148.html
http://blog.csdn.net/njust_qhzt/article/details/8249008
http://www.cnblogs.com/Key-Ky/p/4233581.html
基本格式:
#include "mex.h"
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
}
四個參數分別用來輸出和輸入數據: nlhs 輸出參數個數,plhs 輸出參數指針 (nrhs和prhs是輸入參數相關的)。同時如果涉及到了opencv的編譯,一般還要include "mxArray。h"
注意: 我們對輸出和輸入參數的操作都是通過指針的方式進行的。(這點很容易理解,因爲我們的計算結果是需要傳遞給MATLAB的,實際上我們傳遞的不是數據,而是指針。MATLAB可以通過這些指針,訪問內存中的數據。)
mex文件本質上是接口文件,於是就涉及到數據的輸入和輸出,也就是從MATLAB傳數據給c和從c傳數據給MATLAB。
操作輸入數據(matlab->c)
對輸入數據進行操作,需要通過MEX函數mxGetPr 得到數據的指針地址。 mxGetM 和 mxGetN 得到矩陣數據的行和列 (返回整數)。對於實矩陣,我們可以定義 double *M; 來對實矩陣數據操作。如:
double *M;
int m,n;
// 指針指向第一個參數的數據地址
M = mxGetPr(prhs[0]);
m = mxGetM(prhs[0]);
n = mxGetN(prhs[0]);
1.輸入的如果是單個常數,就可以用
int x
x = mxGetScalar(prhs[0]);
//該函數獲取matlab傳遞過來的數值;
dataCursor = mxGetPr(prhs[0]);
//得到輸入矩陣的第一個元素的指針
int
mrows = mxGetM(prhs[0]);
//獲得矩陣的行
int
ncols = mxGetN(prhs[0]);
//獲得矩陣的列
這樣就可以獲得矩陣的指針dataCursor進行進一步的操作,下面將給出一個詳細額例子。
特殊情況,如果傳的是image,image本身也是矩陣,但是可能是三維的,於是可以用mxArray的函數實現傳遞。
3.如果是字符串:
char
*input_buf;
input_buf = mxArrayToString(prhs[0]);
//使用mxArrayToString將mxArray轉換爲c、c++字符串
需要注意的是,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開始.
操作輸出數據
對於輸出數據,我們需要首先分配內存空間,有專門的mex函數可以使用,如:
plhs[0] = mxCreateDoubleMatrix(m,n, mxREAL); //生成m x n 的實矩陣。
此外還有mxCreateNumericMatrix(m,n,mxREAL);。具體參考上面的第三個鏈接
同輸入數據一樣,要對輸出數據操作,我們也需要一個指向數據的指針變量,如
double *A;
A = mxGetPr(plhs[0]);
然後我們就可以把數值付給A。
下面是個幾個例子:
1.矩陣傳入和傳出
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
double *inData;
double *outData;
int M,N;
int i,j;
inData=mxGetPr(prhs[0]); //獲取輸入的第一個參數指針
M=mxGetM(prhs[0]);
N=mxGetN(prhs[0]);
plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL); //構建一個輸出用的矩陣
outData=mxGetPr(plhs[0]); //指針
for( i=0;i <M;i++)
for(j=0;j <N;j++
outData[j*M+i] =inData[(N-1-j)*M+i];
}
#include "mex.h"
void
mexFunction(
int
nlhs, mxArray *plhs[],
int
nrhs,
const
mxArray *prhs[]){
double
*dataCursor; //指向第一個輸入變量的指針
vector<vector<
double
> > parms; //利用c++的vector定義矩陣
dataCursor = mxGetPr(prhs[0]);
//得到輸入矩陣的第一個元素的指針
int
mrows = mxGetM(prhs[0]);
//獲得矩陣的行
int
ncols = mxGetN(prhs[0]);
//獲得矩陣的列
printf
(
"%d_%d\n"
, mrows, ncols);
//打印行和列
parms.resize(mrows);
//初始化
for
(
int
i = 0; i < mrows; i++){
parms[i].resize(ncols); //每一個一維數組元素都初始化一個向量,於是得到一個矩陣
}
for
(
int
i = 0; i < mrows; i++){
for
(
int
j = 0; j < ncols; j++){
parms[i][j] = dataCursor[j * mrows + i];
//拷貝矩陣的元素到vector of vector
}
}
下面講講涉及到opencv的情況,如果直接傳圖片到c,那麼可以直接用cv::Mat image = MxArray(plhs[0]).toMat();
那麼得到的image就是Mat格式的,而不是vector格式的。如果想從Mat轉vector格式,可以用 im[i*w+j] = image.at<float>(i,j);
實現轉化,注意是float,不是double,因爲opencv和c的精度是不等價的。