将MATLAB中的.mat文件转换为OpenCV中的cv::Mat矩阵

10
我有一些MATLAB的代码,想要迁移到OpenCV上。MATLAB代码使用的数据存储在.mat文件中,然后在运行时加载。
我将这个.mat文件转换成了.csv文件,并使用ifstream将这个数据作为字符串读入OpenCV。但是我无法将此字符串转换成一个可以在OpenCV中使用的数据结构。
有没有办法将.mat文件/.csv文件转换为OpenCV中的Mat数据结构?
编辑:根据我收到的答案,我成功地使用YML文件将MATLAB数据读入OpenCV。我在MAC环境下完成了这项工作。但是,当我尝试在Windows环境下使用相同的代码读取文件时,文件没有被读取。只是想知道是否有人遇到过这样的问题。以下是我的代码片段:
// OpenCVDemo.cpp : Defines the entry point for the console application.
// Created for build/install tutorial, Microsoft Visual Studio and OpenCV 2.4.0

#include "stdafx.h"

#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
#include <iostream>

using namespace cv;
using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{  
        cout << "Loading the basis." << endl;

        FileStorage fs1("basis.yml", FileStorage::READ);

        cv::FileNode B = fs1["B"];

        if (B.EMPTY)
        {
            cout << "File is empty or does not exist" << endl;
            return 1;
        }

        fs1["B"] >> basis;

        cout << basis.cols << endl;

        fs1.release();

            return 0;
}

2
我尝试在Visual Studio的发布模式下运行相同的代码,并成功读取了.yml文件。 - Sid
3个回答

15
你可以使用OpenCV类Filestorage提供的XML / YAML文件存储
例如,如果你有一个像这个yml文件,我会称之为demo.yml
%YAML:1.0
    Variable1: !!opencv-matrix
       rows: 4
       cols: 5
       dt: f
       data: [ -1.60522782e-03, -5.93489595e-03, 2.92204670e-03,
           1.14785777e-02, -1.57432575e-02, -2.17529312e-02, 4.05947529e-02,
           6.56594411e-02, 1.24527821e-02, 3.19751091e-02, 5.41692637e-02,
           4.04683389e-02, 2.59191263e-03, 1.15112308e-03, 1.11024221e-02,
           4.03668173e-03, -3.19138430e-02, -9.40114353e-03, 4.93452176e-02,
           5.73473945e-02 ]
    Variable2: !!opencv-matrix
       rows: 7
       cols: 2
       dt: f
       data: [ -2.17529312e-02, 4.05947529e-02, 5.73473945e-02,
           6.56594411e-02, 1.24527821e-02, 3.19751091e-02, 5.41692637e-02,
           4.03668173e-03, -3.19138430e-02, -9.40114353e-03, 4.93452176e-02,
           4.04683389e-02, 2.59191263e-03, 1.15112308e-03 ]

然后,您可以使用OpenCV的FileStorage类将包含在此demo.yml文件中的变量加载为:

#include <iostream>
#include <string>

#include <cv.h>
#include <highgui.h>

using namespace cv;
using namespace std;

int main (int argc, char * const argv[])
{   
    Mat var1;
    Mat var2;

    string demoFile  = "demo.yml";

    FileStorage fsDemo( demoFile, FileStorage::READ);
    fsDemo["Variable1"] >> var1;
    fsDemo["Variable2"] >> var2;

    cout << "Print the contents of var1:" << endl;
    cout << var1 << endl << endl;

    cout << "Print the contents of var2:" << endl;
    cout << var2 << endl;

    fsDemo.release();
    return 0;
}

现在,你可以编写自己的Matlab解析器,类似于我下面的matlab2opencv.m
function matlab2opencv( variable, fileName, flag)

[rows cols] = size(variable);

% Beware of Matlab's linear indexing
variable = variable';

% Write mode as default
if ( ~exist('flag','var') )
    flag = 'w'; 
end

