将数据从cv::Mat转换为mxArray

7

我希望在C++代码中使用"engine.h"将矩阵发送到Matlab。实际情况是,我有一个cv :: Mat内的数据,需要发送一个mxArray。我尝试使用以下表达式,但它不起作用:

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));

任何人都知道正确的转换方式吗?非常感谢您提供的帮助。谢谢。
编辑:
我找到了以下方法: https://dev59.com/gV_Va4cB1Zd3GeqPRDM0#8848711
3个回答

12

有一个由Kota Yamaguchi开发的库,位于http://github.com/kyamagu/mexopencv。这个库包含一个C++类(称为MxArray),它可以在Matlab原生数据类型(mxArray)和OpenCV数据类型之间进行转换。该库直接支持OpenCV的C++ API(Open CV版本2.0及更高版本),因此不需要进行额外的转换(例如从cvMat到cv::Mat或从IplImage到cv::Mat)。示例用法:

#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 
}

就是这样。确保将你的 mex 函数与库中的 MxArray.cpp 文件一起编译;你可以在 MATLAB 命令行中执行此操作:

    mex yourmexfile.cpp MxArray.cpp

源代码对我来说已经足够了,我只想编写自己的函数。非常感谢,确实非常有用。 - Jav_Rock
1
@Jav_Rock 很高兴听到这个消息!MxArray.cpp 对我也非常有帮助。考虑给这个答案点赞,这样其他人也可以看到这个解决方案。 - Alexey

4
这个主题展示了如何将CvMat转换为mxArray。尽管它不完全是你要找的转换代码,但它非常接近。
这是一个简单的转换,你应该能够调整代码使其与cv::Mat一起工作,而不是CvMat。如果你做不到,一个快速的解决办法是将你的cv::Mat数据转换为CvMat,然后像下面代码那样使用(取自我建议的链接):
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;
}

谢谢。使用engine.h和openCV总是很混乱,不是吗?我原本期望有更直接的解决方案,但如果没有更简单的解决方案,我会尝试这个。 - Jav_Rock
1
一个问题。你是否考虑过OpenCV按行存储数据,而Matlab按列存储数据? - Jav_Rock
1
我必须坚持要求您打开我建议的线程,并查看那里提供的完整源代码。根据其他用户的说法,那段代码是有效的。但是如果它不起作用,至少对您来说是一个开始。 - karlphillip

3

经过一番努力,我找到了一个更简单的方法来进行此转换。我的做法是创建一个像这样的函数:

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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接