用C++创建二维数组,并在MATLAB中使用

Create 2D array in C++ and use it in MATLAB

本文关键字:MATLAB 并在 C++ 创建 二维数组      更新时间:2023-10-16

有一个标准示例,说明如何在C++中创建或更改数组,并将其用作WarpControlPoints:中的数组

/*==========================================================
 * arrayProduct.c - example in MATLAB External Interfaces
 *
 * Multiplies an input scalar (multiplier) 
 * times a 1xN matrix (inMatrix)
 * and outputs a 1xN matrix (outMatrix)
 *
 * The calling syntax is:
 *
 *      outMatrix = arrayProduct(multiplier, inMatrix)
 *
 * This is a MEX-file for MATLAB.
 * Copyright 2007-2012 The MathWorks, Inc.
 *
 *========================================================*/
/* $Revision: 1.1.10.4 $ */
#include "mex.h"
/* The computational routine */
void arrayProduct(double x, double *y, double *z, mwSize n)
{
    mwSize i;
    /* multiply each element y by x */
    for (i=0; i<n; i++) {
        z[i] = x * y[i];
    }
}
/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[])
{
    double multiplier;              /* input scalar */
    double *inMatrix;               /* 1xN input matrix */
    size_t ncols;                   /* size of matrix */
    double *outMatrix;              /* output matrix */
    /* get the value of the scalar input  */
    multiplier = mxGetScalar(prhs[0]);
    /* create a pointer to the real data in the input matrix  */
    inMatrix = mxGetPr(prhs[1]);
    /* get dimensions of the input matrix */
    ncols = mxGetN(prhs[1]);
    /* create the output matrix */
    plhs[0] = mxCreateDoubleMatrix(1,(mwSize)ncols,mxREAL);
    /* get a pointer to the real data in the output matrix */
    outMatrix = mxGetPr(plhs[0]);
    /* call the computational routine */
    arrayProduct(multiplier,inMatrix,outMatrix,(mwSize)ncols);
}

这基本上就是我想要的,只是我想改变一个2D数组,而不仅仅是一个简单的数组。我试图创建一个2D数组(4 x n),并更改第4行,看看它是否有效。如果我更改以下行:

/* The computational routine */
void arrayProduct(double x, double *y, double *z, mwSize n)
{
mwSize i;
/* multiply each element y by x */
for (i=0; i<n; i++) {
z[3][i] = x * y[i];
}
}

/* create the output matrix */
    plhs[0] = mxCreateDoubleMatrix(4,(mwSize)ncols,mxREAL);

它不起作用。我得到的错误是z既不是字段也不是指针。有人能告诉我我做错了什么吗?我是如何做到的?

多维数组仍然存储为单个连续数组,而不是2D C数组。数据按列主顺序排列,这意味着z[0]是元素(1,1),z[1]是元素(2,1)等,一直到z[4*N-1]

要从所需的2D索引(行、列)(基于0)计算线性索引,只需写入idx = column*nrows + row;。这意味着您需要将nrows值传递到计算函数中。

所以:在计算函数nrows中添加一个额外的参数,并在调用它时传递该值。并将z索引为1D数组,如上所述。

提问者可能已经得到了答案。然而,这个答案可能对像我这样从MATLAB转向C++并希望在C++中使用一些MATLAB功能的人有用。

从C++向MATLAB发送1D数组非常容易,因为有很多在线示例可以向您展示这个过程。但是,将2D数组发送到MATLAB有点棘手,因为没有足够的信息可用(尤其是使用动态数组)。下面的代码中显示了一个过程。这个过程遵循一些简单的步骤,

  1. 用C++创建一个2D数组
  2. 使用engPutVariable_func()(用户定义函数)将该2D数组的每一列发送到MATLAB
  3. 在MATLAB中使用C++中的engEvalString()将每一列附加在一起
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <cmath>
#include <string.h>
#include "engine.h"
#include "mex.h"
#include <armadillo> 
/* I'm using armadillo for convenient matrix operations
 * The process is applicable for other Linear Algebra libraries as well (including STL)
*/
using namespace std;
using namespace arma;
int Create_2DArray_in_Matlab(Engine &m_pEngine, dmat PlotData);
int engPutVariable_func(Engine &m_pEngine, dvec TheVector, string MatVarName);

int main(void)
{
    dmat PlotData(100000, 10, fill::randu);
    /* Our Objective is to Put Matrix "PlotData" in MATLAB workspace*/

    /* Opening Matlab Engine */
    Engine *m_pEngine;
    m_pEngine = engOpen(NULL);
    if (m_pEngine == NULL)
    {
        std::cout << "Error" << std::endl;
        exit(1);
    }
    engSetVisible(m_pEngine, 1);
    engEvalString(m_pEngine, "clc;");
    engEvalString(m_pEngine, "close all;");
    engEvalString(m_pEngine, "clear all;");

    Create_2DArray_in_Matlab(*m_pEngine, PlotData);
    engEvalString(m_pEngine, "open PlotData");
    return 0;
}
int Create_2DArray_in_Matlab(Engine &m_pEngine, dmat PlotData)
{
    /*Approach is to put one column at a time, of a 2D Matrix 
     *in Matlab workspace*/
    int SIZE_Dmat_rows = PlotData.n_rows;
    int SIZE_Dmat_cols = PlotData.n_cols;
    for (int i = 0; i < SIZE_Dmat_cols; i++)
    {
        dvec Temp_Col = PlotData.col(i);
        dvec Col_Number(1); Col_Number(0) = i;
        engPutVariable_func(m_pEngine, Temp_Col, "Temp_Col");
        engPutVariable_func(m_pEngine, Col_Number, "Col_Number");
        engEvalString(&m_pEngine, "PlotData(:, Col_Number + 1) = Temp_Col;");

    }
    return 0;
}

int engPutVariable_func(Engine &m_pEngine, dvec TheVector, string MatVarName)
{
    /*This function will put a column vector in MATLAB Workspace*/
    int SIZE = TheVector.n_rows;
    double *Temp = new double[SIZE];

    for (int i = 0; i < SIZE; i++)
    {
        Temp[i] = TheVector(i);
    }
    char Char_VariableName[1000];
    strcpy(Char_VariableName, MatVarName.c_str());
    /* Creating Matlab Variables*/
    mxArray *TheMatVec = NULL;
    TheMatVec = mxCreateDoubleMatrix(SIZE, 1, mxREAL);
    memcpy((void *)mxGetPr(TheMatVec), (void *)Temp, sizeof(Temp)*SIZE);
    engPutVariable(&m_pEngine, Char_VariableName, TheMatVec);
    delete[] Temp;
    return 0;
}

在一个简单的MATLAB程序中,这就是我们在C++中所做的

clc
clear all
close all
A = rand(10, 20); 
for i = 1:length(A)
    A_Temp = A(:, i);
    B(:, i) = A_Temp
    A_Temp = [];
end

希望这些信息可能有用。。。

如果有任何疑问和批评,请发表评论。

感谢并问候

从根本上讲,二维数组总是需要定义其第一个维度。

将指针(z)视为2d数组打破了这一规则。

如果没有定义第一个维度(实际上,除了最后一个维度之外的所有维度),则无法正确计算指针的实际偏移量。

在您的代码中,因为您知道每个维度的大小是相等的,所以您可以自己计算指针偏移量。