跳到主要内容 OpenCV C++ 中 XML 和 YAML 文件的读写操作 | 极客日志
C++ AI 算法
OpenCV C++ 中 XML 和 YAML 文件的读写操作 如何在 OpenCV C++ 中使用 FileStorage 类进行 XML 和 YAML 文件的读写操作。内容包括基础数据类型、OpenCV 数据结构(如 Mat)、容器(Map 和 Seq)以及自定义数据结构的序列化与反序列化方法。文章提供了完整的代码示例,演示了如何打开文件、写入数据、遍历节点以及处理缺失节点的情况,并解释了不同文件格式扩展名的作用及压缩支持。
开源信徒 发布于 2025/2/7 更新于 2026/4/21 0 浏览OpenCV 中使用 XML 和 YAML 文件的文件输入与输出
目标
本文将解答以下问题:
如何使用 YAML 或 XML 文件打印和读取 OpenCV 的文本条目?
如何对 OpenCV 数据结构(如 cv::Mat)做同样的事情?
如何为您的自定义数据结构执行此操作?
源代码示例 (C++)
以下是一个完整的示例代码,展示了如何实现上述目标。该代码基于 OpenCV 官方教程中的 file_input_output.cpp 进行整理和优化。
#include <opencv2/opencv.hpp>
#include <iostream>
#include <string>
using namespace std;
using namespace cv;
static void help (char ** av)
{
cout << endl
<< av[0 ] << "显示了 OpenCV 序列化功能的用法。" << endl
<< "用法:" << endl
<< av[0 ] << " outputfile.yml.gz" << endl
<< "输出文件可以是 XML (.xml) 或 YAML (.yml/.yaml)。您甚至可以通过" << endl
<< "在其扩展名中指定这一点,如 xml.gz, yaml.gz 等..." << endl
<< "使用 FileStorage,您可以使用 << 和 >> 运算符序列化 OpenCV 中的对象" << endl
<< "例如:" << endl
<< " - 创建一个类并对其进行序列化" << endl
<< " - 用它来读取和写入矩阵。" << endl;
}
class MyData
{
public :
int A;
double X;
string id;
MyData () : ( ), ( ), ( ) {}
}
{
fs << << A << << X << << id << ;
}
{
A = ( )node[ ];
X = ( )node[ ];
id = (string)node[ ];
}
};
<<(FileStorage& fs, std::string& name, MyData& x)
{
x. (fs);
}
>>( FileNode& node, MyData& x, MyData& default_value = ())
{
(node. ())
x = default_value;
x. (node);
}
ostream& <<(ostream& out, MyData& m)
{
out << << m.id <<
<< << m.X <<
<< << m.A << ;
out;
}
{
(ac != )
{
(av);
;
}
string filename = av[ ];
{
Mat R = ( , ), T = ( , );
;
;
fs << << ;
fs << << ;
fs << << << ;
fs << ;
fs << << << << ;
fs << << << ;
fs << << R;
fs << << T;
fs << << m;
fs. ();
cout << << endl;
}
{
cout << endl << << endl;
FileStorage fs;
fs. (filename, FileStorage::READ);
(!fs. ())
{
cerr << << filename << endl;
(av);
;
}
itNr;
fs[ ] >> itNr;
cout << itNr << endl;
FileNode n = fs[ ];
(n. () != FileNode::SEQ)
{
cerr << << endl;
;
}
FileNodeIterator it = n. (), it_end = n. ();
(; it != it_end; ++it)
cout << (string)*it << endl;
n = fs[ ];
cout << << ( )(n[ ]) <<
<< << ( )(n[ ]) << endl << endl;
MyData m;
Mat R, T;
fs[ ] >> R;
fs[ ] >> T;
fs[ ] >> m;
cout << endl
<< << R << endl;
cout << << T << endl << endl;
cout << << endl << m << endl << endl;
cout << << endl;
fs[ ] >> m;
cout << endl << << endl << m << endl;
}
cout << endl
<< << endl;
;
}
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
RSA密钥对生成器 生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
Mermaid 预览与可视化编辑 基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
A
0
X
0
id
""
explicit MyData (int val) : A(97 ), X(val), id("mydata1234" ) {
void write (FileStorage& fs) const
"{A"
"X"
"id"
"}"
void read (const FileNode& node)
int
"A"
double
"X"
"id"
static
void
operator
const
const
write
static
void
operator
const
const
MyData
if
empty
else
read
operator
const
"{ id = "
", "
"X = "
", "
"A = "
"}"
return
int main (int ac, char ** av)
if
2
help
return
1
1
3
3
3
1
MyData m (1 )
FileStorage fs (filename, FileStorage::WRITE)
"iterationNr"
100
"strings"
"["
"image1.jpg"
"Awesomeness"
".../data/baboon.jpg"
"]"
"map"
"{"
"one"
1
"two"
2
"}"
"R"
"T"
"MyData"
release
"写完成。"
"Reading: "
open
if
isOpened
"无法打开"
help
return
1
int
"iterationNr"
"strings"
if
type
"错误:strings 不是一个序列!FAIL"
return
1
begin
end
for
"map"
"two "
int
"two"
"; "
"one "
int
"one"
"R"
"T"
"MyData"
"R = "
"T = "
"MyData = "
"尝试读取 NonExisting(应使用其默认值初始化数据结构)。"
"NonExisting"
"NonExisting = "
"提示:使用文本编辑器打开 output.xml 以查看序列化数据。"
return
0
详细解释
XML/YAML 文件打开和关闭 在将任何内容写入此类文件之前,您需要打开它,并在最后关闭它。OpenCV 中的 XML/YAML 数据结构是 FileStorage。要指定此结构绑定到硬盘驱动器上的文件,您可以使用其构造函数或 open 函数:
FileStorage fs (filename, FileStorage::WRITE) ;
FileStorage fs;
fs.open (filename, FileStorage::WRITE);
第二个参数用于指定您可以对它们执行的操作类型:WRITE、READ 或 APPEND。文件名中指定的扩展名还决定了将使用的输出格式。如果指定扩展名(如 *.xml.gz),则输出甚至可以被压缩。
当 FileStorage 对象被销毁时,该文件会自动关闭。但是,您可以使用 release 函数显式调用此函数:
文本和数字的输入和输出 在 C++ 中,数据结构使用 STL 库中的 << 输出运算符。对于基本类型,您可以按照以下方式打印:
fs << "iterationNr" << 100 ;
读入是一个简单的寻址(通过 [] 运算符)和强制转换操作,或者通过 >> 运算符进行读入:
int itNr;
fs["iterationNr" ] >> itNr;
itNr = (int )fs["iterationNr" ];
OpenCV 数据结构的输入/输出 OpenCV 的数据结构(如 cv::Mat)的行为与基本的 C++ 类型完全相同:
Mat R = (3 , 3 ), T = (3 , 1 );
fs << "R" << R;
fs["R" ] >> R;
向量(数组)和关联映射的输入/输出 我们可以输出映射和序列(数组、向量)。同样,我们首先打印变量的名称,然后必须指定我们的输出是序列还是映射。
对于序列,在第一个元素之前打印 [ 字符,在最后一个元素之后打印 ] 字符:
fs << "strings" << "[" ;
fs << "image1.jpg" << "Awesomeness" << ".../data/baboon.jpg" ;
fs << "]" ;
fs << "map" << "{" << "one" << 1 ;
fs << "two" << 2 << "}" ;
为了从中读取数据,我们使用 cv::FileNode 数据结构。FileNode 类的 [] 运算符返回 FileNode 数据类型。如果节点是连续的,我们可以使用 FileNodeIterator 来遍历项目:
FileNode n = fs["strings" ];
if (n.type () != FileNode::SEQ)
{
cerr << "错误:strings 不是一个序列!FAIL" << endl;
return 1 ;
}
FileNodeIterator it = n.begin (), it_end = n.end ();
for (; it != it_end; ++it)
cout << (string)*it << endl;
对于地图,您可以再次使用 [] 运算符来访问给定的项目:
n = fs["map" ];
cout << "two " << (int )(n["two" ]) << "; "
<< "one " << (int )(n["one" ]) << endl;
读取和写入自己的数据结构 class MyData
{
public :
int A;
double X;
string id;
};
在 C++ 中,可以通过 OpenCV I/O XML/YAML 接口通过在类内部和外部添加读取和写入函数来序列化它。
void write (FileStorage& fs) const
{
fs << "{A" << A << "X" << X << "id" << id << "}" ;
}
void read (const FileNode& node)
{
A = (int )node["A" ];
X = (double )node["X" ];
id = (string)node["id" ];
}
外部部分:
需要在类外部添加以下函数定义,以便使用 << 和 >> 运算符:
static void operator <<(FileStorage& fs, const std::string& name, const MyData& x)
{
x.write (fs);
}
static void operator >>(const FileNode& node, MyData& x, const MyData& default_value = MyData ())
{
if (node.empty ())
x = default_value;
else
x.read (node);
}
在这里,您可以观察到,在读取部分中,我们定义了如果用户尝试读取不存在的节点会发生什么。在本例中,我们只返回默认的初始化值,但是更详细的解决方案是返回例如对象 ID 的负 1 值以表示错误。
添加这四个函数后,使用 >> 运算符进行写入,使用 << 运算符进行读取:
MyData m (1 ) ;
fs << "MyData" << m;
fs["MyData" ] >> m;
cout << "尝试读取 NonExisting(应使用其默认值初始化数据结构)。" << endl;
fs["NonExisting" ] >> m;
结果 运行程序后,控制台的屏幕上可以看到类似以下的输出:
写完成。
Reading:
100
image1.jpg
Awesomeness
.../data/baboon.jpg
two 2
R = [1 , 0 , 0
0 , 1 , 0
0 , 0 , 1 ]
T = [0
0
0 ]
MyData =
{ id = mydata1234, X = 3.14159 , A = 97 }
尝试读取 NonExist(应使用其默认值初始化数据结构)。
NonExisting =
{ id = , X = 0 , A = 0 }
提示:使用文本编辑器打开生成的 output.xml 或 output.yml 文件以查看原始序列化数据。XML 和 YAML 都是人类可读的格式,便于调试和手动编辑配置文件。