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?
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.
Related
I'm following this example but I'm not sure what I missed. Specifically, I have this struct in MATLAB:
a = struct; a.one = 1.0; a.two = 2.0; a.three = 3.0; a.four = 4.0;
And this is my test code in MEX ---
First, I wanted to make sure that I'm passing in the right thing, so I did this check:
int nfields = mxGetNumberOfFields(prhs[0]);
mexPrintf("nfields =%i \n\n", nfields);
And it does yield 4, since I have four fields.
However, when I tried to extract the value in field three:
tmp = mxGetField(prhs[0], 0, "three");
mexPrintf("data =%f \n\n", (double *)mxGetData(tmp) );
It returns data =1.000000. I'm not sure what I did wrong. My logic is that I want to get the first element (hence index is 0) of the field three, so I expected data =3.00000.
Can I get a pointer or a hint?
EDITED
Ok, since you didn't provide your full code but you are working on a test, let's try to make a new one from scratch.
On Matlab side, use the following code:
a.one = 1;
a.two = 2;
a.three = 3;
a.four = 4;
read_struct(a);
Now, create and compile the MEX read_struct function as follows:
#include "mex.h"
void read_struct(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs != 1)
mexErrMsgTxt("One input argument required.");
/* Let's check if the input is a struct... */
if (!mxIsStruct(prhs[0]))
mexErrMsgTxt("The input must be a structure.");
int ne = mxGetNumberOfElements(prhs[0]);
int nf = mxGetNumberOfFields(prhs[0]);
mexPrintf("The structure contains %i elements and %i fields.\n", ne, nf);
mwIndex i;
mwIndex j;
mxArray *mxValue;
double *value;
for (i = 0; i < nf; ++i)
{
for (j = 0; j < ne; ++j)
{
mxValue = mxGetFieldByNumber(prhs[0], j, i);
value = mxGetPr(mxValue);
mexPrintf("Field %s(%d) = %.1f\n", mxGetFieldNameByNumber(prhs[0],i), j, value[0]);
}
}
return;
}
Does this correctly prints your structure?
I have encountered an issue when using Eigen in MATLAB MEX files.
Consider this excerpt of code, in which I call a mex function to create an object of the class vars. The class has an integer N, an integer S, and two Eigen arrays.
//constructMat.cpp
class vars {
public:
int N
int S
Eigen::ArrayXd upperLims
Eigen::ArrayXd lowerLims
stateVars (double *, double *, double *)
};
stateVars::stateVars (double *upperInput, double *lowerInput, double *gridInput)
Eigen::ArrayXd upper; upper = Eigen::Map<Eigen::VectorXd>(upperInput, sizeof(*upperInput),1);
Eigen::ArrayXd lower; lower = Eigen::Map<Eigen::VectorXd>(lowerInput, sizeof(*lowerInput),1);
Eigen::ArrayXd gridSizes; gridSizes = Eigen::Map<Eigen::VectorXd>(gridInput, sizeof(*gridInput),1);
upperLims = upper;
lowerLims = lower;
N = upperLims.size();
S = gridSizes.prod();
}
//MEX CODE
void
mexFunction(int nlhs,mxArray *plhs[],int nrhs,const mxArray *prhs[])
{
//....checks to make sure the inputs are okay...
double* upper = mxGetPr(prhs[0]);
double* lower = mxGetPr(prhs[1]);
double* grids = mxGetPr(prhs[2]);
stateVars stateSpace(upper, lower, grids);
mexPrintf("N =%f \n\n", stateSpace.N );
mexPrintf("S =%f \n\n", stateSpace.S );
}
However, when I execute the function, I call constructMat([7.0, 8.0, 9.0], [4.0, 2.0, 3.0], [10, 10, 10]), and I expect mexPrintf("N =%f \n\n", stateSpace.N ) to yield 3 since the array upperLims only has three elements. However, it yields 7. Similarly, I expect mexPrintf("S =%f \n\n", stateSpace.S ) to yield 10^3 = 1000, but it yields 7 as well. I'm not sure what I did wrong. The mex file was compiled successfully.
Also, if I call mexPrintf("upperlims =%f \n\n",stateSpace.upperLims(0) ), i.e. printing out the first element of the Eigen array upperLims, it gives me the right number. Does it have something to do with the method .size() and .prod()?
In the code below "h_fir" is giving all zeros differently from the equivalent Matlab code.
"L" = 204621
This is a function inside a mex file. The call from Matlab is working well and it come back well.
Can you devise the reason?
Matlab 2015a
Below a minimal example.
Thanks
Luis Gonçalves
#include "C:\Program Files\MATLAB\MATLAB Production Server\R2015a\extern\include\mex.h"
#include "C:\Program Files\MATLAB\MATLAB Production Server\R2015a\extern\include\matrix.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <malloc.h>
#include <time.h>
#include <string.h>
#define MAX(p,q) ((p>q)?p:q)
void example(mxArray *,double, double);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double v,f_simb,ts,vkmh,fd,c,R,p,q,fc,pqmax;
mxArray *h_fir;
int g2;
double *a3,*a4;
ts=10e-3;
vkmh=50;
c=3e8;
fc=2e9;
f_simb=1/ts;
v=vkmh/3.6;
fd=v/c*fc;
R=f_simb/(fd*110.5);
p = 100.0;
q = (double)(int)(p/R+0.5);
if (q<0.001)
q= 1.0;
h_fir= mxCreateDoubleMatrix(1,(int)(2.0*10.0*MAX(p,q) + 1.5),mxCOMPLEX);
example(h_fir,p,q);
a3 = mxGetPr(h_fir);
a4=mxGetPi(h_fir);
for(g2=102306-10;g2<102306+10;g2++)
mexPrintf("%e %e\n",a3[g2],a4[g2]);
return;
}
void example(mxArray *h_fir,double p, double q)
{
double N,pqmax,fc,L;
mxArray *L1,*ARRAY1,*ARRAY2;
double *array1,*array2,*hr,*hi;
mxArray *ppFevalRhs[3];
mxArray *ppFevalRhsin[1], *OUT1;
int i1,i2,*l1;
const size_t dims[2]={1,1};
N = 10.0;
pqmax = MAX(p,q);
fc = 1.0/2.0/pqmax;
L = 2.0*N*pqmax + 1.0;
L1 = mxCreateNumericArray(2, dims,mxINT32_CLASS, mxREAL);
l1 = (int *)mxGetData(L1);
*l1= (int)(L-1);
ppFevalRhs[0]=L1;
ARRAY1 = mxCreateDoubleMatrix(4, 1, mxCOMPLEX);
array1 = mxGetPr(ARRAY1);
array1[0]= 0;
array1[1]= 2.0*fc;
array1[2]= 2.0*fc;
array1[3]= 1;
array1 = mxGetPi(ARRAY1);
array1[0]= 0;
array1[1]= 0;
array1[2]= 0;
array1[3]= 0;
ppFevalRhs[1]=ARRAY1;
ARRAY2 = mxCreateDoubleMatrix(4, 1, mxCOMPLEX);
array2 = mxGetPr(ARRAY2);
array2[0]= 1;
array2[1]= 1;
array2[2]= 0;
array2[3]= 0;
array2 = mxGetPi(ARRAY2);
array2[0]= 0;
array2[1]= 0;
array2[2]= 0;
array2[3]= 0;
ppFevalRhs[2]=ARRAY2;
ppFevalRhsin[0]=h_fir;
if (mexCallMATLAB(1, ppFevalRhsin, 3, ppFevalRhs, "firls")!=0)
mexPrintf("firls error\n");
mxDestroyArray(L1);
mxDestroyArray(ARRAY1);
mxDestroyArray(ARRAY2);
}
The output variables of a matlab function called from mex are created by matlab and do not needed to be allocated before. The previous allocated pointer passed to matlab is overwritten by matlab. That is why the code above do not works.
I am doing below in a loop with dims = [1024 768 256]. I want to read a set of block loaded by block_iter (1 to 16) into a RAM of hardware. The memory call seems to display the memory leaking. Am I doing it wrong somewhere?
for (block_iter = 1; block_iter <= num_blocks; block_iter++)
{
//Allocate memory to read data;
mxArray *B= mxCreateNumericArray(3, dims, mxUINT8_CLASS, mxREAL); // Pointer to mxArray
mxArray *in = mxCreateDoubleMatrix(1, 1, mxREAL);
mexCallMATLAB(0, NULL, 0, NULL, "memory");
memcpy(mxGetPr(in), &block_iter, sizeof(double)*1*1);
mexCallMATLAB(1, &B, 1, &in, "data_feeder");
//Call RAM_FILL
ram_fill(d,B);
//Deallocate memory;
mxDestroyArray(B);
mxDestroyArray(in);
}
P.S: the memory leak is around 192 MB each loop which is exactly the amount of data in array B.
for (block_iter = 1; block_iter <= num_blocks; block_iter++)
{
mxArray *B;// = mxCreateNumericArray(3,dims,mxUINT8_CLASS,mxREAL); //Pointer to mxArray
mxArray *ppLhs[1];
mxArray *in = mxCreateDoubleMatrix(1, 1, mxREAL);
// mexCallMATLAB(0,NULL,0,NULL,"memory");
memcpy(mxGetPr(in), &block_iter, sizeof(double)*1*1);
mexCallMATLAB(1, ppLhs,1,&in,"data_feeder");
B = ppLhs[0];
//Call RAM_FILL
ram_fill(d,B,block_iter);
// mexPrintf("BlockIter %d\n",(int)block_iter);
//Deallocate memory;
mxDestroyArray(B);
mxDestroyArray(in);
}
I did this as the mxCallMatlab worked fine with an array of mxArray *, this works fine without memory leak. If there's any elegant solution please let me know.
I wrote the following C/MEX code using the FFTW library to control the number of threads used for a FFT computation from MATLAB. The code works great (complex FFT forward and backward) with the FFTW_ESTIMATE argument in the planner although it is slower than MATLAB. But, when I switch to the FFTW_MEASURE argument to tune up the FFTW planner, it turns out that applying one FFT forward and then one FFT backward does not return the initial image. Instead, the image is scaled by a factor. Using FFTW_PATIENT gives me an even worse result with null matrices.
My code is as follows:
Matlab functions:
FFT forward:
function Y = fftNmx(X,NumCPU)
if nargin < 2
NumCPU = maxNumCompThreads;
disp('Warning: Use the max maxNumCompThreads');
end
Y = FFTN_mx(X,NumCPU)./numel(X);
FFT backward:
function Y = ifftNmx(X,NumCPU)
if nargin < 2
NumCPU = maxNumCompThreads;
disp('Warning: Use the max maxNumCompThreads');
end
Y = iFFTN_mx(X,NumCPU);
Mex functions:
FFT forward:
# include <string.h>
# include <stdlib.h>
# include <stdio.h>
# include <mex.h>
# include <matrix.h>
# include <math.h>
# include </home/nicolas/Code/C/lib/include/fftw3.h>
char *Wisfile = NULL;
char *Wistemplate = "%s/.fftwis";
#define WISLEN 8
void set_wisfile(void)
{
char *home;
if (Wisfile) return;
home = getenv("HOME");
Wisfile = (char *)malloc(strlen(home) + WISLEN + 1);
sprintf(Wisfile, Wistemplate, home);
}
fftw_plan CreatePlan(int NumDims, int N[], double *XReal, double *XImag, double *YReal, double *YImag)
{
fftw_plan Plan;
fftw_iodim Dim[NumDims];
int k, NumEl;
FILE *wisdom;
for(k = 0, NumEl = 1; k < NumDims; k++)
{
Dim[NumDims - k - 1].n = N[k];
Dim[NumDims - k - 1].is = Dim[NumDims - k - 1].os = (k == 0) ? 1 : (N[k-1] * Dim[NumDims-k].is);
NumEl *= N[k];
}
/* Import the wisdom. */
set_wisfile();
wisdom = fopen(Wisfile, "r");
if (wisdom) {
fftw_import_wisdom_from_file(wisdom);
fclose(wisdom);
}
if(!(Plan = fftw_plan_guru_split_dft(NumDims, Dim, 0, NULL, XReal, XImag, YReal, YImag, FFTW_MEASURE *(or FFTW_ESTIMATE respectively)* )))
mexErrMsgTxt("FFTW3 failed to create plan.");
/* Save the wisdom. */
wisdom = fopen(Wisfile, "w");
if (wisdom) {
fftw_export_wisdom_to_file(wisdom);
fclose(wisdom);
}
return Plan;
}
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
#define B_OUT plhs[0]
int k, numCPU, NumDims;
const mwSize *N;
double *pr, *pi, *pr2, *pi2;
static long MatLeng = 0;
fftw_iodim Dim[NumDims];
fftw_plan PlanForward;
int NumEl = 1;
int *N2;
if (nrhs != 2) {
mexErrMsgIdAndTxt( "MATLAB:FFT2mx:invalidNumInputs",
"Two input argument required.");
}
if (!mxIsDouble(prhs[0])) {
mexErrMsgIdAndTxt( "MATLAB:FFT2mx:invalidNumInputs",
"Array must be double");
}
numCPU = (int) mxGetScalar(prhs[1]);
if (numCPU > 8) {
mexErrMsgIdAndTxt( "MATLAB:FFT2mx:invalidNumInputs",
"NumOfThreads < 8 requested");
}
if (!mxIsComplex(prhs[0])) {
mexErrMsgIdAndTxt( "MATLAB:FFT2mx:invalidNumInputs",
"Array must be complex");
}
NumDims = mxGetNumberOfDimensions(prhs[0]);
N = mxGetDimensions(prhs[0]);
N2 = (int*) mxMalloc( sizeof(int) * NumDims);
for(k=0;k<NumDims;k++) {
NumEl *= NumEl * N[k];
N2[k] = N[k];
}
pr = (double *) mxGetPr(prhs[0]);
pi = (double *) mxGetPi(prhs[0]);
//B_OUT = mxCreateNumericArray(NumDims, N, mxDOUBLE_CLASS, mxCOMPLEX);
B_OUT = mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxCOMPLEX);
mxSetDimensions(B_OUT , N, NumDims);
mxSetData(B_OUT , (double* ) mxMalloc( sizeof(double) * mxGetNumberOfElements(prhs[0]) ));
mxSetImagData(B_OUT , (double* ) mxMalloc( sizeof(double) * mxGetNumberOfElements(prhs[0]) ));
pr2 = (double* ) mxGetPr(B_OUT);
pi2 = (double* ) mxGetPi(B_OUT);
fftw_init_threads();
fftw_plan_with_nthreads(numCPU);
PlanForward = CreatePlan(NumDims, N2, pr, pi, pr2, pi2);
fftw_execute_split_dft(PlanForward, pr, pi, pr2, pi2);
fftw_destroy_plan(PlanForward);
fftw_cleanup_threads();
}
FFT backward:
This MEX function differs from the above only in switching pointers pr <-> pi, and pr2 <-> pi2 in the CreatePlan function and in the execution of the plan, as suggested in the FFTW documentation.
If I run
A = imread('cameraman.tif');
>> A = double(A) + i*double(A);
>> B = fftNmx(A,8);
>> C = ifftNmx(B,8);
>> figure,imagesc(real(C))
with the FFTW_MEASURE and FFTW_ESTIMATE arguments respectively I get this result.
I wonder if this is due to an error in my code or in the library. I tried different thing around the wisdom, saving not saving. Using the wisdom produce by the FFTW standalone tool to produce wisdom. I haven't seen any improvement. Can anyone suggest why this is happening?
Additional information:
I compile the MEX code using static libraries:
mex FFTN_Meas_mx.cpp /home/nicolas/Code/C/lib/lib/libfftw3.a /home/nicolas/Code/C/lib/lib/libfftw3_threads.a -lm
The FFTW library hasn't been compiled with:
./configure CFLAGS="-fPIC" --prefix=/home/nicolas/Code/C/lib --enable-sse2 --enable-threads --&& make && make install
I tried different flags without success. I am using MATLAB 2011b on a Linux 64-bit station (AMD opteron quad core).
FFTW computes not normalized transform, see here:
http://www.fftw.org/doc/What-FFTW-Really-Computes.html
Roughly speaking, when you perform direct transform followed by inverse one, you get
back the input (plus round-off errors) multiplied by the length of your data.
When you create a plan using flags other than FFTW_ESTIMATE, your input is overwritten:
http://www.fftw.org/doc/Planner-Flags.html