if ( ~exist(fileName,'file') || flag == 'w' )
    % New file or write mode specified 
    file = fopen( fileName, 'w');
    fprintf( file, '%%YAML:1.0\n');
else
    % Append mode
    file = fopen( fileName, 'a');
end

% Write variable header
fprintf( file, '    %s: !!opencv-matrix\n', inputname(1));
fprintf( file, '        rows: %d\n', rows);
fprintf( file, '        cols: %d\n', cols);
fprintf( file, '        dt: f\n');
fprintf( file, '        data: [ ');

% Write variable data
for i=1:rows*cols
    fprintf( file, '%.6f', variable(i));
    if (i == rows*cols), break, end
    fprintf( file, ', ');
    if mod(i+1,4) == 0
        fprintf( file, '\n            ');
    end
end

fprintf( file, ']\n');

fclose(file);

所以你可以运行类似以下的命令:

varA = rand( 3, 6);
varB = rand( 7, 2);

matlab2opencv( varA, 'newStorageFile.yml');
matlab2opencv( varB, 'newStorageFile.yml', 'a'); % append mode passed by 'a' flag

获取 newStorageFile.yml
%YAML:1.0
    varA: !!opencv-matrix
        rows: 3
        cols: 6
        dt: f
        data: [ 0.430207, 0.979748, 0.258065, 
            0.262212, 0.221747, 0.318778, 0.184816, 
            0.438870, 0.408720, 0.602843, 0.117418, 
            0.424167, 0.904881, 0.111119, 0.594896, 
            0.711216, 0.296676, 0.507858]
    varB: !!opencv-matrix
        rows: 7
        cols: 2
        dt: f
        data: [ 0.085516, 0.578525, 0.262482, 
            0.237284, 0.801015, 0.458849, 0.029220, 
            0.963089, 0.928854, 0.546806, 0.730331, 
            0.521136, 0.488609, 0.231594]

您可以像之前解释 Variable1Variable2 一样阅读 varAvarB

希望这能帮到您。


感谢 drodbar。我曾考虑使用 XML,因为 Haar Classifier 上有一个使用 XML 文件的 OpenCV 示例。但是我不确定如何以兼容的方式保存我的 MATLAB 数据。YAML 格式非常好用。感谢您提供这种格式。 - Sid
没问题!我得看一下Haar分类器示例。我知道如何使用“YAML”来做,但是不知道如何使用“XML”使其工作 :) - Drodbar

1
你可以使用opencv contrib中的Matlab桥接器。你只需要从Opencv Contrib中复制contrib/modules/matlab/include/opencv2/matlab文件夹到include/opencv2文件夹中即可。
同时需要安装Matlab Compiler Runtime(只需libmx.lib、libmex.lib和libmat.lib)。
MATFile *pmat = matOpen(filename, "r");
if (pmat == NULL)
{
     cerr << "Error opening file " << filename << endl;
}
else
{
     int numVars;
     char** namePtr = matGetDir(pmat, &numVars);
     cout << filename << " contains vars " << endl;
     for (int idx = 0; idx < numVars; idx++)
     {
           std::cout << "                     " << namePtr[idx] << " ";
           mxArray* m = matGetVariable(pmat, namePtr[idx]);
           matlab::MxArray mArray(m);
           cv::bridge::Bridge bridge(mArray);
           cv::Mat mat = bridge.toMat();
           //  do something with opencv Mat 
     }
}

0
除了使用@Drodbar建议的XML/YAML文件存储之外,您还可以尝试cvmatio,它提供了API以直接将MATLAB MAT文件加载到OpenCV中。
代码将会非常简单:
#include "MatlabIO.hpp"
#include "MatlabIOContainer.hpp"

...

// load the MATLAB MAT file
MatlabIO matio;
bool ok = matio.open("-path-to-mat-file.mat", "r");
if (!ok) return -1;

// read all of the variables in the file
std::vector<MatlabIOContainer> variables;
variables = matio.read();
matio.close();

// load the matrix by name in OpenCV style
cv::Mat basis = matio.find<cv::Mat>(variables, "B")

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接