When I write MEX files which use OpenCV functions it's easy to pass the data from MATLAB to the MEX environment without copying the data. Is there a way to return the data to MATLAB in the same manner? (That is, without copying the data and without causing MATLAB to crash...)
A simple example:
#include "mex.h"
#include "/opencv2/core.hpp"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs,const mxArray *prhs[])
{
Rows=mxGetM(prhs[0]);
Cols=mxGetN(prhs[0]);
Mat InMat(Cols,Rows,CV_64FC1,mxGetPr(prhs[0]));//Matlab passes data column-wise
// no need to copy data - SUPER!
InMat=InMat.t();//transpose so the matrix is identical to MATLAB's one
//Make some openCV operations on InMat to get OutMat...
//Way of preventing the following code??
plhs[0]=mxCreateDoubleMatrix(OutMat.rows,OutMat.cols,mxREAL);
double *pOut=mxGetPr(plhs[0]);
for (int i(0);i<OutMat.rows;i++)
for (int j(0);j<OutMat.cols;j++)
pOut[i+j*OutMat.rows]=OutMat.at<double>(i,j);
}
-----------------------------------------
Usually I do the input and output just like that, attaching a pointer to deal with the input and looping over elements on output. But, I think the output can be done in a similar manner to the input, although not without a copy of some sort. The only way to avoid a copy is to create the output Mat
with a pointer from a mxArray
and operate on it inplace. That's not always possible, of course. But you can be graceful about how you copy the data out.
You can exploit the same trick of attaching a buffer to a cv::Mat
that you use (me too!) to bring data in from MATLAB, but also to get it out. The twist on the trick to exporting the data is to use copyTo
just right so that it will use the existing buffer, the one from the mxArray
in plhs[i]
.
Starting with an input like this:
double *img = mxGetPr(prhs[0]);
cv::Mat src = cv::Mat(ncols, nrows, CV_64FC1, img).t(); // nrows <-> ncols, transpose
You perform some operation, like resizing:
cv::Mat dst;
cv::resize(src, dst, cv::Size(0, 0), 0.5, 0.5, cv::INTER_CUBIC);
To get dst
into MATLAB: first transpose the output (for sake of reordering the data into col-major order) then create an output cv::Mat
with the pointer from the plhs[0]
mxArray
, and finally call copyTo
to fill out the wrapper Mat
with the transposed data:
dst = dst.t(); // first!
cv::Mat outMatWrap(dst.rows, dst.cols, dst.type(), pOut); // dst.type() or CV_*
dst.copyTo(outMatWrap); // no realloc if dims and type match
It is very important to get the dimensions and data type exactly the same for the following call to copyTo
to keep from reallocating outMatWrap
.
Note that when outMatWrap
is destroyed, the data
buffer will not be deallocated because the reference count is 0 (Mat::release()
does not deallocate .data
).
Possible template (by no means bullet-proof!)
template <typename T>
void cvToMATLAB(cv::Mat mat, T *p)
{
CV_Assert(mat.elemSize1() == sizeof(T));
mat = mat.t();
cv::Mat outMatWrap(mat.rows, mat.cols, mat.type(), p);
mat.copyTo(outMatWrap);
}
This should be good for channels>1, as long as the size of the MATLAB array is in pixel order too (e.g. 3xMxN). Then use permute
as needed.
Note about copyTo
The conditions under which copyTo
will reallocate the destination buffer are if the dimensions or data type do not match:
opencv2\core\mat.hpp line 347 (version 2.4.10), with my comments:
inline void Mat::create(int _rows, int _cols, int _type)
{
_type &= TYPE_MASK;
if( dims <= 2 && rows == _rows && cols == _cols && type() == _type && data )
return; // HIT THIS TO USE EXISTING BUFFER!
int sz[] = {_rows, _cols};
create(2, sz, _type); // realloc!
}
So, just make sure you get the size and data type correct, and the data will end up in the mxArray
buffer instead of somewhere else. If you do it right, copyTo
will use the buffer you specified, calling memcpy
on each row.
'Matlab > mex' 카테고리의 다른 글
Passing Two or More Inputs or Outputs (0) | 2016.09.30 |
---|---|
opencv mat를 matlab mex 데이터로 변환할때는 .t()로 transpose시켜줘야 한다. (0) | 2016.09.29 |
cmake, visual studio로 mex파일 만들때, INSTALL 프로젝트를 빌드해줘야 생성됨 (0) | 2016.09.23 |
generate MEX-files using Visual Studio (0) | 2016.09.22 |
mex "example_mex_function.cpp" compile error (0) | 2016.09.13 |