【问题标题】:Passing mxArray to mexCallMatlab fails将 mxArray 传递给 mexCallMatlab 失败
【发布时间】:2014-11-22 03:09:28
【问题描述】:

我正在编写一个调用 conv2 函数的 mex 文件。这个mex 文件将获得大小为(M, N) 的图像,并使用conv2 多次应用卷积。

#include "mex.h"

void myconv( mxArray *Ain, mxArray *Kernel, mxArray *&Aout )
{

    mxArray *rhs[3];

    rhs[0] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
    rhs[1] = mxCreateNumericMatrix( 0, 0, mxDOUBLE_CLASS, mxREAL );
    rhs[2] = mxCreateString       ( "same" );

    double *ainPtr = mxGetPr( Ain   );
    mxSetPr( rhs[0], ainPtr         );
    mxSetM ( rhs[0], mxGetM(Ain)    );
    mxSetN ( rhs[0], mxGetM(Ain)    );

    double *kernelPtr = mxGetPr( Kernel );
    mxSetPr( rhs[1], kernelPtr          );
    mxSetM ( rhs[1], mxGetM(Kernel)     );
    mxSetN ( rhs[1], mxGetN(Kernel)     );

    mexCallMATLAB(1, &Aout, 3, rhs, "conv2");

    mxSetPr( rhs[0], NULL ); 
    mxSetPr( rhs[1], NULL );

}

void myconv_combine( mxArray *Ain, mxArray *&Aout )
{

    mxArray *mask = mxCreateDoubleMatrix( 1, 5, mxREAL );

    double *maskPtr = mxGetPr( mask );
    maskPtr[0] = 0.05; 
    maskPtr[1] = 0.25; 
    maskPtr[2] = 0.4; 
    maskPtr[3] = 0.25; 
    maskPtr[4] = 0.05;

    mxArray *maskTranspose = mxCreateDoubleMatrix( 0, 0, mxREAL );
    mxSetPr( maskTranspose, maskPtr      );
    mxSetM ( maskTranspose, mxGetN(mask) );
    mxSetN ( maskTranspose, mxGetM(mask) );

    mxArray *AinConvolved = mxCreateDoubleMatrix( (mwSize)mxGetM(Ain), (mwSize)mxGetN(Ain), mxREAL );
    double *AinConvolvedPtr = mxGetPr( AinConvolved );
    myconv( Ain, mask, AinConvolved );

    // Some modifications.
    mxArray *Temp = mxCreateDoubleMatrix( (mwSize)mxGetM(Ain), (mwSize)mxGetN(Ain), mxREAL );
    double *TempPtr = mxGetPr( Temp );
    for( int i = 0; i < (mwSize)mxGetM(Ain)*(mwSize)mxGetN(Ain); i++ )
            TempPtr[ i ] = 2.0*AinConvolvedPtr[ i ];

    // Some other convolution.
    mxArray *TempConvolved = mxCreateDoubleMatrix( (mwSize)mxGetM(Ain), (mwSize)mxGetN(Ain), mxREAL );
    double *TempConvolvedPtr = mxGetPr( TempConvolved );
    myconv( Temp, maskTranspose, TempConvolved );

    // Some other modifications.
    double *AoutPtr = mxGetPr( Aout );
    for( int i = 0; i < (mwSize)mxGetM(Ain)*(mwSize)mxGetN(Ain); i++ )
            AoutPtr[ i ] = 2.0*TempConvolvedPtr[ i ];


}


void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{

   mxArray *Ain  = mxCreateDoubleMatrix( 100, 100, mxREAL );
   mxArray *Aout = mxCreateDoubleMatrix( 100, 100, mxREAL );

   myconv_combine( Ain, Aout );


}

在我的实际代码中,当它到达该行时:

myconv( Temp, maskTranspose, TempConvolved );

MATLAB 崩溃,我不知道为什么会发生这种情况,不幸的是,我无法在上面提供的示例代码中复制相同的错误。在我的实际代码中,图像按行成功卷积:

myconv( Ain, mask, AinConvolved );

但是,只要它想应用第二个卷积:

myconv( Temp, maskTranspose, TempConvolved );

它崩溃了,当我调试它时,它发生在 mexCallMATLABmyconv 函数调用时。 Temp/TempConvolvedAin/AinConvolved 之间有什么区别导致前者在 mexCallMATLAB 时崩溃?

有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: matlab mex


    【解决方案1】:

    重用数据缓冲区

    将来自mxArray *mask 的数据指针重用于mxArray *maskTransposed 是自找麻烦,因为 MATLAB 具有严格的引用计数机制,因为共享数据数组是 MATLAB 内存优化的重要组成部分。相反,使用mxDuplicateArray 复制整个内容:

    mxArray *maskTranspose = mxDuplicateArray(mask);
    

    有一个未记录的 mxCreateSharedDataCopy 模拟 MATLAB 的延迟复制机制,但对于 5 元素数组来说,这确实有点过头了。

    mexCallMATLAB 之前进行多余的mxArray 初始化

    另外,在调用mexCallMATLAB 之前不要费心初始化mxArray *AinConvolved。只需传递一个 NULL 指针,它就会为您创建它。如果你不这样做,它只会擦除旧的(将其发送到垃圾收集)并为conv2 的输出创建一个新的。这让我想起了这表明这是您的代码中的问题:

    mxArray *AinConvolved = mxCreateDoubleMatrix(mxGetM(Ain), mxGetN(Ain), mxREAL);
    double *AinConvolvedPtr0 = mxGetPr(AinConvolved);
    myconv(Ain, mask, AinConvolved);
    double *AinConvolvedPtr = mxGetPr(AinConvolved);
    mexPrintf("%p\n%p\n", AinConvolvedPtr0, AinConvolvedPtr);
    

    MATLAB 中的输出:

    00000000B852FA20
    0000000026B8EB00
    

    如您所见,如果您在使用 mexCallMATLAB 之前尝试使用通过 mxGetPr 获得的指针,那么您可能使用了错误的数据,可能已经释放了内存..

    使用imfilter自动分离过滤

    另外,请注意,如果您有imfilter,则不需要实现可分离卷积,因为它内置了该功能。只需查看imfilter.m 并注意isSeparable 功能。见here for more information

    试试吧,我会发布一个测试。

    【讨论】:

    • 我更改了代码并使用了mxArray *AinConvolved= NULL;mxArray *TempConvolved = NULL;。我还尝试使用myconv( Temp, mask, TempConvolved ); 来消除导致引用计数的可能性,并使用mask 而不是maskTranspose。但是,它仍然不起作用,并且问题发生在与以前相同的位置,无法计算 TempConvolved
    • @A2009 mxGetPr(AinConvolved)mxGetPr( TempConvolved ) 在调用mexCallMATLAB 之后如何放置?是否有任何可以重现的代码,您可以在 gist.github.com 上发布大量代码?
    • 让我看看如何重现错误部分以更好地澄清问题。感谢您的帮助。
    • @A2009 我今晚试试。
    • @A2009 明白,但它是same issue as before,特别是this discussion point。如果你传入一个金字塔,有两个选择:将每个级别作为它自己的输入参数,或者使用带有mxGetCell 的元胞数组。传递一个单元格非常容易。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-15
    • 2013-08-26
    • 2020-08-30
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    相关资源
    最近更新 更多