首页 文章

如何在C mex函数中传递Matlab m x n单元矩阵参数?

提问于
浏览
4

我想将在Matlab中创建的这样的单元矩阵作为输入参数传递给mex函数,

for i=1:5,
    p{i}=rand(3,4);
end

然后将其作为3维双数组作为输出参数返回 . 预期语法:

Parray = convert(p);

其中Parray是一个3乘4乘5的数值数组而P(:,:,i)= p ;

我正在使用的以下代码可以成功构建到所需的mex函数中:

#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <matrix.h>
#include <cstring>
#include <string>
#include "mex.h"


using namespace std;

void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] )
{

if (nlhs>=1 && nrhs>=1){
        int       nsubs =2,  index;
        mwIndex   subs[]={0, 0};
        mxArray   *tmp;
        double     **buf;

        int cameraNum = mxGetNumberOfElements(prhs[0]);
        mwIndex  dims[]={cameraNum,3,4};
        plhs[0] = mxCreateNumericArray(3,dims,mxDOUBLE_CLASS,mxREAL);
        mexPrintf("there are %d cameras in the input cell.",cameraNum);

        /* allocate memory  for storing pointers */

        buf = (double**)mxGetData(plhs[0]);

        for (int i=0; i<cameraNum; i++){
            subs8[1] = i;

            // get the cell (i,1)
            index = mxCalcSingleSubscript(prhs[1], nsubs, subs);
            tmp = mxGetCell(prhs[0],index);

            buf[i] = (double*)mxGetData(tmp); 
            int rownum = mxGetM(tmp);
            int colnum = mxGetN(tmp);
            mexPrintf("\n No. %d camera matrix is: \n",i);
            for(int m=0;m<rownum;m++){
                for(int n=0; n<colnum;n++){
                    mexPrintf("%lf\t",buf[i][m*colnum+n]);
                }
            }

        }
        mxFree(buf);
    }

    return;
}

然而,由于未知原因,它导致Matlab崩溃 . 是什么原因?我怎样才能摆脱这个问题呢?

此外,如果所需的语法是:

Parray = convert(p);

和Parray完全一样,如何在C mex函数中实现?

谢谢

