我的 mex 文件有什么问题? input/output定义?
What is wrong in my mex file? input/output definition?
我正在尝试 运行 我在 VS 中用 C++ 编写的 mex 函数。它在 MATLAB 中编译成功但 returns 错误的值。我非常确定,我不是在读取 16×21 输入矩阵伽马。有人能看出这里出了什么问题吗?
void fun(double gammas[], int num1, int num2, int length, double a[])
{
...
}
void mexFunction(int nlhs, mxArray *plhs, int nrhs, const mxArray *prhs)
{
double *gammas, *a;
int num1, num2, length;
size_t mrows, mcols;
mrows = 4; mcols = 21;
length = 21;
plhs[0] = mxCreateDoubleMatrix((mSize)mrows, (mwSize)ncols, mxREAL);
gammas = mxGetPr(prhs[0]);
num1 = (int)*mxGetPr(prhs[1]);
num2 = (int)*mxGetPr(prhs[2]);
a = mxGetPr(plhs[0]);
fun(gammas, num1, num2, length, a);
}
当我在 "main" 中调用 "fun" 而不是 VS 中的 "mex" 函数并手动提供输入伽玛时,我得到正确的 "a"。当我在我的 MATLAB 代码中调用生成的 mex 文件时,我收到错误的 "a"。
作为输入转置矩阵来解决 的 row/column-major 差异的替代方法,您可以在 MEX 文件中处理转置。使用辅助 C++ 函数。您可以编写一个循环来复制元素,或者通过 mexCallMATLAB
简单地调用 permute
。类似于以下内容:
int permute2DMATtoC(mxArray*& matPermuted, const mxArray* mat)
{
mxAssert(mxGetNumberOfDimensions(mat)<=3, "Requires 2D or 3D matrix.");
mxArray *permuteRHSArgs[2];
permuteRHSArgs[0] = const_cast<mxArray*>(mat);
permuteRHSArgs[1] = mxCreateDoubleMatrix(1,3,mxREAL);
mxGetPr(permuteRHSArgs[1])[0] = 2;
mxGetPr(permuteRHSArgs[1])[1] = 1;
mxGetPr(permuteRHSArgs[1])[2] = 3; // supports 2D and 3D
return mexCallMATLAB(1, &matPermuted, 2, permuteRHSArgs, "permute");
}
使用:
mxArray *matPermuted;
permute2DMATtoC(matPermuted, prhs[0]); // matPermuted is MATLAB-managed
double *gammas = (double*)mxGetData(matPermuted);
注意:由于 matPermuted
由 MATLAB 管理,您无需显式销毁它来回收资源,但是当您完成后,您可以根据需要执行此操作:
mxDestroyArray(matPermuted);
对于 RGB,可能需要将像素顺序 (RGB-RGB-RGB-...) 转换为平面顺序 (RRRR...-GGGG...-BBBB...)。
正如对您的问题的评论所怀疑的那样,问题是由于 matlab 和 c/c++ 如何将线性存储的数组元素排序为内存中的一维数组。 Matlab 使用 column-major order while C/C++ uses row-major.
我不建议您在调用 mex 函数之前进行排列,而是建议您在 mex 函数内部进行排列。正如@chappjc 所建议的,通过使用 mexCallMatlab
调用 permute
或调用 mxCalcSingleSubscript
,其中 returns matlab 的线性索引来自坐标(无论维数是多少)。
旁注:需要确认并找回我读过的很棒的文章,但 matlab 使用列优先排序,因为它更适合矩阵乘法(创建较少的页面默认值访问内存缓存时,因此速度更快)。再次需要确认 ...但至少这个组织更适合按列而不是按行访问...
编辑
顺便说一句,一些简单的代码 (C#) 从 maltab 的基于零的线性索引(mxCalcSingleSubscript
的反向)获取坐标:
private static int[] getCoordinatesFromMatlabLinearIndex(int index, int[] arrayDims)
{
var ret = new int[count];
var count = arrayDims.Length;
for (var k = 0; k < count; k++)
{
index = Math.DivRem(index, arrayDims[k], out ret[k]);
}
return ret;
}
我正在尝试 运行 我在 VS 中用 C++ 编写的 mex 函数。它在 MATLAB 中编译成功但 returns 错误的值。我非常确定,我不是在读取 16×21 输入矩阵伽马。有人能看出这里出了什么问题吗?
void fun(double gammas[], int num1, int num2, int length, double a[])
{
...
}
void mexFunction(int nlhs, mxArray *plhs, int nrhs, const mxArray *prhs)
{
double *gammas, *a;
int num1, num2, length;
size_t mrows, mcols;
mrows = 4; mcols = 21;
length = 21;
plhs[0] = mxCreateDoubleMatrix((mSize)mrows, (mwSize)ncols, mxREAL);
gammas = mxGetPr(prhs[0]);
num1 = (int)*mxGetPr(prhs[1]);
num2 = (int)*mxGetPr(prhs[2]);
a = mxGetPr(plhs[0]);
fun(gammas, num1, num2, length, a);
}
当我在 "main" 中调用 "fun" 而不是 VS 中的 "mex" 函数并手动提供输入伽玛时,我得到正确的 "a"。当我在我的 MATLAB 代码中调用生成的 mex 文件时,我收到错误的 "a"。
作为输入转置矩阵来解决 mexCallMATLAB
简单地调用 permute
。类似于以下内容:
int permute2DMATtoC(mxArray*& matPermuted, const mxArray* mat)
{
mxAssert(mxGetNumberOfDimensions(mat)<=3, "Requires 2D or 3D matrix.");
mxArray *permuteRHSArgs[2];
permuteRHSArgs[0] = const_cast<mxArray*>(mat);
permuteRHSArgs[1] = mxCreateDoubleMatrix(1,3,mxREAL);
mxGetPr(permuteRHSArgs[1])[0] = 2;
mxGetPr(permuteRHSArgs[1])[1] = 1;
mxGetPr(permuteRHSArgs[1])[2] = 3; // supports 2D and 3D
return mexCallMATLAB(1, &matPermuted, 2, permuteRHSArgs, "permute");
}
使用:
mxArray *matPermuted;
permute2DMATtoC(matPermuted, prhs[0]); // matPermuted is MATLAB-managed
double *gammas = (double*)mxGetData(matPermuted);
注意:由于 matPermuted
由 MATLAB 管理,您无需显式销毁它来回收资源,但是当您完成后,您可以根据需要执行此操作:
mxDestroyArray(matPermuted);
对于 RGB,可能需要将像素顺序 (RGB-RGB-RGB-...) 转换为平面顺序 (RRRR...-GGGG...-BBBB...)。
正如对您的问题的评论所怀疑的那样,问题是由于 matlab 和 c/c++ 如何将线性存储的数组元素排序为内存中的一维数组。 Matlab 使用 column-major order while C/C++ uses row-major.
我不建议您在调用 mex 函数之前进行排列,而是建议您在 mex 函数内部进行排列。正如@chappjc 所建议的,通过使用 mexCallMatlab
调用 permute
或调用 mxCalcSingleSubscript
,其中 returns matlab 的线性索引来自坐标(无论维数是多少)。
旁注:需要确认并找回我读过的很棒的文章,但 matlab 使用列优先排序,因为它更适合矩阵乘法(创建较少的页面默认值访问内存缓存时,因此速度更快)。再次需要确认 ...但至少这个组织更适合按列而不是按行访问...
编辑
顺便说一句,一些简单的代码 (C#) 从 maltab 的基于零的线性索引(mxCalcSingleSubscript
的反向)获取坐标:
private static int[] getCoordinatesFromMatlabLinearIndex(int index, int[] arrayDims)
{
var ret = new int[count];
var count = arrayDims.Length;
for (var k = 0; k < count; k++)
{
index = Math.DivRem(index, arrayDims[k], out ret[k]);
}
return ret;
}