opencv学习 --- FileStorage类使用注意事项
发布日期:2022-02-02 02:58:00 浏览次数:9 分类:技术文章

本文共 2453 字,大约阅读时间需要 8 分钟。

FileStorage类是中用来进行文件操作的封装类,可以对XML,YAML,txt甚至doc文件进行读写操作。在使用opencv时经常需要对特征数据等进行保存,这时候通常会选择XML文件或者YAML文件。xml和yaml都是属于标记语言,开发者可以根据自身需要定义标签。同时他们也是一种语义/结构化语言,他们可以描述文档的结构和语义。FileStorage类可以对C++的基础数据类型(int,float,double等)、容器类(vector,maps)、opencv定义的(Mat,Scalar等)进行读写操作。

FileStorage类的使用流程如下:

(1)实例化一个FileStorage类对象

(2)使用流操作符<<进行文件写入,>>进行文件读取,类似C++中的文件操作

(3)使用FileStorage::release()函数析构掉类对象,并关闭文件

给出具体实例:

fs<<"strings";输入的是标签,这里切不可写成fs<<"strings:"如果多加了个冒号则会报错:

OpenCV Error: Bad argument (Key name may only contain alphanumeric characters [a-zA-Z0-9]
fs<<"[";代表向量vector的开始,后续输入则是向量容器中具体数据
fs<<"]";表示之前的vector输入结束.

OpenCV 中的 FileStorage 类能够读写硬盘中的.xml.yaml文件,这里我们只讨论对 .xml 的以下几种操作:

  • 写入(FileStorage::WRITE,覆盖写)
  • 追加(FileStorage::APPEND,追加写)
  • 读取(FileStorage::WRITE

FileStorage 以 FileNode 为单位存储数据,且无法删改某个已有 FileNode的内容,想实现删改功能,得自己造轮子……

写入FileNode

FileNode有两种类型,seq 和 map

FileStorage fs("data.xml", FileStorage::WRITE); // seq_node 是一个 seq 型的节点, 以它为父节点,存入10个数据fs << "seq_node" << "[";for(size_t i = 0; i < 10; ++i){  fs << i;}fs << "]"; // map_node 是一个 map 型节点, 以它为父节点,存入10个数据fs << "map_node" << "{";for(size_t i = 0; i < 10; ++i){  fs << "node_" + to_string(i) << i;}fs << "}"; fs.release();

通过上面这段代码,我们可以看到 seq 和 map 这两种类型的节点,在写入数据时的差别:前者在子节点间,写入一对方括号[], 而后者写入花括号{};前者在写入子节点的时候,无法为子节点命名,而后者可以。OpenCV 最重要的 Mat 类型在存储时是以 map 方式写入的。

读入FileNode

seq 和 map 节点在读入数据的时候,前者以索引的方式去获得子节点,后者用子节点的名字,即一个字符串去获得子节点(字符串为键,节点为值):

FileStorage fs("data.xml", FileStorage::READ);vector
a, b; // seq_node 是一个 seq 型的节点FileNode seq_node = fs["seq_node"];for(size_t i = 0; i < 10; ++i){ seq_node[i] >> a[i];} // map_node 是一个 map 型节点FileNode map_node = fs["map_node"];for(size_t i = 0; i < 10; ++i){ fs["node_" + to_string(i)] >> b[i];} fs.release();

seq 型节点既然能以索引去取子节点,那自然有人会想到,能不能用迭代器去访问子节点呢?答案是可以。OpenCV为我们提供了FileNode的迭代器:

 

// seq_node 是一个 seq 型的节点FileNode seq_node = fs["seq_node"];FileNodeIterator it = seq_node.begin();for(; it != seq_node.end(); ++it){  *it >> a[i];}

自定义类型的读写

需要重载 write 和 read 函数:

struct MyData{  int i;  string str;  Mat I;} // 自定义写入static void write(FileStorage &fs, const string &, const MyData &mydata){  fs << "{"     << "index" << mydata.i     << "str"   << mydata.str     << "img"   << mydata.I     << "}"} // 自定义读取static void read(const FileNode &node, MyData &mydata, const MyData &default_val = MyData()){  if(node.empty()) mydata = default_val;  else {    node["index"] >> mydata.i;    node["str"] >> mydata.str;    node["img"] >> mydata.I;  }}

转自:

转载地址:https://blog.csdn.net/u010368556/article/details/86478864 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:opencv 学习--- 双线性插值算法原理简述
下一篇:双目立体图像矫正方法简述

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月09日 16时24分04秒