C++下OpenCV学习笔记----输入和输出XML和YAML

C++下OpenCV学习笔记

----输入和输出XML和YAML

一.XML和YAML简介
  1. XML:Extensible Markup Language,可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。
  2. YAML:YAML Ain’t a Markup Language 的递归缩写,是一个可读性高,用来表达数据序列化的格式。原意是"Yet Another Markup Language",但为了强调这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。
二.FileStorage类
  1. 构造函数
    FileStorage(const string& source, int flags, const string& encoding=string());

第一个参数:表示存储或读取数据的文件名
第二个参数:表示操作模式
FileStorage::READ 打开文件进行读操作
FileStorage::WRITE 打开文件进行写操作
FileStorage::APPEND 打开文件进行附加操作
FileStorage::MEMORY 从source读数据,或向内部缓存写入数据(由FileStorage::release返回)
第三个参数:表示文件的编码方式。目前不支持UTF-16 XML 编码,应使用 8-bit 编码

FileStorage fs("xxx.xml", FileStorage::WRITE);

FileStorage( );

FileStorage fs;
fs.open("xxx.xml", FileStorage::WRITE);
  1. 写入数据:operator <<
    template<typename_Tp> FileStorage& operator<<(FileStorage& fs, const _Tp& value);

第一个参数:表示需要写入数据的文件
第二个参数:表示待写入的数据

        template<typename_Tp> FileStorage& operator<<(FileStorage& fs, const vector<_Tp>& vec);

第一个参数:表示需要写入数据的文件
第二个参数:表示待写入的向量值

  • 文本和数字的输入
fs << "year" << 2021;    
fs << "hello" << "world";
  • OpenCV数据结构的输入
Mat R = Mat_<uchar>::eye(3, 3);
fs << "R" << R;
  1. 读取数据:operator >>
  • 文本和数字的读取
int Year = (int)fs["year"];
cout << "year: " << Year << endl;

在这里插入图片描述

std::string str;
fs["hello"] >> str;
cout << "hello: " << str << endl;

在这里插入图片描述

  • OpenCV数据结构的读取
Mat R;
fs["R"] >> R;
cout << "R = " << R << endl;
  1. vector数据结构的输入输出
  • vector数据,xml / yaml文件节点,不包含子节点
  • 在输入vector数据的开始和结尾要分别输入“[”,“]”
  • 输入vector数据前要先输入标签名称
FileStorage fs("test.yml", FileStorage::WRITE);
fs << "src" << "{" << "src1" << "[" << 1 << 2 << 3 << "]"
    << "src2" << "[" << 4 << 5 << 6 << "]" << "}";
fs.release();
  1. map数据结构的输入输出
  • map数据,xml / yaml文件节点,包含子节点
  • 在输入map数据的开始和结尾要分别写入“{”,“}”
  • 输入 map数据前要先输入标签名称

代码同上
创建一个yaml父节点(map),包含两个子节点(vector)

  1. FileStorage::open
    打开文件.
    boolFileStorage::open(const string& filename, int flags, const string&encoding=string());

第一个参数:表示存储或读取数据的文件名。其扩展名(.xml 或 .yml/.yaml) 决定文件格式(XML 或 YAML)
第二个参数:表示操作模式
第三个参数:表示文件的编码方式

  1. FileStorage::isOpened
    检查文件是否已经打开.
    boolFileStorage::isOpened();

返回true:打开
返回false:其他情况

FileStorage fs1("xxx.yml", FileStorage::READ);
FileStorage fs2("test.yml", FileStorage::READ);
bool flag1 = fs1.isOpened();
bool flag2 = fs2.isOpened();

cout << "flag1 = " << flag1 << endl;
cout << "flag2 = " << flag2 << endl;

在这里插入图片描述

  1. FileStorage::release
    存储或读取操作完成后,需要关闭文件并释放缓存.
    void FileStorage::release();
 FileStorage fs("xxx.yml", FileStorage::WRITE);
 ...
 fs.release();
  1. FileStorage::getFirstTopLevelNode
    返回映射(mapping)顶层的第一个元素.
    FileStorage::getFirstTopLevelNode();
FileStorage fs2("test.yml", FileStorage::READ);
string FirstNode = fs2.getFirstTopLevelNode();
cout << "The first top level node is " << FirstNode << endl;

在这里插入图片描述

  1. FileStorage::root
    返回顶层映射(mapping).
    FileNode FileStorage::root(int streamidx = 0);

第一个参数:表示从0开始的字符串索引。大部分情况文件中只有一个串,但YAML支持多个串,因此可以有多个。

写入文件中

