Converting a .mat file from MATLAB into cv::Mat matrix in OpenCV

c++, io, matlab, matrix, opencv

Solution

You can use the XML/YAML file storages provided by the OpenCV class Filestorage.

As an example, if you have a yml file like this one, that I'll call 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 ]

Then, you can use OpenCV FileStorage class to load the variables contained on this demo.yml file as:

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

Now, what you can do is writing your own Matlab parser, similarly to my matlab2opencv.m below:

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

So you could run something like:

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

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

obtaining 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]

from which you could read `varA` and `varB` as previously explained for `Variable1` and `Variable2`.

Hope it helps

Problem

I have some MATLAB code that I want to migrate to OpenCV. The data that the MATLAB code uses is stored in a .mat file which is then loaded at run time. I converted this .mat file into a .csv file and am then reading this data into OpenCV as a string using ifstream. I am having problems converting this string into a data-structure that I can then use in OpenCV. Is there anyway that I can convert the .mat file / .csv file to a Mat data structure in OpenCV? Edit: Based on the Answer I received, I was successful in reading MATLAB data into OpenCV using a YML file. This I did in a MAC environment. However, when I try to read the file with the same piece of code in a Windows environment, the file is not being read. Just wondering if anyone ran into such an issue. Below is my code snippet: ``` // 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; } ```

Original source