在把 Matlab 转化成 OpenCV(C++) 的过程中,经常会遇见 load .mat 文件这个问题。正巧,Stackoverflow 上有个问题《Converting a .mat file from MATLAB into cv::Mat matrix in OpenCV》就是回答这个的。这篇博文的主要分为两部分,第 1 部分是将这个答案转述一遍,以方便日后需要;第 2 部分是在原答案的基础上的改进,以求在方便程度和灵活性上有一定的提高。
1. (翻译)将 MATLAB 的 .mat 文件转化成 OpenCV 的 cv::Mat 矩阵
由于 OpenCV 没法直接读取 MATLAB 的 .mat 文件,这就需要通过第三方的格式作为两者之间的桥梁。考虑到 OpenCV 的 FileStorage
类提供了 XML/YML
文件的存取功能。
例如,我们有一个如下的 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 parser,类似于如下这样的:
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);
由此,我们就可以将 Matlab 变量储存成 yml 文件,如下所示:
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]
读取 varA
和 varB
的方法就跟之前读取 Variable1
和 Variable2
那样。
2. 改进的代码
需求
- 根据输入的数据类型,自适应地调整写入到 yml 文件的数据类型,以方便后面
cv::Mat
类型的数据访问。
先来一个稍微改动一下,写入 int
类型的代码:
function matlab2opencv_int( 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: i\n');
fprintf( file, ' data: [ ');
% Write variable data
for i=1:rows*cols
fprintf( file, '%i', variable(i));
if (i == rows*cols), break, end
fprintf( file, ', ');
if mod(i+1,8) == 0
fprintf( file, '\n ');
end
end
fprintf( file, ']\n');
fclose(file);
有了上面的基础,下面自动的代码就可以是:
function dym_matlab2opencv(variable, fileName, flag, varClass)
% varClass: the variable class waiting for write:
% 'i': for int
% 'f': for float
% flag : Write mode
% 'w': for write
% 'a': for append
[rows, cols] = size(variable);
% Beware of Matlab's linear indexing
variable = variable';
% Write mode as default
if ( ~exist('flag','var') )
flag = 'w';
end
% float as default
if ( ~exist('varClass','var') )
if isfloat(variable)
varClass = 'f';
else isinteger(variable)
varClass = 'i';
end
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: ' varClass '\n']);
fprintf( file, ' data: [ ');
% Write variable data
for i=1:rows*cols
fprintf( file, ['%' varClass], variable(i));
if (i == rows*cols), break, end
fprintf( file, ', ');
if mod(i+1,8) == 0
fprintf( file, '\n ');
end
end
fprintf( file, ']\n');
fclose(file);
以上,初写于 2015-05-02,更新于 2015-07-23。
首发于 Yimian Dai's Homepage,转载请注明出处。
网友评论