Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reading .mat file using C: how to read cell-structure properly

Tags:

c

matlab

I am basically attempting to translate Matlab code in C code. This is the extension of my previous question.

In Matlab, I have used cell-structures which holds matrices (double) of variable sizes. Here is a toy example of what my *.mat file is supposed to store:

Matlab Code:

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 8]; [-1.0 -1.0]];

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

C-code: The function "matread_Matrix" reads matrices stored in *.mat properly. It's the function "matread_Cell", which is supposed to read cell-structure, is not working.

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

mxArray *arr;
mxArray *C_CELL;
/* declare  a 2 x 1 array of pointers to access the cell array in C */
mxArray *cellArray[2];

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

void matread_Matrix(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("matread_Matrix \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;
}

void matread_Cell(const char *file, const char *FieldName2Read, int CellIndex)
{
    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
    C_CELL = matGetVariable(pmat, FieldName2Read);
    cellArray[CellIndex] = mxGetCell(C_CELL, CellIndex);

    double* p2 = (double*)cellArray[CellIndex];
    int nRows  = mxGetM(cellArray[CellIndex]);
    int nCols  = mxGetN(cellArray[CellIndex]);

    printf(" From inside matread_Cell : nRows %i and nCols %i \n", nRows, nCols);

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

    // close the file
    matClose(pmat);
}


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_Matrix(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;
    }

    // Reading the structure
    const char *FieldName2Read2 = "Filters";
    matread_Cell(FileName, FieldName2Read2, 0);
    matread_Cell(FileName, FieldName2Read2, 1);


    // cleanup the mex-array
    mxDestroyArray(arr);
    mxDestroyArray(C_CELL);
    /* How to delete mxArray of pointer : should this be a array of pointers */
    //mxDestroyArray(cellArray[0]);
    //mxDestroyArray(cellArray[1]);

    return 0;
}

Output:

$ gcc -g -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...

matread_Matrix 
oDoubleMat_LOC.nRows 3 ; oDoubleMat_LOC.nCols 3 
From main 
oDoubleMat.nRows 3 ; oDoubleMat.nCols 3 
 copied value : 1.000000 
 copied value : 5.000000 
 copied value : 3.000000 
 copied value : 2.000000 
 copied value : 7.000000 
 copied value : 5.000000 
 copied value : 3.000000 
 copied value : 1.000000 
 copied value : 9.000000 
Reading file /home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat...

 From inside matread_Cell : nRows 3 and nCols 3 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
Reading file /home/dkumar/CPP_ExampleCodes_DKU/Read_mat_File/Test_FILE.mat...

 From inside matread_Cell : nRows 3 and nCols 2 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 
 copied value : 0.000000 

Also, I could not read this field properly as well: Creator = 'DKumar';

UPDATE:

Based on suggestion of @Sherwin

My C-code:

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

mxArray *arr;
mxArray *C_CELL;
/* declare  a 2 x 1 array of pointers to access the cell array in C */
mxArray *cellArray[2];

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


