Reading .mat file from C: Can read variable ; but

2019-08-08 19:04发布

问题:

I am trying to use MATLAB-API to read .mat file using C (NOT C++).

This is MATLAB code which would create sort of .mat file I want:

A = [[1 2 3]; [5 7 1]; [3 5 9]];
B = [[2 4];[5 7]];
Creator = 'DKumar';

nFilters = 2;

Filters{1} = [[-1.0 -1.0 -1.0]; [-1.0 8 -1.0]; [-1.0 -1.0 -1.0]];
Filters{2} = 2.0*[[-1.0 -1.0 -1.0]; [-1.0 8 -1.0]; [-1.0 -1.0 -1.0]];

cd('/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File');
save('Test_FILE.mat', 'A', 'B', 'Creator', 'nFilters', 'Filters');

Please notice that I also need to read cell-structure or something similar.

(1) In the C code, it seems that I can read matrix stored in .mat just fine; but, cannot return properly (see the output in the end).

(2) I still have no idea about cell-structure which in this example would STORE DOUBLE MATRICES which may vary in size.

Full-C code follows. First, the function matread, which can seemingly read the data properly.

#include <stdio.h>
#include <stdlib.h>
#include "/usr/local/MATLAB/R2011b/extern/include/mat.h"


struct stDoubleMat{
   double* pValueInField;
   int nRows, nCols;
};

void matread(const char *file, const char *FieldName2Read, struct stDoubleMat oDoubleMat_LOC)
{
    printf("Reading file %s...\n\n", file);

    //Open file to get directory
    MATFile* pmat = matOpen(file, "r");

    if (pmat == NULL) {
      printf("Error opening file %s\n", file);
      return;
    }

    // extract the specified variable
    mxArray *arr = matGetVariable(pmat, FieldName2Read);

    double *pr;
    if (arr != NULL && !mxIsEmpty(arr)) {
        // copy data
        mwSize num = mxGetNumberOfElements(arr);

        pr = mxGetPr(arr);

        if (pr != NULL) {
        oDoubleMat_LOC.pValueInField = pr;
            oDoubleMat_LOC.nRows  = mxGetM(arr);
            oDoubleMat_LOC.nCols  = mxGetN(arr);
        }
    printf("From inside the function \n") ;
        printf( "oDoubleMat_LOC.nRows %i ; oDoubleMat_LOC.nCols %i \n", oDoubleMat_LOC.nRows , oDoubleMat_LOC.nCols);

    }else{
        printf("nothing to read \n") ;
    }

    // cleanup
    mxDestroyArray(arr);
    matClose(pmat);

    return;
}

In the same file, the main function, which seems to be unable to return the read data:

int main(int argc, char **argv)
{
    const char *FileName = "/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat";
    const char *FieldName2Read = "A";

    struct stDoubleMat oDoubleMat; 
    matread(FileName, FieldName2Read, oDoubleMat);
    double* v = oDoubleMat.pValueInField;


    printf("From main \n");
    printf( "oDoubleMat.nRows %i ; oDoubleMat.nCols %i \n", oDoubleMat.nRows , oDoubleMat.nCols);
/*
    for (int i = 0; i < oDoubleMat.nElements; i++)
    {
        std::cout <<" copied value : " << *v << "\n";
        v = v +1;
    }*/

    return 0;
}

Here is the output

$ gcc -o Test Read_MatFile_DKU_2.c -I/usr/local/MATLAB/R2011b/extern/include -L/usr/local/MATLAB/R2011b/bin/glnxa64 -lmat -lmx

$ ./Test 
Reading file /home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat...

From inside the function 
oDoubleMat_LOC.nRows 3 ; oDoubleMat_LOC.nCols 3 
From main 
oDoubleMat.nRows 0 ; oDoubleMat.nCols 0 

Update:

Here is the updated code which read matrix-field just fine. I still have no clue about how to read "cell-structure".

#include <stdio.h>
#include <stdlib.h>
#include "/usr/local/MATLAB/R2011b/extern/include/mat.h"

mxArray *arr;

struct stDoubleMat{
   double* pValueInField;
   int nRows, nCols;
};

void matread(const char *file, const char *FieldName2Read, struct stDoubleMat* poDoubleMat_LOC)
{
    printf("Reading file %s...\n\n", file);

    //Open file to get directory
    MATFile* pmat = matOpen(file, "r");

    if (pmat == NULL) {
      printf("Error opening file %s\n", file);
      return;
    }

    // extract the specified variable
    arr = matGetVariable(pmat, FieldName2Read);

    double *pr;
    if (arr != NULL && !mxIsEmpty(arr)) {
        // copy data
        mwSize num = mxGetNumberOfElements(arr);

        pr = mxGetPr(arr);

        if (pr != NULL) {
        poDoubleMat_LOC->pValueInField = pr;
            poDoubleMat_LOC->nRows  = mxGetM(arr);
            poDoubleMat_LOC->nCols  = mxGetN(arr);
        }
    printf("From inside the function \n") ;
        printf( "oDoubleMat_LOC.nRows %i ; oDoubleMat_LOC.nCols %i \n", poDoubleMat_LOC->nRows , poDoubleMat_LOC->nCols);

    }else{
        printf("nothing to read \n") ;
    }

    // close the file
    matClose(pmat);

    return;
}

int main(int argc, char **argv)
{
    const char *FileName = "/home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat";
    const char *FieldName2Read = "A";

    struct stDoubleMat oDoubleMat; 
    matread(FileName, FieldName2Read, &oDoubleMat);
    double* v = oDoubleMat.pValueInField;


    printf("From main \n");
    printf( "oDoubleMat.nRows %i ; oDoubleMat.nCols %i \n", oDoubleMat.nRows , oDoubleMat.nCols);

    int i;
    for (i = 0; i < oDoubleMat.nCols*oDoubleMat.nRows; i++)
    {
        printf(" copied value : %f \n", *v);
        v = v +1;
    }

    // cleanup the mex-array
    mxDestroyArray(arr);

    return 0;
}

回答1:

You pass the "output" argument (oDoubleMat_LOC) by value to matread, so you can never actually get an output because it is copied on input (i.e. only modified locally):

void matread(const char *file, const char *FieldName2Read, 
    struct stDoubleMat oDoubleMat_LOC) /* oDoubleMat_LOC copied */

Since you are using C, where references are not available, pass a pointer. Redefine matread:

void matread(const char *file, const char *FieldName2Read, 
    struct stDoubleMat *oDoubleMat_LOC) /* use a pointer */

Then inside matread, you need to dereference it to modify its fields (with -> instead of .):

oDoubleMat_LOC->pValueInField = pr;
oDoubleMat_LOC->nRows  = mxGetM(arr);
oDoubleMat_LOC->nCols  = mxGetN(arr);

In main, call like this:

struct stDoubleMat oDoubleMat; 
matread(FileName, FieldName2Read, &oDoubleMat);

However, note that you have bigger problems because the mxArray that is backing double *pValueInField is both allocate and destroyed inside matread. While you can return the pointer to the data array, it will be a dangling pointer, which points to deallocated data. You'll need to either allocate an mxArray outside of matread and pass it in, or allocate a double * and copy the data into it inside matread. Otherwise, as soon as mxDestroyArray is called, the pointer is useless.



标签: c matlab mex