how to transfer data from MATLAB to c++ using MEX
17 visualizaciones (últimos 30 días)
Mostrar comentarios más antiguos
amin sari
el 24 de Oct. de 2018
Comentada: James Tursa
el 25 de Oct. de 2018
I use following code to transfer data from c++ to matlab:
void function(vector<vector<double>> mat)
{
size_t rows = mat.size();
size_t cols = mat[0].size();
mxArray* T = mxCreateDoubleMatrix(rows, cols, mxREAL);
double * in_buf = (double *)mxGetPr(T);
for (int i = 0; i<rows; i++)
{
std::memcpy(in_buf + i * cols, &mat[i][0], cols *sizeof(double));
}
}
and pass the mat into matlab function say pca(T)
then
engEvalString(ep, "[coeff , latent] = pca(T);");
my question is how to get the data calculated above and store them in different vectors:
mxArray* coef = engGetVariable(ep, " coeff' ");
mxArray* latent = engGetVariable(ep, " latent' ");
vector<double> latents(rows);
vector<vector<double>> coeff(rows, vector<double>(cols));
memcpy((void *)latents,(void *)mxGetPr(latent), rows *sizeof(double));
memcpy((void *)latents,(void *)mxGetPr(coef), rows *sizeof(double));
I used std::memcpy to do this but it doesn't work ?
Any help will be greatly appreciated.
Regards
0 comentarios
Respuesta aceptada
James Tursa
el 24 de Oct. de 2018
Editada: James Tursa
el 24 de Oct. de 2018
Here is some example code for you. It is written as a mex routine but you should be able to adapt the functions to your Engine application. Pay special attention to the fact that due to the different matrix memory ordering (C++ is row based and MATLAB is column based) the conversions are done as transposes in both directions. (Different code could of course be written to transform the memory ordering of the elements so that the sizes remain the same ... but that would entail an element-by-element copy instead of entire row/column at once.)
/* Example code for converting between C++ vector<vector<double>> and mxArray
*
* Because C++ memory is row ordered and MATLAB mxArray memory is column
* ordered, the conversion is done in both directions as the transpose so
* that the memory copies are done as entire rows/colums.
*
* Programmer: James Tursa
*/
/* Includes ----------------------------------------------------------- */
#include "mex.h"
#include <vector>
using namespace std;
// Convert a C++ matrix to an mxArray as the TRANSPOSE
mxArray *vv2mx(vector<vector<double>> mat)
{
size_t rows = mat.size();
size_t cols = mat[0].size();
mxArray *T = mxCreateDoubleMatrix(cols, rows, mxREAL);
double *in_buf = (double *) mxGetData(T);
for (int i = 0; i<rows; i++) {
memcpy( in_buf + i * cols, &mat[i][0], cols *sizeof(double) );
}
return T;
}
// Convert an mxArray to a C++ matrix as the TRANSPOSE
vector<vector<double>> mx2vv(const mxArray *T) {
size_t rows = mxGetN(T);
size_t cols = mxGetM(T);
double *in_buf = (double *) mxGetData(T);
vector<vector<double>> mat(rows, vector<double>(cols));
for (int i = 0; i<rows; i++) {
memcpy( &mat[i][0], in_buf + i * cols, cols *sizeof(double) );
}
return mat;
}
// Display a C++ matrix
void vvdisp(vector<vector<double>> mat)
{
size_t rows = mat.size();
size_t cols = mat[0].size();
for (int i = 0; i<rows; i++) {
for( int j=0; j<cols; j++ ) {
mexPrintf("%f ",mat[i][j]);
}
mexPrintf("\n");
}
return;
}
// Display an mxArray
void mxdisp(const mxArray *T)
{
size_t rows = mxGetM(T);
size_t cols = mxGetN(T);
double *in_buf = (double *) mxGetData(T);
for (int i = 0; i<rows; i++) {
for( int j=0; j<cols; j++ ) {
mexPrintf("%f ",*(in_buf + i + j*rows));
}
mexPrintf("\n");
}
return;
}
/* Gateway ------------------------------------------------------------ */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if( nrhs == 0 || !mxIsDouble(prhs[0]) || mxIsSparse(prhs[0]) || mxIsComplex(prhs[0]) ) {
mexErrMsgTxt("Need exactly one full double matrix input");
}
if( nlhs > 1 ) {
mexErrMsgTxt("Too many outputs.");
}
mexPrintf("\nInput matrix:\n");
mxdisp(prhs[0]);
mexPrintf("\nInput matrix as vv:\n");
vector<vector<double>> mat = mx2vv(prhs[0]);
vvdisp(mat);
mexPrintf("\n2*vv:\n");
size_t rows = mat.size();
size_t cols = mat[0].size();
for (int i = 0; i<rows; i++) {
for( int j=0; j<cols; j++ ) {
mat[i][j] *= 2.0;
}
}
vvdisp(mat);
mexPrintf("\nOutput matrix:\n");
plhs[0] = vv2mx(mat);
mxdisp(plhs[0]);
}
And a sample run:
>> mex vectorvector.cpp
Building with 'Microsoft Visual C++ 2013'.
MEX completed successfully.
>> x = reshape(1:6,2,3)
x =
1 3 5
2 4 6
>> vectorvector(x)
Input matrix:
1.000000 3.000000 5.000000
2.000000 4.000000 6.000000
Input matrix as vv:
1.000000 2.000000
3.000000 4.000000
5.000000 6.000000
2*vv:
2.000000 4.000000
6.000000 8.000000
10.000000 12.000000
Output matrix:
2.000000 6.000000 10.000000
4.000000 8.000000 12.000000
ans =
2 6 10
4 8 12
3 comentarios
James Tursa
el 25 de Oct. de 2018
So, I hesitate to respond to this because my answer would greatly depend on what you are doing and where the initial memory originates from. My personal preference is to always avoid data copies whenever possible, even if I have to stray outside official MATLAB API functions. I would never want to copy a 1GB array if I didn't have to.
So, if you start with a MATLAB mxArray, then I would simply grab the data pointer and do my own manual matrix indexing inside the C++ code in order to avoid a data copy. That direction is fairly straightforward and doesn't involve any non-standard coding. If this is a mex routine then it is pretty easy to set up data sharing this way.
But if you start with native C++ memory (e.g. a vector<double>) and want to use it as an mxArray without a data copy, then you would need to stray outside the offical MATLAB API functions in order to construct an mxArray that shares this data memory. The solution for this will look very different from the solution to the previous paragraph, but it can be done with some mxArray hacks.
Finally, I will point out that the standard MATLAB Engine requires that data is copied between your C++ code and the MATLAB process. Here again, you would have to stray outside of official MATLAB API functions in order to have your program share this data memory with MATLAB. And the solution for this will look very different from the previous paragraphs.
In summary, there is probably a way to do what you want without huge data copies, but the solution can be anywhere from easy to very involved depending on your particular circumstances.
Más respuestas (0)
Ver también
Categorías
Más información sobre Call C++ from MATLAB en Help Center y File Exchange.
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!