我正在尝试运行我在VS中用c ++编写的mex函数。它在MATLAB中成功编译但返回错误的值。我非常确定,我不是在阅读16×21输入矩阵gammas。谁能看到这里有什么问题?
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);
}
当我在VS中的“main”而不是“mex”函数中调用“fun”并手动提供输入gamma时,我得到了正确的“a”。当我在MATLAB代码中调用生成的mex文件时,我收到错误的“a”。
答案 0 :(得分:2)
作为输入转置矩阵以解决CitizenInsane pointed out的行/列主要差异的替代方法,您可以在MEX文件中处理转置。使用辅助C ++函数。您可以编写循环来复制元素,也可以只通过permute
调用mexCallMATLAB
。如下所示:
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 ...)。
答案 1 :(得分:2)
正如您对问题的评论所怀疑的那样,问题是由于matlab和c / c ++如何将数组元素作为内存中的1D数组进行线性存储。 Matlab使用column-major顺序,而C / C ++使用row-major。
我不建议你在调用mex函数之前进行排列,而是在mex函数中进行排列。要么@chappjc通过调用permute
和mexCallMatlab
调用,要么调用mxCalcSingleSubscript
,从坐标(无论维度数量)返回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;
}