FileStorage fs("test.yml", FileStorage::WRITE);
Mat src = (Mat_<double>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
fs << "src1" << src;
fs << "src2" << src;
fs.release();

读取文件中

FileStorage fs2("test.yml", FileStorage::READ);
FileNode rootnode = fs2.root();
FileNodeIterator it;
for (it = rootnode.begin();it < rootnode.end();it++)
{
	Mat dst;
	(*it) >> dst;
	cout << dst << endl;
}
  1. 读数据:FileStorage::operator[]
    返回指定的顶层映射元素.
    FileNode FileStorage::operator[](const string& nodename) const;
    FileNode FileStorage::operator[](const char* nodename) const;

第一个参数:表示文件的节点名

Mat R;
fs["R"] >> R;
cout << "R = " << R << endl;
三.写入文件

以XML为例,若想输出YAML文件(.yaml或.yml)甚至txt和doc,更改后缀名即可。

#define _CRT_SECURE_NO_WARNINGS 
#include<opencv2/opencv.hpp>
#include<time.h>
using namespace cv;

int main()
{
    FileStorage fs("test.yml", FileStorage::WRITE);

    fs << "frameCount" << 5;
    time_t rawtime;
    time(&rawtime);
    fs << "calibrationDate" << asctime(localtime(&rawtime));

    Mat cameraMatrix = (Mat_<double>(3, 3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1);
    Mat distCoeffs = (Mat_<double>(5, 1) << 0.1, 0.01, -0.001, 0, 0);
    fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs;
    fs << "features" << "[";
    for (int i = 0; i < 3; i++)
    {
        int x = rand() % 640;
        int y = rand() % 480;
        uchar lbp = rand() % 256;

        fs << "{:" << "x" << x << "y" << y << "lbp" << "[:";
        for (int j = 0; j < 8; j++)
            fs << ((lbp >> j) & 1);
        fs << "]" << "}";
    }
    fs << "]";
    fs.release();
    printf("文件读写完毕\n");
    getchar();
    return 0;
}
  • 若出现:
    在这里插入图片描述
    则在所有include文件前,添加:
#define _CRT_SECURE_NO_WARNINGS
  • 运行结果:
四.读取文件

将写入的text.yml文件复制粘贴到工程目录下:

#define _CRT_SECURE_NO_WARNINGS 
#include<opencv2/opencv.hpp>
#include<time.h>
using namespace cv;
using namespace std;

int main()
{
	system("color 6F");

	FileStorage fs2("test.yml", FileStorage::READ);
	
	int frameCount = (int)fs2["frameCount"];
	
	std::string date;
	fs2["calibrationDate"] >> date;

	Mat cameraMatrix2, distCoeffs2;
	fs2["cameraMatrix"] >> cameraMatrix2;
	fs2["distCoeffs"] >> distCoeffs2;

	cout << "frameCount: " << frameCount << endl
		<< "calibration date: " << date << endl
		<< "camera matrix: " << cameraMatrix2 << endl
		<< "distortion coeffs" << distCoeffs2 << endl;

	FileNode features = fs2["features"];
	FileNodeIterator it = features.begin(), it_end = features.end();
	int idx = 0;
	std::vector<uchar> lbpval;

	for (;it != it_end;++it, idx++)
	{
		cout << "feature #" << idx << ": ";
		cout << "x=" << (int)(*it)["x"] << ", y=" << (int)(*it)["y"] << ", lbp: (";
		(*it)["lbp"] >> lbpval;
		for (int i = 0;i < (int)lbpval.size();i++)
			cout << " " << (int)lbpval[i];
		cout << ")" << endl;
	}
	
	fs2.release();
	printf("\n文件读取完毕!\n");
	getchar();
	return 0;
}
  • 运行结果:
五.FileNode数据结构
  • 文件存储节点类,对于进行读操作的文件节点用于存储每个文件元素。
  • 当读取XML或YMAL文件,节点是第一个被解析并作为一个节点结合存储到存储器中。每个节点都可以作为一个包含一个数字或一个字符或其他节点的“叶子”。每个节点都有一个名字并可以通过节点的名字对节点进行访问,这些节点就组成了一个集合,就算节点没有名字也可以通过元素的索引对节点结合进行排序。
  • 节点只用用来对文件的读取提供引导,而文件进行写操作后将没有数据存储在内存中。
  1. 构造函数
    FileNode::FileNode();
    FileNode::FileNode(const CvFileStorage* fs, const CvFileNode* node);
    FileNode::FileNode(const FileNode& node);
  2. 类型:seq和map
    写入
    (1)seq
    在子节点间,写入一对方括号[];无法为子节点命名。
    (2)map
    在子节点间,写入一对花括号{};可以为子节点命名。

OpenCV 最重要的 Mat 类型在存储时是以 map 方式写入的。

FileStorage fs("test.yml", FileStorage::WRITE);
fs << "seq_node" << "[";
for (int i = 0; i < 3; ++i) 
    fs << i;
fs << "]";

fs << "map_node" << "{";
for (int i = 0; i < 3; ++i) 
    fs << "node_" + std::to_string(i) << i;
fs << "}";
fs.release();

         读取
          (1)seq
          以索引的方式去获得子节点,也可以用迭代器去访问子节点。
           (2)map
          用子节点的名字,即一个字符串去获得子节点(字符串为键,节点为值)。

FileStorage fs("test.yml", FileStorage::READ);
FileNode seq_node = fs["seq_node"];
for (int i = 0; i < 3; i++) 
{
	int num;
	seq_node[i] >> num;
	cout << num << endl;
}

FileNode map_node = fs["map_node"];
for (int i = 0; i < 3; i++) 
{
	int n;
    map_node["node_" + to_string(i)] >> n;
    cout << "node_" + to_string(i) << ": " << n << endl;
}

关于map型读取的分析:
---->父节点:map_code,内含三个子节点:node_0, node_1, node_2;
---->通过FileNode map_node = fs2["map_node"];找到父节点map_node;再在父节点内寻找子节点map_node["node_" + to_string(i)],得到值
---->若用fs["node_" + to_string(i)]是找不到值的,因为父节点没有node_0, node_1, node_2

六.FileNodeIterator数据结构

用于迭代访问序列(sequences)和映射表(mappings)。是一种典型的STL符号,通过node.begin()和node.end()来标识序列的开始和结束位置。

  1. 构造函数
    FileNodeIterator::FileNodeIterator();
    FileNodeIterator::FileNodeIterator(const CvFileStorage* fs, const CvFileNode* node, size_t ofs=0);
    FileNodeIterator::FileNodeIterator(const FileNodeIterator& it);
  2. seq 型用迭代器去访问子节点
FileStorage fs("test.yml", FileStorage::READ);
FileNode seq_node = fs["seq_node"];
FileNodeIterator it = seq_node.begin();
for (; it != seq_node.end(); ++it) {
	int i;
	*it >> i;
	cout << i << endl;
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X to Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值