跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++AI算法

OpenCV C++ 中 XML 和 YAML 文件的读写操作

综述由AI生成如何在 OpenCV C++ 中使用 FileStorage 类进行 XML 和 YAML 文件的读写操作。内容包括基础数据类型、OpenCV 数据结构(如 Mat)、容器(Map 和 Seq)以及自定义数据结构的序列化与反序列化方法。文章提供了完整的代码示例,演示了如何打开文件、写入数据、遍历节点以及处理缺失节点的情况,并解释了不同文件格式扩展名的作用及压缩支持。

开源信徒发布于 2025/2/7更新于 2026/5/212 浏览
OpenCV C++ 中 XML 和 YAML 文件的读写操作

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;

     ;
}
A
0
X
0
id
""
// 显式构造函数以避免隐式转换
explicit MyData(int val) : A(97), X(val), id("mydata1234") {
// 写入函数:将类的数据序列化到 FileStorage
void write(FileStorage& fs) const
"{A"
"X"
"id"
"}"
// 读取函数:从 FileNode 反序列化数据
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)
// 或者:FileStorage fs; fs.open(filename, FileStorage::WRITE);
"iterationNr"
100
// 字符串序列
"strings"
"["
"image1.jpg"
"Awesomeness"
".../data/baboon.jpg"
"]"
// 关闭序列
// 映射
"map"
"{"
"one"
1
"two"
2
"}"
// OpenCV 数据结构
"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 函数显式调用此函数:

fs.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"]; // 读取字符串序列 - Get Node
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; one 1
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 都是人类可读的格式,便于调试和手动编辑配置文件。

目录

  1. OpenCV 中使用 XML 和 YAML 文件的文件输入与输出
  2. 目标
  3. 源代码示例 (C++)
  4. 详细解释
  5. XML/YAML 文件打开和关闭
  6. 文本和数字的输入和输出
  7. OpenCV 数据结构的输入/输出
  8. 向量(数组)和关联映射的输入/输出
  9. 读取和写入自己的数据结构
  10. 结果
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 Segment Anything 模型的图像分割部署与测试
  • AI 虚拟女友与角色扮演开源项目汇总
  • 基于 C# .NET Framework 的 Web Service 服务开发实例详解
  • 自定义 MCP 本地服务搭建:stdio 与 SSE 模式及 AI 工具调用
  • OpenClaw 自托管 AI 网关安装与配置指南
  • 基于 AutoGPT 与 Python 构建自主智能体实战指南
  • R 语言零截断数据建模实战:复杂数据结构下的统计建模技术
  • Linux 下安装配置 Claude Code 及 VS Code SSH 远程集成指南
  • 机器人通讯架构选型:CAN/FD、高速 485、EtherCAT 对比分析
  • Trae 集成腾讯地图 MCP 实战:让 AI 直接调用地图能力
  • 35 道常见前端 Vue 面试题解析
  • FPGA 以太网接口设计:纯 Verilog 实现 UDP/TCP 协议与校验重发
  • 腾讯云轻量应用服务器部署 OpenClaw 并接入 QQ 与飞书机器人
  • AI 大模型在金融、医疗、法律等垂直领域的创新应用与突破
  • 移动前端与 Web 前端开发的核心区别
  • 基于 Pygame 的水果忍者小游戏实现教程
  • 企业微信群机器人添加可点击链接:图文与 Markdown 实现方式
  • 网络安全入门:黑客必须掌握的核心技术与技能体系
  • AI 编程技能(Skill)详解:概念、用法与 Java 生成实战
  • 基于 Selenium+Python 自动获取登录态 Cookie 的三种实战方案

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online