Reputation: 2337
I am writing a mex file in which conv2
function is called. This mex
file will get an image of size (M, N)
and apply convolution several time using 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 );
}
In my actual code, when it reaches the line:
myconv( Temp, maskTranspose, TempConvolved );
MATLAB crashes which I have no clue why this happens and unfortunately I could not duplicate the same error in the example code I provided above. In my actual code, the image is convolved successfully by line:
myconv( Ain, mask, AinConvolved );
However, as soon as it wants to apply a second convolution:
myconv( Temp, maskTranspose, TempConvolved );
It crashes and when I debug it, it occurs when mexCallMATLAB
is called on myconv
function. What can be the difference between Temp
/TempConvolved
and Ain
/AinConvolved
that makes the former crash at the time of mexCallMATLAB
?
Could someone kindly help me fix this issue?
Upvotes: 1
Views: 250
Reputation: 30589
Reusing data buffers
Reusing the data pointer from mxArray *mask
for mxArray *maskTransposed
is asking for trouble, as MATLAB has rigorous mechanisms for reference counting as shared-data arrays are an important part of MATLAB's memory optimizations. Instead, duplicate the whole thing with mxDuplicateArray
:
mxArray *maskTranspose = mxDuplicateArray(mask);
There is an undocumented mxCreateSharedDataCopy
that emulates MATLAB's lazy-copy mechanism, but that's really overkill for a 5-element array.
Superfluous-to-problematic mxArray
initialization prior to mexCallMATLAB
Also, do not bother initializing mxArray *AinConvolved
before calling mexCallMATLAB
. Just pass a NULL pointer and it will create it for you. If you don't it will just wipe the old one (send it to garbage collection) and create a fresh one for the output of conv2
. Which reminds me this demonstrates how this is a problem in your code:
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);
Output in MATLAB:
00000000B852FA20
0000000026B8EB00
As you can see, if you try to use the pointer you got with mxGetPr
before using mexCallMATLAB
, you're probably using the wrong data, possibly already deallocated memory..
Automatic separable filtering with imfilter
Also, note that if you have imfilter
, you don't need to implement separable convolution because it has that functionality built in. Just have a look at imfilter.m
and note the isSeparable
function. See here for more information.
Try that, I'll post a test.
Upvotes: 1