有时候程序中的变量值、字符串、数组等数据也需要独立于源代码本身保存,这个时候就需要用到XML和YAML文件进行保存。
OpenCV4提供了用于生成和读取XML文件和YAML文件的类FileStorage,该类的构造函数原型有两种,分别如下:
其构造函数的第一种原型:
C++
cv::FileStorage::FileStorage()
Python:
<FileStorage object> = cv.FileStorage()
其构造函数的第二种原型:
C++
cv::FileStorage::FileStorage(const String & filename,int flags,const String & encoding = String() )
Python:
<FileStorage object> = cv.FileStorage(filename, flags[, encoding])
第一种原型基本大家都不用,因为没有任何初始化参数,相当于只定义,不做初始化。
通常用的都是第二种原型。
第二种原型中各参数的说明如下。
filename—生成或读取的XML或YAML文件名称,可以使用的后缀名有.xml、.yml/.yaml 、 .json
flags—操作模式选择。其可选值及意义如下:
值得注意的是:在Python中,上面的flags参数可选值都要加上cv.FileStorage_的前缀,比如READ要写为“cv.FileStorage_READ”。
接下来通过一个简单的Python例子来说明类FileStorage的使用。
首先是源码,
源码请大家访问下面的页面获取。
https://www.hhai.cc/thread-107-1-1.html
上面页面提供的源码的作用为:
创建一个包含数据的yaml或xml文件,然后再通过读取它获取相应的变量值。
代码说明如下:
先说成员函数cv.FileStorage.write(),这个函数可用于将变量名称和变量值写入XML或YAML文件。这个成员函数的原型如下:
C++原型有五种,分别如下:
void cv::FileStorage::write(const String &name,int val)
void cv::FileStorage::write(const String &name,doble val)
void cv::FileStorage::write(const String &name,const String &val)
void cv::FileStorage::write(const String &name,const Mat &val)
void cv::FileStorage::write(const String &name,const std::vector<String> &val)
参数name是要写入XML或YAML文件的变量的名称,参数val是对应变量的值。
从以上五个原型可以看出,val可以是下面五种类型
int、double、String、Mat、std::vector<String>
而由于Python不是强制类型语言,所以在OpenCV-Python中,FileStorage.write()只有一种原型,如下:
None = cv.FileStorage.write(name, val)
对于Python而言,val在这里的类型可以有三种,分别为实数、字符串和矩阵这三种类型的数据。
值得注意的是,把要写入文件的变量用FileStorage.write()写入文件之后,必须要用成员FileStorage的成员函数release()作一次释放操作,否则不会生成相应的文件,相关的代码如上面代码中的语句“file.release()”。
再说成员函数cv.FileStorage.getNode(),这个成员函数用于从XML或YAML文件中读取对应变量名的值。其函数原型如下:
C++原型有两种:
cv::FileStorage::operator[](const String & nodename) const
cv::FileStorage::operator[](const char * nodename) const
可见在OpenCV的C++版本中,并没有成员函数FileStorage.getNode(),它用操作符“[]”代替了函数名“getNode”。如果你要问上面原型末尾的const是怎么回事?可以参见我之前写的博文:类中成员函数声明后面的const的含义
其Python原型有三种,如下:
# 读取实数数据时需要用下面这种原型
retval = cv.FileStorage.getNode(nodename).real()
# 读取字符串数据时需要用下面这种原型
retval = cv.FileStorage.getNode(nodename).string()
# 读取矩阵数据时需要用下面这种原型
retval = cv.FileStorage.getNode(nodename).mat()
三种原型的作用已写于上面的注释中,这里就不多做赘述了。
程序运行时生成的yaml和xml文件分别如下,大家可以对照着程序看一看,这样很容易就理解yaml、xml其格式风格分别是怎么样的了。
生成的yaml文件内容如下:
%YAML:1.0
---
name: "毛晓彤"
age: 34
birth_date: "1988-02-16"
scores: !!opencv-matrix
rows: 3
cols: 3
dt: i
data: [ 92, 98, 98, 94, 98, 99, 92, 96, 95 ]
生成的xml文件内容如下:
<opencv_storage>
<name>"毛晓彤"name>
<age>34age>
<birth_date>"1988-02-16"birth_date>
<scores type_id="opencv-matrix">
<rows>3rows>
<cols>3cols>
<dt>idt>
<data>
92 98 98 94 98 99 92 96 95data>scores>
opencv_storage>
对比一下,昊虹君觉得yaml看着更舒服呢。