使用OpenCV时不仅要保存影像结果,往往也需要保存中间的矩阵结果,而OpenCV的imwrite函数只支持CV8U类型的数据(使用OpenCV保存其他类型Mat的时候,程序不会报错,但是无法生成结果文件),因此会给工作带来很多不便。OpenCV在2.0以后的版本中提供了FileStorage类,供用户直接使用,保存为XML/YAML文件。
保存示例如下:
Mat mat = Mat::eye(Size(12,12), CV_8UC1);
FileStorage fs("f:\\vocabulary.xml", FileStorage::WRITE);
fs << "vocabulary" << mat;
fs.release();
得到结果文件如下所示:
<opencv_storage>
<vocabulary type_id="opencv-matrix">
<rows>12rows>
<cols>12cols>
<dt>udt>
<data>
1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 0 0 1data>vocabulary>
opencv_storage>
需要注意的是,因为保存的结果为xml文件,所以再保存的时候需要给定标签,格式就是下面的形式,先存储标签内容,再存储矩阵:
fs << "vocabulary" << mat;
同样使用FileStorage类可以直接获取保存的xml文件内容。
读取示例如下:
FileStorage fs(".\\vocabulary.xml", FileStorage::READ);
Mat mat_vocabulary;
fs["vocabulary"] >> mat_vocabulary;
读取文件的时候同样要给定标签内容,这里通过中括号[]给定:
fs["vocabulary"] >> mat_vocabulary;
很多时候,直接使用CSV文件相比XML更方便,使用XML保存得到的数据,无论是查看(excel查看,XML中矩阵不是格式化的)还是接着使用别的工具处理(例如matlab),都可以快速的读取,而XML需要解析则比较繁琐。那么该如何保存CSV文件呢,对保存的CSV文件又应该如何读取呢,请看下文分解。
OpenCV提供了结果保存的格式化函数format,使用format我们就可以根据自己想要的格式打印和保存数据了。
先直接看保存函数,再来分析具体含义吧:
ofstream file("test.csv");
file << format(mat, Formatter::FMT_CSV);
file.close();
根据上面的代码只用ofstream对象打开要写入的csv文件,再直接写入数据即可,需要注意的是,接入的矩阵用format格式化,format函数第二个参数表示格式类型,这里选择CSV格式即Formatter::FMT_CSV。
这里保存格式为定义在Formatter类中的枚举类型,总共有6中选项,各位读者可以根据自己的需求选择。
class CV_EXPORTS Formatter
{
public:
enum { FMT_DEFAULT = 0,
FMT_MATLAB = 1,
FMT_CSV = 2,
FMT_PYTHON = 3,
FMT_NUMPY = 4,
FMT_C = 5
};
virtual ~Formatter();
virtual Ptr format(const Mat& mtx) const = 0;
virtual void set32fPrecision(int p = 8) = 0;
virtual void set64fPrecision(int p = 16) = 0;
virtual void setMultiline(bool ml = true) = 0;
static Ptr get(int fmt = FMT_DEFAULT);
};
在保存为CSV格式后该如何读取呢,这里可以使用OpenCV中ml模块的TrainData类的函数读取。具体代码如下所示,第二行为加载数据,参数0表示没有标题行,第三行获取得到的数据。
Ptr<TrainData> train_data;
train_data = TrainData::loadFromCSV("test.csv", 0);
Mat m = train_data->getTrainSamples();
cout << format(m, Formatter::FMT_CSV) << endl;
参考链接:
1. OpenCV使用FileStorage保存Mat数据
2. XML/YAML file storages. Writing to a file storage.