我的 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;
}