【问题标题】:Reading .mat file using C: how to read cell-structure properly使用 C 读取 .mat 文件:如何正确读取单元结构
【发布时间】:2015-04-17 01:58:30
【问题描述】:

我基本上是在尝试将 Matlab 代码翻译成 C 代码。这是我之前question的扩展。

在 Matlab 中,我使用了 cell-structures,其中包含 matrices (double) of variable sizes。这是我的 *.mat 文件的玩具示例supposed to store

Matlab 代码:

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 代码: 函数 "matread_Matrix" reads matrices stored in *.mat properly。是"matread_Cell"函数,应该是读取细胞结构的,是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;
}

输出:

$ 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 

另外,我也无法正确读取该字段:Creator = 'DKumar';

更新:

基于@Sherwin 的建议

我的 C 代码:

#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;
}

输出:

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 :  

问题:1)creator中存储的字符串值显示不正确。

2) 如何删除 cellArray[2])?

【问题讨论】:

  • 如果您在 Matlab 之外读取数据,为什么要以 MAT 格式保存数据?为什么不将数据(在 Matlab 中)导出到 hdf5 并使用现有工具读取 hdf5 二进制数据?
  • 我之前没用过hdf5格式,不知道能不能存储和访问单元格结构。
  • Matlab 以 hdf5 格式保存其 MAT 文件(对于 7.3 及更高版本,AFAIK)。所以,原则上它可以做任何你需要的事情。您必须亲自动手并学习如何与 hdf5 接口,但考虑到您正在经历与 MAT 格式相同(痛苦)的过程这一事实,我认为您最好学习一个更通用的工具( HDF5) 而不是专注于非常受限的 MAT……但这只是我的看法。
  • 查看hdf5 web page 获取帮助和教程
  • 这对我来说可能不是最佳解决方案。我主要在 Matlab 中编写代码,并且有一个任务需要我显着加快数据处理速度。幸运的是,有人已经有一个用 C 代码编写的求解器,他声称它的速度至少快了 10 倍。所以,我需要一些 Matlab 和 C 之间的快速接口来检查他的声明。

标签: c matlab


【解决方案1】:

结果稍作改动,你的代码就可以工作了:

在函数“void matread_Cell”中,将double* p2 = (double*)cellArray[CellIndex];行替换为:

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

我检查过了。它完成了工作。

还要读取创建者字段,与mtread_matrix 类似的代码应该可以工作,只是类型是char* 而不是double*(虽然我没有检查这个。如果没有,请告诉我工作)。

更新:您可以使用以下代码来读取字符串。 (参考: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;
}

main 中你可以像这样使用它:

 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]);
    } 

关于释放 cellArray,我收到错误消息:“未分配指针被释放”,所以我认为您不需要释放它。另一个释放动态内存的有用命令是:void mxFree(void *ptr);

关于mexPrintf 函数,我实际上可以使用它。我只是收到警告implicit declaration of function 'mexPrintf' is invalid in C99 [-Wimplicit-function-declaration],因为我是通过 gcc 而不是 mex 编译的。如果您使用 gcc,您可能需要包含正确的库来识别该功能。您可能会发现 this 很有用,因为它对我有用。

【讨论】:

  • 我根据您的建议更新了我的代码,我可以读取 CellArray,但仍然无法读取字符串。另外,我不知道如何删除 cellArray[2])。另外,我更喜欢使用 mexPrintf。但是,我收到一个错误:未定义对“mexPrintf”的引用。有什么猜测吗??
猜你喜欢
  • 2021-02-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-02
  • 2014-07-31
  • 2015-06-30
  • 1970-01-01
  • 1970-01-01
  • 2018-07-04
相关资源
最近更新 更多