1 FileStorage
OpenCV
中可以使用FileStorage
类对xml,yml
等文本文件进行读写。
1.1 重要函数
1.1.1 构造函数FileStorage
函数作用:构造函数,打开待操作的文件;
cv::FileStorage::FileStorage(const cv::String& filename, int flags, const cv::String& encoding = cv::String())
-
filename
:待操作的文件名; -
flags
:操作方式,如读READ
、写WRITE
、追加APPEND
等;
| 含义 |
| 以读的形式打开 |
| 以写的形式打开 |
| 以追加的形式打开 |
| 从内存中读写数据 |
| 格式化数据的掩码 |
| 自动格式化数据 |
| 将文件按照 |
| 将文件按照 |
| 将文件按照 |
-
encoding
:文件编码方式,到目前位置(opencv 4.4.0
),尚不支持UTF-16
,只能使用8位编码方式;
cv::FileStorage::FileStorage()
默认构造函数;
一般与cv::FileStorage::open(const cv::String& filename, int flags, const cv::String& encoding = cv::String())
配合使用;
打开文件之前,会先调用
cv::FileStorage::release()
,关闭文件并释放所有的缓存;
1.1.2 析构函数~FileStorage
函数作用:析构函数,关闭待操作的文件;
析构函数调用cv::FileStorage::release()
;
1.1.3 release
函数作用:关闭文件,并释放所有的缓存;
1.1.4 isOpened
函数作用:判断文件是否打开成功;bool cv::FileStorage::isOpened()
1.1.5 operator<<
重载运算符函数作用:将数据写入到某个节点中;
1.1.6 operator>>
重载运算符函数作用:从某个节点中读取数据,并写入到某个变量中;
1.1.7 operator[]
重载运算符函数作用:取出某个节点的数据;
1.2 数据存储
FileStorage
中的数据存储有两种方式:
-
mapping
(键值对,key/value pair
) -
sequence
(没有名称的序列)
文件格式如下:
<?xml version="1.0"?>
<opencv_storage>
<Style1>
<day1>Monday</day1>
<day2>Tuesday</day2>
<day3>Wednesday</day3>
<day4>Thursday</day4>
<day5>Friday</day5>
<day6>Saturday</day6>
<day7>Sunday</day7></Style1>
<Style2>
1 2 3 4 5 6 7</Style2>
</opencv_storage>
Style1
节点按mapping
方式存储,Style2
节点按sequence
方式存储;
代码如下:
cv::FileStorage fs("xmlFile.xml", cv::FileStorage::WRITE);
// mapping
fs << "Style1";
fs << "{";
fs << "day1" << "Monday";
fs << "day2" << "Tuesday";
fs << "day3" << "Wednesday";
fs << "day4" << "Thursday";
fs << "day5" << "Friday";
fs << "day6" << "Saturday";
fs << "day7" << "Sunday";
fs << "}";
// sequence
fs << "Style2";
fs << "[";
fs << 1 << 2 << 3 << 4 << 5 << 6 << 7;
fs << "]";
fs.release();
2 写文件
首先以写的方式打开xml
文件,若本地不存在该文件,则自动创建:
// 方法1
cv::FileStorage fs("xmlFile.xml", cv::FileStorage::WRITE);
// 方法2
cv::FileStorage fs;
fs.open("xmlFile.xml", cv::FileStorage::WRITE);
2.1 写入1个节点1个值
向文件中写入1个节点,该节点只包含1个值,示例代码及输出文件如下:
// 代码
std::string key = "day1";
int value = 1;
fs << key << value;
// 输出文件
<?xml version="1.0"?>
<opencv_storage>
<day1>1</day1>
</opencv_storage>
节点名称必须是字符串,且该字符串内容要符合C++变量命名规则;
节点值可以是int,float,double,string
等;
2.2 写入1个节点多个值
向文件中写入1个节点,该节点包含多个值,示例代码及输出文件如下:
std::string key = "day1";
int value1 = 1;
std::string value2 = "Monday";
fs << key << "[" << value1 << value2 << "]";
<?xml version="1.0"?>
<opencv_storage>
<day1>
1 Monday</day1>
</opencv_storage>
上述示例代码中,1个节点中有2个值,代码中必须使用一对中括号
[]
包含多个值,输出文件中多个值之间通过空格分隔;
2.3 创建多级节点
向文件中创建多个节点,并写入值,示例代码及输出文件如下:
std::string key = "day1";
int value = 1;
fs << "Year2022";
fs << "{" << "December";
fs << "{";
fs << key << value;
fs << "}" << "}" ;
<?xml version="1.0"?>
<opencv_storage>
<Year2022>
<December>
<day1>1</day1></December></Year2022>
</opencv_storage>
上述示例代码中,通过使用一对花括号
{}
来增加节点,多级节点则使用多对{}
;
2.4 写入cv::Mat对象
FileStorage
支持将opencv
中的Mat
对象直接写入xml
文件,示例代码及输出文件如下:
std::string key = "matrix";
cv::Mat value = cv::Mat::eye(3, 4, CV_64FC1);
fs << key << value;
<?xml version="1.0"?>
<opencv_storage>
<matrix type_id="opencv-matrix">
<rows>3</rows>
<cols>4</cols>
<dt>d</dt>
<data>
1. 0. 0. 0. 0. 1. 0. 0. 0. 0. 1. 0.</data></matrix>
</opencv_storage>
Mat
类型数据在xml
文件中的节点名称为_ type_id="opencv-matrix"
,有4个子节点,rows
表示矩阵行数,cols
表示矩阵列数,dt
表示数据类型(u->uchar,f->float,d->double
),data
表示数据内容;
2.5 复杂示例代码
下面是一个略复杂的示例代码及对应输出文件:
#include <opencv2/core.hpp>
int main()
{
cv::FileStorage fs("xmlFile.xml", cv::FileStorage::WRITE);
fs << "WeekNum" << 2;
fs << "WeekInfo" << "[" << "ThisWeek" << 1 << "NextWeek" << 2 << "]";
fs << "ThisWeek" << "{";
fs << "Monday" << "{";
fs << "weather" << "Sunny";
fs << "temperature" << 20;
fs << "diet" << "{";
fs << "breakfast" << "[" << "bread" << 2 << "]";
fs << "lunch" << "[" << "steak" << 1 << "]";
fs << "dinner" << "milk";
fs << "}" << "}";
fs << "Sunday" << "{";
fs << "weather" << "Rainy";
fs << "temperature" << 15;
fs << "diet" << "{";
fs << "breakfast" << "[" << "porridge" << 1 << "]";
fs << "lunch" << "[" << "rice" << 2 << "]";
fs << "dinner" << "coffee";
fs << "}";
fs << "plan" << "learning OpenCV FileStorage";
fs << "}" << "}";
cv::Mat matEye = cv::Mat::eye(3, 3, CV_8UC1);
cv::Mat matZeros = cv::Mat::zeros(4, 5, CV_32FC1);
fs << "NextWeek" << "{";
fs << "plan" << "{";
fs << "MatLearning" << "[" << matEye << matZeros << "]";
fs << "game" << "Plants V.S. JiangShi, ^o^.";
fs << "}" << "}";
fs.release();
std::system("pause");
}
<?xml version="1.0"?>
<opencv_storage>
<WeekNum>2</WeekNum>
<WeekInfo>
ThisWeek 1 NextWeek 2</WeekInfo>
<ThisWeek>
<Monday>
<weather>Sunny</weather>
<temperature>20</temperature>
<diet>
<breakfast>
bread 2</breakfast>
<lunch>
steak 1</lunch>
<dinner>milk</dinner></diet></Monday>
<Sunday>
<weather>Rainy</weather>
<temperature>15</temperature>
<diet>
<breakfast>
porridge 1</breakfast>
<lunch>
rice 2</lunch>
<dinner>coffee</dinner></diet>
<plan>"learning OpenCV FileStorage"</plan></Sunday></ThisWeek>
<NextWeek>
<plan>
<MatLearning>
<_ type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>u</dt>
<data>
1 0 0 0 1 0 0 0 1</data></_>
<_ type_id="opencv-matrix">
<rows>4</rows>
<cols>5</cols>
<dt>f</dt>
<data>
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.</data></_></MatLearning>
<game>"Plants V.S. JiangShi, ^o^."</game></plan></NextWeek>
</opencv_storage>
3 读文件
首先以读的方式打开xml
文件:
// 方法1
cv::FileStorage fs("xmlFile.xml", cv::FileStorage::READ);
// 方法2
cv::FileStorage fs;
fs.open("xmlFile.xml", cv::FileStorage::READ);
以下示例代码中,读取的xml
文件为2.5
节中输出的文件;
3.1 读取1个节点中的1个值
从文件中读取1个节点,该节点只包含1个值,示例代码如下:
// 方法1
int value = fs["WeekNum"];
// 方法2
int value;
fs["WeekNum"] >> value;
// 方法3
cv::FileNode fn1 = fs["WeekNum"];
cv::FileNodeIterator fn1_iter = fn1.begin();
int value = *fn1_iter;
// 方法4
// 方法3
cv::FileNode fn1 = fs["WeekNum"];
cv::FileNodeIterator fn1_iter = fn1.begin();
int value;
*fn1_iter >> value;
3.2 读取1个节点中的多个值
从文件中读取1个节点,该节点包含4个值,示例代码如下:
// 方法1
cv::FileNode fn2 = fs["WeekInfo"];
cv::FileNodeIterator fn2_iter = fn2.begin();
// 以下通过赋值操作读取数据,也能使用>>重载运算符
std::string str_value1 = (std::string)*fn2_iter;
int i_value2 = (int)*(++fn2_iter);
std::string str_value3 = (std::string)*(++fn2_iter);
int i_value4 = (int)*(++fn2_iter);
// 方法2
cv::FileNode fn2 = fs["WeekInfo"];
if (cv::FileNode::SEQ == fn2.type()) {
// 以下通过赋值操作读取数据,也能使用>>重载运算符
std::string str_value1 = (std::string)fn2[0];
int i_value2 = (int)fn2[1];
std::string str_value3 = (std::string)fn2[2];
int i_value4 = (int)fn2[3];
}
3.3 读取多级节点中的值
从文件中读取多级节点中的值,示例代码如下:
cv::FileNode fn3 = fs["ThisWeek"];
cv::FileNode fn31 = fn3["Monday"];
cv::FileNode fn313 = fn31["diet"];
// 以下通过赋值操作读取数据,也能使用>>重载运算符
std::string str_value = (std::string)fn313["dinner"];
3.4 读取cv::Mat类型的数据
FileStorage
支持从xml
文件中直接读取opencv
中的Mat
对象,示例代码及输出文件如下:
cv::FileNode fn4 = fs["NextWeek"];
cv::FileNode fn41 = fn4["plan"];
cv::FileNode fn411 = fn41["MatLearning"];
// 只能使用>>重载运算符
cv::Mat mat1, mat2;
fn411[0] >> mat1;
fn411[1] >> mat2;
3.5 复杂示例代码
下面是一个略复杂的示例代码及对应输出:
int main()
{
cv::FileStorage fs("xmlFile.xml", cv::FileStorage::READ);
std::cout << "-WeekNum: ";
cv::FileNode fn1 = fs["WeekNum"];
std::cout << (int)fn1 << std::endl;
std::cout << "-WeekInfo" << std::endl;
cv::FileNode fn2 = fs["WeekInfo"];
if (cv::FileNode::SEQ == fn2.type()) {
std::cout << (std::string)fn2[0] << " ";
std::cout << (int)fn2[1] << " ";
std::cout << (std::string)fn2[2] << " ";
std::cout << (int)fn2[3] << std::endl;
}
std::cout << "-ThisWeek:" << std::endl;
cv::FileNode fn3 = fs["ThisWeek"];
std::cout << "--Monday:" << std::endl;
cv::FileNode fn31 = fn3["Monday"];
std::cout << "---weather: ";
std::cout << (std::string)fn31["weather"] << std::endl;
std::cout << "---temperature: ";
std::cout << (int)fn31["temperature"] << std::endl;
std::cout << "---diet:" << std::endl;
cv::FileNode fn313 = fn31["diet"];
std::cout << "----breakfast: ";
std::cout << (std::string)fn313["breakfast"][0] << " ";
std::cout << (int)fn313["breakfast"][1] << std::endl;
std::cout << "----lunch: ";
std::cout << (std::string)fn313["lunch"][0] << " ";
std::cout << (int)fn313["lunch"][1] << std::endl;
std::cout << "----dinner: ";
std::cout << (std::string)fn313["dinner"] << std::endl;
std::cout << "--Sunday:" << std::endl;
cv::FileNode fn32 = fn3["Sunday"];
std::cout << "---weather: ";
std::cout << (std::string)fn32["weather"] << std::endl;
std::cout << "---temperature: ";
std::cout << (int)fn32["temperature"] << std::endl;
std::cout << "---diet:" << std::endl;
cv::FileNode fn323 = fn32["diet"];
std::cout << "----breakfast: ";
std::cout << (std::string)fn323["breakfast"][0] << " ";
std::cout << (int)fn323["breakfast"][1] << std::endl;
std::cout << "----lunch: ";
std::cout << (std::string)fn323["lunch"][0] << " ";
std::cout << (int)fn323["lunch"][1] << std::endl;
std::cout << "----dinner: ";
std::cout << (std::string)fn323["dinner"] << std::endl;
std::cout << "---plan: ";
std::cout << (std::string)fn32["plan"] << std::endl;
std::cout << "-NextWeek:" << std::endl;
cv::FileNode fn4 = fs["NextWeek"];
std::cout << "--plan:" << std::endl;
cv::FileNode fn41 = fn4["plan"];
std::cout << "---MatLearning:" << std::endl;
cv::FileNode fn411 = fn41["MatLearning"];
// 只能使用>>重载运算符
cv::Mat mat1, mat2;
fn411[0] >> mat1;
fn411[1] >> mat2;
std::cout << mat1 << std::endl;
std::cout << mat2 << std::endl;
std::cout << "---game: ";
cv::FileNode fn412 = fn41["game"];
std::cout << (std::string)fn412 << std::endl;
fs.release();
std::system("pause");
return 0;
}
-WeekInfo
ThisWeek 1 NextWeek 2
-ThisWeek:
--Monday:
---weather: Sunny
---temperature: 20
---diet:
----breakfast: bread 2
----lunch: steak 1
----dinner: milk
--Sunday:
---weather: Rainy
---temperature: 15
---diet:
----breakfast: porridge 1
----lunch: rice 2
----dinner: coffee
---plan: learning OpenCV FileStorage
-NextWeek:
--plan:
---MatLearning:
[ 1, 0, 0;
0, 1, 0;
0, 0, 1]
[0, 0, 0, 0, 0;
0, 0, 0, 0, 0;
0, 0, 0, 0, 0;
0, 0, 0, 0, 0]
---game: Plants V.S. JiangShi, ^o^.