I want to send a Matrix to Matlab using "engine.h" in c++ code. The fact is that I have the data inside a cv::Mat, and I need to sent a mxArray. I tried to use this expression but it doesn´t work:
cv::Mat _priorP;
_priorP = Mat::eye(13, 13, CV_32FC1);
mxArray *mat;
mat = mxCreateDoubleMatrix(13, 13, mxREAL);
memcpy(mxGetPr(mat),_priorP.data, 13*13*sizeof(double));
Anybody knows the correct way to do the conversion? Any help would be apreciated. Thanks.
EDIT
I found this way: https://stackoverflow.com/a/8848711/744859
There is a library developed by Kota Yamaguchi at http://github.com/kyamagu/mexopencv The package contains a C++ class (called MxArray) that converts between Matlab's native data type (mxArray) and OpenCV data types. The library directly supports C++ API for OpenCV (Open CV version 2.0 and higher), so there's no need to do an extra conversions (e.g. from cvMat to cv::Mat or from IplImage to cv::Mat). Sample usage:
#include "mexopencv.hpp" // include the library
#include "highgui.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
cv::Mat image;
image = imread("filename"); // read an image from file
plhs[0] = MxArray(image); // convert from cv::Mat to mxArray
}
That's it. Make sure to compile your mex function together with MxArray.cpp file from the library; you can do so in MATLAB command line:
mex yourmexfile.cpp MxArray.cpp
This thread shows how to convert a CvMat
to mxArray
. Even though it's not exactly the conversion code you are looking for, it's pretty close.
This is a simple conversion and you should be able to adjust the code to work with cv::Mat
instead of CvMat
. If you can't, a quick hack is to convert your cv::Mat
data to CvMat
and then use the code below as is (taken from the link I suggested):
mxArray* CvMat_to_new_mxArr (const CvMat* mat)
{
const int TYPE = cvGetElemType (mat);
// 2-d image
if (CV_64FC1 == TYPE) {
return helper_2dcvmat_to_mat<CV_64FC1> (mat);
}
else if (CV_32FC1 == TYPE) {
return helper_2dcvmat_to_mat<CV_32FC1> (mat);
}
else if (CV_32SC1 == TYPE) {
return helper_2dcvmat_to_mat<CV_32SC1> (mat);
}
else if (CV_16SC1 == TYPE) {
return helper_2dcvmat_to_mat<CV_16SC1> (mat);
}
else if (CV_16UC1 == TYPE) {
return helper_2dcvmat_to_mat<CV_16UC1> (mat);
}
else if (CV_8UC1 == TYPE) {
return helper_2dcvmat_to_mat<CV_8UC1> (mat);
}
else if (CV_8SC1 == TYPE) {
return helper_2dcvmat_to_mat<CV_8SC1> (mat);
}
//Multi-dimensional arrays not supported, yet.
/*
// 3-d image
else if (CV_64FC3 == TYPE) {
return helper_rgbimage_to_mat<IPL_DEPTH_64F> (img);
}
else if (CV_32FC3 == TYPE) {
return helper_rgbimage_to_mat<IPL_DEPTH_32F> (img);
}
else if (CV_8UC3 == TYPE) {
return helper_rgbimage_to_mat<IPL_DEPTH_8U> (img);
}
*/
// unsupported conversion, return null mxArray
return mxCreateDoubleMatrix(0,0,mxREAL);
}
template<int TYPE>
mxArray* helper_2dcvmat_to_mat (const CvMat* mat)
{
void* pBeg;
int pitch;
cvGetRawData(mat, (uchar**)&pBeg,&pitch);
CvSize size = cvGetSize (mat);
const mxClassID cid = cvm_traits<TYPE>::CID;
mxArray* pArrOut =
mxCreateNumericMatrix(size.height,size.width,cid,mxREAL);
void* pBegOut = mxGetData(pArrOut);
typedef mc_traits<cid>::CT T;
pix_iterator_2d<T,eRowWise> it_src1(static_cast<T*>(pBeg),
size.width,size.height,pitch);
pix_iterator_2d<T,eRowWise> it_src2(static_cast<T*>(pBeg),
size.width,size.height,pitch);
it_src2.end ();
pix_iterator_2d<T,eColWise> it_dest(static_cast<T*>(pBegOut),
size.width,size.height);
std::copy (it_src1,it_src2,it_dest);
return pArrOut;
}
I found a simpler method to do this convertion after some effort. What I do is creating a function like this:
void arithmetic::cvLoadMatrixToMatlab( Engine *ep, const Mat& m, string name)
{
int rows=m.rows;
int cols=m.cols;
//Mat data is float, and mxArray uses double, so we need to convert.
mxArray *T=mxCreateDoubleMatrix(cols, rows, mxREAL);
double *buffer=(double*)mxGetPr(T);
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
buffer[i*(cols)+j]= (double)m.at<float>(i, j);
}
}
//memcpy((char*)mxGetPr(T), (char*)m.data, rows*cols*sizeof(double));
engPutVariable(ep, name.c_str(), T);
name=name+"="+name+"'"; // Column major to row major (mat=mat')
engEvalString(ep, name.c_str());
mxDestroyArray(T);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With