在做图像处理算法测试的时候往往会用到复杂的数据结构来保存最终的处理结果。本文介绍如何使用opencv的FileStorage类实现这一个目的,该功能的实现主要包含三个部分:数据保存、压缩、读取。如果数据量较小的时候可以去除压缩这一步。
FileStorage类有两种组织数据的方法,分别是"{" "}"、"[" "]"两种符号对。"{" "}"符号对,要求期间的每个数据都要有自己的数据名,适用于保存不同类型的数据,"[" "]"符号对用来保存同一类型的数据,如数组、vector类型的数据。"{:" "}"、"[:" "]"符号对表示中间数据要以紧凑的方式保存。
下面是一个使用例子代码:
<span style="font-size:14px;">#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/core/core.hpp"
#include <string>
#include <iostream>
using namespace cv;
using namespace std;
class Data0
{
public:
int a;
vector<Mat> mat;
};
class Data
{
public:
string name;
vector<Mat> imageset;
vector<Data0> data0;
//该类的写数据函数, 由于类的结构opencv不知道,所以需要自己写相应的代码,对于已知的数据类型,如Mat、vector、int等只需直接利用
//操作符>>或者<<。
void write(FileStorage& fs) const
{
fs << "{";
fs << "name" << name;
fs << "imageset" << imageset;
fs << "data0" << "[";
for(int i = 0; i < data0.size(); i++)
{
fs << "{";
fs << "a" << data0[i].a;
fs << "mat" << data0[i].mat;
fs << "}";
}
fs << "]";
}
//该类的读数据函数,由于类的结构opencv不知道,所以需要自己写相应的代码,对于已知的数据类型,如Mat、vector、int等只需直接利用
//操作符>>或者<<。
void read(const FileNode& node)
{
node["name"] >> name;
node["imageset"] >> imageset;
FileNode node0 = node["data0"];
FileNodeIterator it = node0.begin(), it_end = node0.end();
for(; it < it_end; it++)
{
Data0 tmp;
(*it)["a"] >> tmp.a;
(*it)["mat"] >> tmp.mat;
data0.push_back(tmp);
}
}
};
//These write and read functions must exist as per the inline functions in operations.hpp
static void write(FileStorage& fs, const std::string&, const Data& x)
{
x.write(fs);
}
static void read(const FileNode& node, Data& x, const Data& default_value = Data())
{
if(node.empty())
x = default_value;
else
x.read(node);
}
int main()
{
Data data;
data.name = string("Tom");
for(int i = 0; i < 2; i++)
{
Mat tmp(10, 10, CV_32F, Scalar(0.5));
data.imageset.push_back(tmp);
}
for(int i = 0; i < 2; i++)
{
Data0 data0;
data0.a = i;
data0.mat.push_back(Mat::eye(10, 10, CV_32F));
data.data0.push_back(data0);
}
//保存未压缩的数据
FileStorage fw("uncompress.yaml", FileStorage::WRITE);
fw << "Data" << data;
fw.release();
//保存数据并压缩
FileStorage fwc("compress.yaml.gz", FileStorage::WRITE);
fwc << "Data" << data;
fwc.release();
//读取压缩数据
FileStorage fr("compress.yaml.gz", FileStorage::READ);
Data dread;
fr["Data"] >> dread;
cout << "name: " << dread.name << endl;
for(int i = 0; i < dread.imageset.size(); i++)
{
cout << dread.imageset[i] << endl;
cout << endl;
}
for(int i = 0; i < dread.data0.size(); i++)
{
cout << dread.data0[i].a << endl;
for(int j = 0; j < dread.data0[i].mat.size(); j++)
{
cout << dread.data0[i].mat[j] << endl;
cout << endl;
}
cout << endl;
}
}</span>
运行结果如下,可以看出读取的数据是正确的。
<span style="font-size:14px;">name: Tom
[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
[0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5;
0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5]
0
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 1, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 1, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 1, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 1, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 1, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 1, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
1
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0;
0, 1, 0, 0, 0, 0, 0, 0, 0, 0;
0, 0, 1, 0, 0, 0, 0, 0, 0, 0;
0, 0, 0, 1, 0, 0, 0, 0, 0, 0;
0, 0, 0, 0, 1, 0, 0, 0, 0, 0;
0, 0, 0, 0, 0, 1, 0, 0, 0, 0;
0, 0, 0, 0, 0, 0, 1, 0, 0, 0;
0, 0, 0, 0, 0, 0, 0, 1, 0, 0;
0, 0, 0, 0, 0, 0, 0, 0, 1, 0;
0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
</span>
压缩效果测试, 可以看出未压缩数据占磁盘空间大小为5.6k,压缩后为302Byte,效果还是很明显的。特别实在算法测试时,数据量很大,对数据进行压缩后再保存很有必要。
<span style="font-size:14px;">-rw-rw-r-- 1 xuehen xuehen 302 1月 31 15:32 compress.yaml.gz
-rw-rw-r-- 1 xuehen xuehen 0 1月 31 15:57 result
-rw-rw-r-- 1 xuehen xuehen 5.6K 1月 31 15:32 uncompress.yaml</span>