前端之家收集整理的这篇文章主要介绍了
OpenCV学习笔记:输入输出XML和YAML文件,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_
403_30@
代码
你可以点击此处下载或直接从OpenCV代码库中找到源文件。samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp。
以下用简单的示例代码演示如何逐一实现所有目的.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
#include <opencv2/core/core.hpp>
#include <iostream>
#include <string>
using namespace cv;
namespace std;
class MyData
{
public:
MyData(): A(0), X(id()
{}
explicit MyData(int) 97), X(CV_PI), id("mydata1234") // explicit 避免隐式类型转换
{}
void write(FileStorage& fs) const //Write serialization for this class
{
fs << "{" "A" << A "X" << X "id" << id "}";
}
void read(const FileNode& node) //Read serialization for this class
{
A = (int)node["A"];
X double)node["X"];
id = (string)node["id"];
}
: // Data Members
int A;
double X;
string id;
};
//These write and read functions must be defined for the serialization in FileStorage to work
& fs, const std::string&,32); font-weight:bold">const MyData& x)
{
x.write(fs);
}
& node, MyData& x,102)">& default_value = MyData()){
if(node.empty())
x = default_value;
else
x.read(node);
}
// This function will print our custom class to the console
ostream& operator<<(ostream& out,102)">& m)
{
out "{ id = " << m.id ",";
out "X = " << m.X "A = " << m.A "}";
return out;
}
int main(int ac, char** av)
{
if (ac != 2)
{
help(av);
return 1;
}
string filename = av[1];
{ //write
Mat R = Mat_<uchar>::eye(3, 3),
T <double>::zeros(1);
MyData m(1);
FileStorage fs(filename, FileStorage::WRITE);
fs "iterationNr" << 100;
fs "strings" "["; // text - string sequence
fs "image1.jpg" "Awesomeness" "baboon.jpg";
fs "]"; // close sequence
fs "Mapping"; // text - mapping
fs "One" 1;
fs << "Two" 2 "}";
fs "R" << R; // cv::Mat
fs "T" << T;
fs "MyData" << m; // your own data structures
fs.release(); // explicit close
cout "Write Done." << endl;
}
{//read
cout << endl "Reading: " << endl;
FileStorage fs;
fs.open(filename,102)">::READ);
int itNr;
//fs["iterationNr"] >> itNr;
itNr int) fs["iterationNr"];
cout << itNr;
if (!fs.isOpened())
{
cerr "Failed to open " << filename << endl;
help(av);
1;
}
FileNode n = fs["strings"]; // Read string sequence - Get node
if (n.type() != FileNode::SEQ)
{
cerr "strings is not a sequence! FAIL" << endl;
1;
}
FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node
for (; it != it_end; ++it)
cout << (string)*it << endl;
n "Mapping"]; // Read mappings from a sequence
cout "Two " << (int)(n["Two"]) "; ";
cout "One " "One"]) << endl;
MyData m;
Mat R, T;
fs["R"] >> R; // Read cv::Mat
fs["T"] >> T;
fs["MyData"] >> m; // Read your own structure_
cout << endl
"R = " << R << endl;
cout "T = " << T "MyData = " << m << endl;
//Show default behavior for non existing nodes
cout "Attempt to read NonExisting (should initialize the data structure with its default).";
fs["NonExisting"] >> m;
cout "NonExisting = " << endl;
}
cout << endl
"Tip: Open up " " with a text editor to see the serialized data." << endl;
0;
}
|
代码分析
这里我们仅讨论XML和YAML文件输入。你的输出(和相应的输入)文件可能仅具有其中一个扩展名以及对应的文件结构。XML和YAML的串行化分别采用两种不同的数据结构:mappings(就像STL map) 和element sequence(比如 STL vector>。二者之间的区别在map中每个元素都有一个唯一的标识名供用户访问;而在sequences中你必须遍历所有的元素才能找到指定元素。
-
XML\YAML 文件的打开和关闭。在你写入内容到此类文件中前,你必须先打开它,并在结束时关闭它。在OpenCV中标识XML和YAML的数据结构是FileStorage。要将此结构和硬盘上的文件绑定时,可使用其构造函数或者open()函数:
string filename = "I.xml";
FileStorage fs(filename,FileStorage::WRITE);
\\...
fs.open(filename,FileStorage::READ);
无论以哪种方式绑定,函数中的第二个参数都以常量形式指定你要对文件进行操作的类型,包括:WRITE,READ 或 APPEND。文件扩展名决定了你将采用的输出格式。如果你指定扩展名如.xml.gz,输出甚至可以是压缩文件。
当FileStorage对象被销毁时,文件将自动关闭。当然你也可以显示调用release函数:
-
输入\输出文本和数字。数据结构使用与STL相同的 << 输出操作符。输出任何类型的数据结构时,首先都必须指定其标识符,这通过简单级联输出标识符即可实现。基本类型数据输出必须遵循此规则:
读入则通过简单的寻址(通过 [] 操作符)操作和强制转换或 >> 操作符实现:
int itNr;
fs["iterationNr"] >> itNr;
itNr "iterationNr"];
-
输入\输出OpenCV数据结构。其实和对基本类型的操作方法是相同的:
Mat R <uchar >::eye (T 1);
fs // 写 cv::Mat
fs << T;
fs[// 读 cv::Mat
fs[>> T;
-
输入\输出 vectors(数组)和相应的maps.之前提到我们也可以输出maps和序列(数组,vector)。同样,首先输出变量的标识符,接下来必须指定输出的是序列还是map。
对于序列,在第一个元素前输出”[“字符,并在最后一个元素后输出”]“字符:
// 文本 - 字符串序列
fs "baboon.jpg";
fs // 序列结束
对于maps使用相同的方法,但采用”{“和”}“作为分隔符。
// 文本 - mapping
fs 1;
fs "}";
对于数据读取,可使用FileNode和FileNodeIterator数据结构。FileStorage的[] 操作符将返回一个FileNode数据类型。如果这个节点是序列化的,我们可以使用FileNodeIterator来迭代遍历所有元素。
FileNode n // 读取字符串序列 - 获取节点
::SEQ)
{
cerr << endl;
1;
}
FileNodeIterator it // 遍历节点
++it)
cout << endl;
对于maps类型,可以用 [] 操作符访问指定的元素(或者 >> 操作符):
n // 从序列中读取map
cout "Two " "; ";
cout "One " << endl;
-
读写自定义数据类型。假设你定义了如下数据类型:
:
MyData() id() {}
// 数据成员
int A;
double X;
string id;
};
添加内部和外部的读写函数,就可以使用OpenCV I/O XML/YAML接口对其进行序列化(就像对OpenCV数据结构进行序列化一样)。内部函数定义如下:
//对
自定义类进行写序列化
{
fs "}";
}
//从序列读取自定义类
{
A "A"];
X "X"];
id "id"];
}
接下来在类的外部定义以下函数:
& x)
{
x.write(fs);
}
= MyData())
{
if(node.empty())
x = default_value;
else
x.read(node);
}
这儿可以看到,如果读取的节点不存在,我们返回默认值。更复杂一些的解决方案是返回一个对象ID为负值的实例。
一旦添加了这四个函数,就可以用 >> 操作符和 << 操作符分别进行读,写操作:
MyData m(1);
fs << m; // 写自定义数据结构
fs[// 读自定义数据结构
或试着读取不存在的值:
fs[>> m; // 请注意不是 fs << "NonExisting" << m
cout << endl;
结果
好的,大多情况下我们只输出定义过的成员。在控制台程序的屏幕上,你将看到:
Write Done.
Reading:
100image1.jpg
Awesomeness
baboon.jpg
Two 2; One 1
R = [1,0;
0,1,1]
T [0; 0; 0]
MyData =
{ id = mydata1234,X = 3.14159,213)">A = 97}
Attempt to read NonExisting (should initialize the data structure with its default).
NonExisting =,102)">= 0,102)">= 0}
Tip: Open up output.xml with a text editor to see the serialized data.
然而,在输出的xml文件中看到的结果将更加有趣:
<?xml version="1.0"?>
<opencv_storage>
<iterationNr>100</iterationNr>
<strings>
image1.jpg Awesomeness baboon.jpg</strings>
<Mapping>
<One>1</One>
<Two>2</Two></Mapping>
<R type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>u</dt>
<data>
1 0 0 0 1 0 0 0 1</data></R>
<T <cols>1<dt>d<data>
0. 0. 0.</data></T>
<MyData>
<A>97</A>
<X>3.1415926535897931e+000</X>
<id>mydata1234</id></MyData>
</opencv_storage>
或YAML文件:
%YAML:1.0
iterationNr: 100
strings:
- "image1.jpg"
- Awesomeness
- "baboon.jpg"
Mapping:
One: 1
Two: 2
R: !!opencv-matrix
rows: 3
cols: 3
dt: u
data: [ 1,1 ]
T: !!opencv-matrix
rows: 3
cols: 1
dt: d
data: [ 0.,0.,0. ]
MyData:
A: 97
X: 3.1415926535897931e+000
id: mydata1234