3 回答

  • 1

    plhs[0] 中,您创建了一个3D mxArray,它有一个双精度缓冲区 . 所以在 buf8 = (double**)mxGetData(plhs[0]) 中, mxGetDatavoid* 返回到该缓冲区,您不能简单地将其转换为 double** 并期望得到一组有效指针 . 顺便说一句,我建议使用 static_cast 代替C风格的演员 .

  • 1

    我终于通过一个评论的例子来实现它 . 我在这里发布了示例实现代码,以供任何感兴趣的其他人参考 .

    /*==========================================================
    * testmex01.cpp - example in MATLAB External Interfaces
    *
    * Illustrates how to use some C++ language features in a MEX-file.
    *
    * This is a MEX-file for MATLAB.
    * no Copyright; 2013 The LC Factorization, Inc.
    *
    *========================================================*/
    /* $Revision: 0.0 $ */
    
    #include <iostream>
    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    #include "mex.h"
    #include <matrix.h>
    //
    #include <Eigen/Dense>
    #include "Eigen/Eigen"
    #include "Eigen/LU"
    #include "Eigen/SVD"
    //
    using namespace Eigen;
    using namespace std;
    #include "mpir.h"
    #include "mpreal.h"
    
    #include <cstring>
    #include <string>
    
    using namespace mpfr;
    //using namespace std;
    
    //extern void _main();
    //
    ///****************************/
    //class MyData {
    //
    //public:
    //  void display();
    //  void set_data(double v1, double v2);
    //  MyData(double v1 = 0, double v2 = 0);
    //  ~MyData() { }
    //private:
    //  double val1, val2;
    //};
    //
    //MyData::MyData(double v1, double v2)
    //{
    //  val1 = v1;
    //  val2 = v2;
    //}
    //
    //void MyData::display()
    //{
    //#ifdef _WIN32
    //  mexPrintf("Value1 = %g\n", val1);
    //  mexPrintf("Value2 = %g\n\n", val2);
    //#else
    //  cout << "Value1 = " << val1 << "\n";
    //  cout << "Value2 = " << val2 << "\n\n";
    //#endif
    //}
    //
    //void MyData::set_data(double v1, double v2) { val1 = v1; val2 = v2; }
    //
    ///*********************/
    //
    //static
    ////void
    //double mexcpp(
    //      double num1,
    //      double num2
    //      )
    //{
    //#ifdef _WIN32
    //  mexPrintf("\nThe initialized data in object:\n");
    //#else
    //  cout << "\nThe initialized data in object:\n";
    //#endif
    //  MyData *d = new MyData; // Create a  MyData object
    //  d->display();           // It should be initialized to
    //                          // zeros
    //  d->set_data(num1,num2); // Set data members to incoming
    //                          // values
    //#ifdef _WIN32
    //  mexPrintf("After setting the object's data to your input:\n");
    //#else
    //  cout << "After setting the object's data to your input:\n";
    //#endif
    //  d->display();           // Make sure the set_data() worked
    //  delete(d);
    //  flush(cout);
    //  return num1+num2;
    //}
    
    ////////////// how to handle structure
    struct mystruct
    {
    char   *a;
    double *b;
    double *c;
    double *d;
    };
    
    void printme( char *a, double *b, double *c, double *d )
    {
        mexPrintf(a);
        mexPrintf( "\n a = %s,\tb = %f,\tc = %f,\td = %f\n", a, b[0], c[0], d[0] );
        mexPrintf( "a = %s,\tb = %f,\tc = %f,\td = %f\n", a, b[99], c[99], d[99] );
    }
    /////////////  how to handle structure
    
    
    void mexFunction(
        int          nlhs,
        mxArray      *plhs[],
        int          nrhs,
        const mxArray *prhs[]
    )
    {
        //double      *vin1, *vin2;
    
        /* Check for proper number of arguments */
    
        //if (nrhs != 2) {
        //  mexErrMsgIdAndTxt("MATLAB:mexcpp:nargin", 
        //          "MEXCPP requires two input arguments.");
        //} else if (nlhs >= 1) {
        //  mexErrMsgIdAndTxt("MATLAB:mexcpp:nargout",
        //          "MEXCPP requires no output argument.");
        //}
    
        //vin1 =  mxGetPr(prhs[0]);//(double *) mxGetPr(prhs[0]);
        //vin2 = mxGetPr(prhs[1]); //(double *) mxGetPr(prhs[1]);
    
    
        ////////////// Here are the multiple precision settings
    
        const int digits = 256;
        // Setup default precision for all subsequent computations
        // MPFR accepts precision in bits - so we do the conversion 
        mpreal::set_default_prec(mpfr::digits2bits(digits));
        const mpreal pi          =    mpfr::const_pi();
    
        const int n = 5;
    
        typedef Matrix<mpreal,Dynamic,Dynamic>  MatrixXmp;
        typedef Matrix<mpreal,Dynamic,1>        VectorXmp;
    
        MatrixXmp A = MatrixXmp::Random(n,n);
        VectorXmp b = VectorXmp::Random(n);
        VectorXmp x =  A.lu().solve(b);
        VectorXmp residue0 = A *x -b;//.norm();
        mpreal residue = residue0.norm();
    
    
        if(nlhs>=1){
    
            const char *fieldnames[] = {"a", "b" , "c" , "d"};
            int T = 100;
            struct mystruct X;
            plhs[0] = mxCreateStructMatrix(1 , 1 , 4 , fieldnames);
    
            string str2= pi.toString();// first struct field is char Pi
            mxSetFieldByNumber(plhs[0] ,0 , 0 , mxCreateString(str2.c_str()));
    
            for(int i = 1 ; i < 4 ; i++){
                mxArray *data = mxCreateNumericMatrix(T, 1 , mxDOUBLE_CLASS,mxREAL);
    
                for(int j = 0; j < T; j++ ) {
                    *(mxGetPr(data) + j) = (i * T) + j;
                }
                mxSetFieldByNumber(plhs[0] ,0 , i , data);
            }
    
            int strlenn= mxGetN(mxGetFieldByNumber( plhs[0], 0, 0 ))+1;
            //char tempchar[digits+2]; // Here the digits can be any positive integer
            X.a = (char*)mxCalloc(strlenn,sizeof(char));//tempchar;
            // Allocate enough memory to hold the converted string
            printf("\n X.a before being allocated a string is %s ; size of X.a is %d \n",X.a,sizeof(X.a));
            //_strdup(pi.toString().c_str()); //mxCalloc(n,sizeof(char)) cannot be used here..
            mxGetString(mxGetFieldByNumber( plhs[0], 0, 0 ),X.a ,strlenn);//strlen(X.a) //sizeof(X.a)// here the 3rd input argument can be any integer?
            printf("The strlen of X.a is %d, size of X.a is %d, mxGetN+1 is %d , sizeof char is %d \n",strlen(X.a),sizeof(X.a),strlenn,sizeof(char));
            //mxGetString( mxGetFieldByNumber( plhs[0], 0, 0 ), X.a, sizeof(X.a));//strlen(X.a)*sizeof(mxChar)+1);//strlen()
            X.b = mxGetPr( mxGetFieldByNumber( plhs[0], 0, 1 ) );
            X.c = mxGetPr( mxGetFieldByNumber( plhs[0], 0, 2 ) );
            X.d = mxGetPr( mxGetFieldByNumber( plhs[0], 0, 3 ) );
    
             printme(X.a, X.b, X.c, X.d);
             //mxFree(X);
        }
    
    
        //second output argument is matrix: A, which can be double or char*
        // double type output
        if (nlhs>=2&&nrhs<1){
            double *two2three;
            plhs[1]= mxCreateDoubleMatrix(n,n, mxREAL);//mxCreateCellMatrix(n,n);
            two2three= mxGetPr(plhs[1]);//mxGetCell(plhs[1],);
            for (int i=0;i<n;i++)
                for(int j=0; j<n; j++){
                    two2three[i+j*n]=A(i, j).toDouble();
                }
        }
    
        if (nlhs>=2 && nrhs>=1){ // try to output A as cell matrix
    
            mwSize ndims[] ={5,5} ;
            int nsubs=2;
            mwIndex subs[2];
            plhs[1]= mxCreateCellArray(2, ndims);//create a 2D array with 5x5 dimensions
            //mxSetName(plhs[1], "amoeba");
    
            for (int i=0;i<n;i++)
                for(int j=0; j<n; j++){
                    subs[0]=i;subs[1]=j;
                    int index = mxCalcSingleSubscript(plhs[1], nsubs, subs); // nsubs 
                    mxSetCell(plhs[1],index,mxCreateString(_strdup(A(i, j).toString().c_str())));//two2three[i+j*n]=A(i, j).toDouble();
                }
        }
    
        //The 3rd argument is b vecoter, with double and char* options,
        if (nlhs>=3 && nrhs<1){ 
            double  *three2two;
            plhs[2]= mxCreateDoubleMatrix(n,1, mxREAL);//mxCreateCellMatrix(n,n);
            three2two = mxGetPr(plhs[2]);//mxGetCell(plhs[1],);
            for (int i=0;i<n;i++)
                three2two[i]=b(i).toDouble();
        }
    
        if (nlhs>=3&&nrhs>=1){//try to set output b as cell vector
            plhs[2]=mxCreateCellMatrix(n, 1);
            for (int i = 0; i < n; i++) {
                mxSetCell(plhs[2],i,mxCreateString(_strdup(b(i).toString().c_str())));
            }
        }
    
        //with double and char* options for testing double/char matrix argument type
        if (nlhs>=4&& nrhs<1){// x as double
            double  *solution;
            plhs[3]= mxCreateDoubleMatrix(n,1, mxREAL);//mxCreateCellMatrix(n,n);
            solution = mxGetPr(plhs[3]);//mxGetCell(plhs[1],);
            for (int i=0;i<n;i++)
                solution[i]= x(i).toDouble();
        }
    
        // the 4th cell/string char* matrix argument
        if (nlhs>=4 && nrhs>=1){//try to set output x as cell vector
            //memory allocation
            plhs[3]=mxCreateCellMatrix(n, 1);
            for (int i = 0; i < n; i++) {//format for output
                mxSetCell(plhs[3],i,mxCreateString(_strdup(x(i).toString().c_str())));
            }
        }
    
        // Euclidean norm of residue vector in mpreal, by char* output
        if (nlhs>=5)
            plhs[4] = mxCreateString(residue.toString().c_str());
    
        //the 6th residue vector; in Char* matrix/vector , as mpreal multiple precision
        if (nlhs>=6){
            //always allocate memory first
            plhs[5]=mxCreateCellMatrix(n, 1);
    
            //int m = digits + 60;       
            ///* Stuff the input into a string buffer. */
            //std::string strbuf;
    
            //char **line;
            ///* Create line buffers for the individual vector elements. */
            //for (int i=0; i<n;i++){
            //  line[i] =(char *) mxCalloc(m,sizeof(char));  //char * writable = new char[str.size() + 1];
            //  strbuf = residue0(i).toString();;
            //  std::copy(strbuf.begin(), strbuf.end(), line[i]);
            //  line[i][strbuf.size()] = '\0';
            //  mxSetCell(plhs[5],i,mxCreateString(line[i]));
            //  mxFree(line[i]);
            //}
    
            for (int i = 0; i < n; i++) {
                //note the conversion method here:
                mxSetCell(plhs[5],i,mxCreateString(_strdup(residue0(i).toString().c_str())));
                //Other methods of converting string into const char* or char*
                // residue0(i).toString().data();// const char*
            }
            //plhs[5] = mxCreateString(residue0(n-1).toString().c_str());//array;
        }
    
        //test data type conversion from mpreal to double, excellent result;
        if (nlhs>=7&&nrhs>=1){
            double *xconversion = (double *) mxGetPr(prhs[0]);// (double *)mxGetData(prhs[0]);
    
            mpreal yconversion =xconversion[0];
    
            mexPrintf("\n The input argument in double is %lf \n                mpreal double is %lf string is %s; ",xconversion[0],yconversion.toDouble(),yconversion.toString().c_str());
            plhs[6] = mxCreateString(yconversion.toString().c_str());
        }
    
        //第八个输出参数是3维的数字矩阵;把包含相机的Cell向量中的相机取出,放到数字型三维矩阵并输出
        if (nlhs>=8&&nrhs>=2){
            if (!mxIsCell(prhs[1])){
                //mexErrMsgTxt(" 2nd input argument must be cell matrix.");
                mexPrintf("\n 2nd input argument must be cell matrix.\n");
            }
    
            mwIndex   subs8[] ={0}; // first 
            mxArray   *strtmp;//*cell_element_ptr;
    
            int cameraNum = mxGetNumberOfElements(prhs[1]);
            // multidimensional array output "3 x 4 x nViews"
            mwIndex  dims[]={3,4,cameraNum};//for output double{ 3, 4, cameraNum} array
    
            plhs[7] = mxCreateNumericArray(3,dims,mxDOUBLE_CLASS,mxREAL);
    
            //初始化mpreal类型的矩阵和临时变量
            MatrixXmp eigenM(3,4);
            mpreal tempdbl;
    
            //逐个把第2个输入参数的double矩阵里的元素,赋值给输出参数的数字型矩阵
            for (int i=0;i<cameraNum;i++){
                *subs8 = i;
                //把右侧Cell输入向量的第i个矩阵元素取出到mxArray* 临时变量;
                strtmp = mxGetCell(prhs[1],mxCalcSingleSubscript(prhs[1], 1, subs8));
                int nrows = mxGetM(strtmp); //实际已经知道是 3x4
                int ncols = mxGetN(strtmp);
    
                //逐个矩阵(页面i)显示矩阵
                mexPrintf("\n No. %d camera matrix is: \n",i+1);
    
                for (int m=0; m<3;m++){
                    for(int n=0;n<4;n++){
                        tempdbl = ((double*)mxGetPr(strtmp))[m+n*nrows];
                        //逐个元素取出的方式是指针操作; 序数的计算方法值得注意
                        ((double*)mxGetPr(plhs[7]))[i*nrows*ncols+m+n*nrows]= tempdbl.toDouble();
    
                        if(i==cameraNum-1)
                            eigenM(m,n) = tempdbl;
    
                        mexPrintf("%lf\t",((double*)mxGetPr(strtmp))[m+n*nrows]);//Note the difference between them
                    }
                    mexPrintf("\n");
                }
            }
            // 显示mpreal格式的最后一个3x4矩阵的逐列
            mexPrintf("\n");
            for (int i=0;i<4;i++){
                mexPrintf("\n Column No. %d :\n",i+1);
                for (int j=0; j<3;j++){
                    mexPrintf(" %s \n",eigenM(j,i).toString().c_str());
                }
            }
            //最末一个双精度元素转化为字符串,然后字符,再显示(精度不能设置)mpreal更好
            std::ostringstream strss;
            strss  << ((double*)mxGetPr(strtmp))[2+3*3];
            std::string strnum = strss.str();
    
            mpreal mprrealnum=((double*)mxGetPr(strtmp))[2+3*3];
    
            char *charnum =new char[strnum.size()+1];
            charnum[strnum.size()]=0;
            memcpy(charnum,strnum.c_str(),strnum.size());
    
            mexPrintf("\n The converted double string is %s with size %d \n",charnum,strnum.size());
            mexPrintf(" The mpreal based conversion is %s \n",mprrealnum.toString().c_str());
    
    
            //if (mxIsCell(strtmp)){
            //  mexPrintf("\n strtmp is cell \n");
            //}
            //else{
            //  mexPrintf("\n strtmp is NOT cell \n");
            //}
    
            //if (mxIsDouble(strtmp)){
            //  mexPrintf("\n strtmp is double \n");
            //}
            //else{
            //  mexPrintf("\n strtmp is NOT double \n");
            //}
    
            //mexPrintf("The mxGetM of prhs[1] is %d, mxGetN is %d \n",mxGetM(prhs[1]),mxGetN(prhs[1]));
            //mexPrintf("\n There are %d cameras in the input cell.\n",cameraNum);
    
            //buf = mxArrayToString(strtmp);
            //mexPrintf("The converted string is %s\n",buf);
    
    
            //  mexPrintf("\n No. %d camera matrix is: \n",i);
            //  for(int m=0;m<rownum;m++){
            //      for(int n=0; n<colnum;n++){
            //          mexPrintf("%lf\t",buf8[i][m*colnum+n]);
            //      }
            //  }
    
            //}
            //mxFree(buf8);
        }
    
        return;
    }
    
  • 2

    我用它在结构中创建一个矩阵字段:一个选项是创建一个临时变量,然后将它的值赋给结构的一个字段:

    // Create temp variable
    mxArray* array = convertVectorToMxArray(mat, nb_rows, nb_cols);  
    const std::string temp_name = array_name + "_temp";
    int ret = engPutVariable(ep, temp_name.c_str(), array);
    
    // Set variable to struct field
    const std::string cmd = std::string(array_name + " = " + temp_name + "; ");
    matlabExecute(ep, cmd);
    
    // Delete array
    mxDestroyArray(array);
    

相关问题