我想将在Matlab中创建的这样的单元矩阵作为输入参数传递给mex函数,
for i=1:5,
p{i}=rand(3,4);
end
然后将其返回为3维双数组作为输出参数。 预期语法:
Parray = convert(p);
其中Parray是一个3乘4乘5的数值数组而P(:,:,i)= p {i};
我正在使用的以下代码可以成功构建到所需的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与p完全一样,如何在C ++ mex函数中实现?
由于
答案 0 :(得分:2)
在plhs[0]
中你创建了一个3D mxArray,它有一个双精度缓冲区。因此,在buf8 = (double**)mxGetData(plhs[0])
中,mxGetData
会向该缓冲区返回一个void*
,您不能简单地将其转换为double**
并期望得到一组有效指针。顺便说一句,我建议使用static_cast
代替C风格的演员。
答案 1 :(得分: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 :(得分:1)
我用它来在结构中创建一个矩阵字段:一个选项是创建一个临时变量,然后将它的值赋给结构的一个字段:
// 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);