void matread_Matrix(MATFile* pmat , const char *FieldName2Read, struct stDoubleMat* poDoubleMat_LOC)
{
    // 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("matread_Matrix \n") ;
        printf( "oDoubleMat_LOC.nRows %i ; oDoubleMat_LOC.nCols %i \n", poDoubleMat_LOC->nRows , poDoubleMat_LOC->nCols);

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

void matread_String(MATFile* pmat , const char *FieldName2Read)
{
    // 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) {
            char *p2 = (char*) pr; 

            // Printing and checking
        int i2;
        for (i2 = 0; i2 < num; i2++)
        {
        printf(" copied value : %s \n", p2);
        p2 = p2 +1;
        }

    }

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

void matread_Cell(MATFile* pmat , const char *FieldName2Read, int CellIndex)
{

    // extract the specified variable
    C_CELL = matGetVariable(pmat, FieldName2Read);
    cellArray[CellIndex] = mxGetCell(C_CELL, CellIndex);

    double *p2 = (double*) mxGetPr(cellArray[CellIndex]); 
    int nRows  = mxGetM(cellArray[CellIndex]);
    int nCols  = mxGetN(cellArray[CellIndex]);

    printf(" From inside matread_Cell : nRows %i and nCols %i \n", nRows, nCols);

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


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

    //Open file to get directory
    printf("Reading file %s...\n\n", FileName);
    MATFile* pmat = matOpen(FileName, "r");

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

    struct stDoubleMat oDoubleMat; 
    matread_Matrix(pmat, FieldName2Read, &oDoubleMat);
    double* v = oDoubleMat.pValueInField;

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

    // Reading the structure
    const char *FieldName2Read2 = "Filters";
    matread_Cell(pmat, FieldName2Read2, 0);
    matread_Cell(pmat, FieldName2Read2, 1);

    // Reading the string
    const char *FieldName2Read3 = "Creator";
    matread_String(pmat, FieldName2Read3);

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

    /* How to delete mxArray of pointer : should this be a array of pointers */
    //mxDestroyArray(cellArray[0]);
    //mxDestroyArray(cellArray[1]);


    // close the file
    matClose(pmat);

    return 0;
}

Output:

oDoubleMat.nRows 3 ; oDoubleMat.nCols 3 
 copied value : 1.000000 
 copied value : 5.000000 
 copied value : 3.000000 
 copied value : 2.000000 
 copied value : 7.000000 
 copied value : 5.000000 
 copied value : 3.000000 
 copied value : 1.000000 
 copied value : 9.000000 
 From inside matread_Cell : nRows 3 and nCols 3 
 copied value : -1.000000 
 copied value : -1.000000 
 copied value : -1.000000 
 copied value : -1.000000 
 copied value : 8.000000 
 copied value : -1.000000 
 copied value : -1.000000 
 copied value : -1.000000 
 copied value : -1.000000 
 From inside matread_Cell : nRows 3 and nCols 2 
 copied value : -2.000000 
 copied value : -2.000000 
 copied value : -2.000000 
 copied value : -2.000000 
 copied value : 16.000000 
 copied value : -2.000000 
 copied value : D 
 copied value :  
 copied value : K 
 copied value :  
 copied value : u 
 copied value :  
 copied value :  

Problem: 1) String value stored in creator is not properly displayed.

2) How to delete cellArray[2])?

like image 603
Garima Singh Avatar asked Apr 12 '15 22:04

Garima Singh


People also ask

How do I read a .MAT file?

How to Open an MAT File. MAT files that are Microsoft Access Shortcut files can be created by dragging a table out of Access and to the desktop or into another folder. Microsoft Access needs to be installed in order to use them. MATLAB from MathWorks can open MAT files that are used by that program.

What is the structure of a .MAT file?

In MATLAB Version 5, a MAT-file is made up of a 128-byte header followed by one or more data elements. Each data element is composed of an 8-byte tag followed by the data in the element.

Are .MAT files HDF5?

Version 7.3 MAT-files use an HDF5-based format that stores data in compressed chunks.

How do I extract a .MAT file in MATLAB?

Direct link to this answer s = load(fullMatFileName); % Extract the table.


1 Answers

It turns out with a slight change, your code works:

In the function "void matread_Cell" replace the line double* p2 = (double*)cellArray[CellIndex]; with:

p2 = (double*) mxGetPr(cellArray[CellIndex]); 

I checked it out. It does the work.

Also to read the creator field, a similar code to mtread_matrix should work, just the type is char* instead of double* (I didn't check this one though. let me know if it doesn't work).

update: you can use the following code to read strings. (Reference: here)

void matread_string(const char *file, const char *FieldName2Read, char *pr, mwSize *len)
{
    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);

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

        //int mxGetString(const mxArray *pm, char *str, mwSize strlen);
        int res= mxGetString(arr, pr, num+1); //strlen should be len+1. c.f. reference.
        if(res==0)
            printf("success!\n");
        else
            printf("failed.\n");


        if ( pr == NULL){
            printf("null pointer.\n");
        }   
        printf("matread_string \n") ;
        printf( "len: %i \n", (int)num);

        *len=num; 

    }else{
        printf("nothing to read \n") ;
    }
    // close the file
    matClose(pmat);

    return;
}

In the main you can use it like:

 const char *FieldName2Read3 = "Creator";
    char pr[20];
    mwSize len;
    matread_string(FileName, FieldName2Read3, pr, &len);

    //int i;
    printf(" copied value: %s \n",pr);
    for (i = 0; (mwSize) i <  len; i++)
    {
        printf(" copied value : %c \n", pr[i]);
    } 

Regarding deallocating cellArray, I get the error: "pointer being freed was not allocated", so I don't think you need to free that. Another useful command for freeing dynamic memory is : void mxFree(void *ptr);

Regarding the mexPrintf function I am actually able to use it. I just get a warning implicit declaration of function 'mexPrintf' is invalid in C99 [-Wimplicit-function-declaration], since I am compiling via gcc rather than mex. If you are using gcc, you probably need to include the proper libraries to recognize that function. You might find this useful, as it worked for me.

like image 191
Shervin Avatar answered Oct 27 '22 23:10

Shervin