Opencv 读写xml和yml文件

有时候我们处理完图像后需要保存一下数据到文件上,以供下一步的处理。一个比较广泛的需求场景就是:我们对一幅图像进行特征提取之后,需要把特征点信息保存到文件上,以供后面的机器学习分类操作。那么如果遇到这样的场景,我们有什么好方法,搭建这类的小型数据库文件?我第一时间想到的是把这些数据全写到文件上,下次我们需要这些数据就把他们从文件里读出来就好了。

其实更好的办法是使用xml和yml,因为他们更具有可读性,简直就是为保存数据结构而生的好方法!OpenCV提供了很好用的读写xml/yml的类,我们只要掌握其读写要领,很容易就可以实现这个小型数据库。

xml/yml的写操作
如何将我们的数据写入文件保存下来?

一个简单数据写入的例子
下面是我们最常用的一些数据类型的写入xml的操作。

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

typedef struct
{
	int x;
	int y;
	string s;
}test_t;


int main(int argc, char** argv)
{
	FileStorage fs("test.xml", FileStorage::WRITE); //填入写操作

//测试数据
int a1 = 2;
char a2 = -1;
string str = "hello sysu!";
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
test_t t = { 3,4,"hi sysu" };
map<string, int> m;
m["kobe"] = 100;
m["james"] = 99;
m["curry"] = 98;

//写入文件操作,先写标注在写数据
fs << "int_data" << a1;
fs << "char_data" << a2;
fs << "string_data" << str;

//写入数组
fs <<"array_data"<< "["; //数组开始
for (int i = 0; i < 10; i++)
{
	fs << arr[i];
}
fs << "]"; //数组结束

//写入结构体
fs << "struct_data" << "{"; //结构体开始
fs << "x" << t.x;
fs << "y" << t.y;
fs << "s" << t.s;
fs << "}";  //结构结束


//map的写入 
fs << "map_data" << "{";  //map的开始写入
map<string, int>::iterator it = m.begin();
for (; it != m.end(); it++)
{
	fs << it->first << it->second;
}
fs << "}";  //map写入结束


return 0;
}

打开test.xml文件,我们看到我们的数据保存是这样子的:

在这里插入图片描述

如果我们将文件存为test.yml,即

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

那么我们最终的得到的test.yml是这样子的:

在这里插入图片描述

我们还可以保存为txt格式

FileStorage fs("test.txt", FileStorage::WRITE);

打开看是这样的:

在这里插入图片描述

我们还还可以保存为doc文件!

FileStorage fs("test.doc", FileStorage::WRITE); 

打开看是这样子的:
在这里插入图片描述

我们可以看出,显然yml文件的排版更加简洁明了,xml文件却显得有点冗余和杂乱了。

一个复杂写入的例子
在这里举一个简易的学生信息系统文件的搭建,以熟悉一下较为复杂的数据结构的写入文件的操作流程。

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

typedef struct
{
	string phone_num;
	string address;
}contact_t;

typedef struct
{
	string name;
	int age;
}parents_t;

typedef struct
{
	string name;
	int age;
	int id;
	contact_t contact_ways;
	parents_t parents[2];
}student_t;

int main(int argc, char** argv)
{

FileStorage fs("student.xml", FileStorage::WRITE); //填入写操作

student_t st[3]; 
memset(st, 0, sizeof(st));

//测试数据填入
st[0].name = "Kobe";
st[0].age = 21;
st[0].id = 1;
st[0].contact_ways.address = "1st building";
st[0].contact_ways.phone_num = "123";
st[0].parents[0].name = "dad";
st[0].parents[1].name = "mum";
st[0].parents[0].age = 40;
st[0].parents[1].age = 39;

st[1].name = "James";
st[1].age = 20;
st[1].id = 2;
st[1].contact_ways.address = "2st building";
st[1].contact_ways.phone_num = "12223";
st[1].parents[0].name = "daddy";
st[1].parents[1].name = "mumy";
st[1].parents[0].age = 44;
st[1].parents[1].age = 38;


fs << "student" << "["; //结构体数组的开始
for (int i = 0; i < 3; i++)
{
	fs <<"{"; //结构体的开始
	fs << "name" << st[i].name;
	fs << "age" << st[i].age;
	fs << "id" << st[i].id;

	fs << "contact_ways" << "{";  //嵌套结构体的开始
	fs << "phone_number" << st[i].contact_ways.phone_num;
	fs << "address" << st[i].contact_ways.address;
	fs << "}";  //结构体结束

	fs << "parents"<<"[";  //嵌套结构体数组开始
	for (int j = 0; j < 2; j++)
	{
		fs << "{";
		fs << "name" << st[i].parents[j].name;
		fs << "age" << st[i].parents[j].age;
		fs << "}";
	}
	fs << "]";  //嵌套结构体数组结束

	fs << "}"; //结构体结束

}
fs << "]"; // 结构体数组结束

return 0;
}

打开student.xml文件,如下

<?xml version="1.0"?>
<opencv_storage>
<student>
  <_>
    <name>Kobe</name>
    <age>21</age>
    <id>1</id>
    <contact_ways>
      <phone_number>"123"</phone_number>
      <address>"1st building"</address></contact_ways>
    <parents>
      <_>
        <name>dad</name>
        <age>40</age></_>
      <_>
        <name>mum</name>
        <age>39</age></_></parents></_>
  <_>
    <name>James</name>
    <age>20</age>
    <id>2</id>
    <contact_ways>
      <phone_number>"12223"</phone_number>
      <address>"2st building"</address></contact_ways>
    <parents>
      <_>
        <name>daddy</name>
        <age>44</age></_>
      <_>
        <name>mumy</name>
        <age>38</age></_></parents></_>
  <_>
    <name>""</name>
    <age>0</age>
    <id>0</id>
    <contact_ways>
      <phone_number>""</phone_number>
      <address>""</address></contact_ways>
    <parents>
      <_>
        <name>""</name>
        <age>0</age></_>
      <_>
        <name>""</name>
        <age>0</age></_></parents></_></student>
</opencv_storage>

若存储的是yml文件,打开如下:

	%YAML:1.0
	student:
   -
      name: Kobe
      age: 21
      id: 1
      contact_ways:
         phone_number: "123"
         address: "1st building"
      parents:
         -
            name: dad
            age: 40
         -
            name: mum
            age: 39
   -
      name: James
      age: 20
      id: 2
      contact_ways:
         phone_number: "12223"
         address: "2st building"
      parents:
         -
            name: daddy
            age: 44
         -
            name: mumy
            age: 38
   -
      name: ""
      age: 0
      id: 0
      contact_ways:
         phone_number: ""
         address: ""
      parents:
         -
            name: ""
            age: 0
         -
            name: ""
            age: 0

xml/yml的读操作
我们的数据已经稳妥地写入文件保存下来了,接下来我们想从该文件中读取出我们的数据,该如何操作呢?我们继续以上述的例子数据为例,讲解读操作。

一个简单读入的例子
我们举个简单例子,读入上面提到test.xml的数据。

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

typedef struct
{
    int x;
    int y;
    string s;
}test_t;

int a1;
int a2;
string str;
int arr[10];
test_t t;
map<string, int> m;

//打印出学生资料,来验证读取文件信息是否成功
void data_info_dump()
{
	cout << "a1:" << a1 << endl;
	cout << "a2:" << a2 << endl;
	cout << "str:" << str << endl;
	cout << "t.x:" << t.x << endl;
	cout << "t.y:" << t.y << endl;
	cout << "t.s:" << t.s << endl;
	cout << "curry:" << m["curry"] << endl;
	cout << "kobe:" << m["kobe"] << endl;
	cout << "james:" << m["james"] << endl;
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << endl;
	}
}

int main(int argc, char** argv)
{
	FileStorage fs("test.xml", FileStorage::READ); //填入读操作
	a1 = (int)fs["int_data"];
	a2 = (int)fs["char_data"];
	str = (string)fs["string_data"];

	//读入数组
	FileNode arr_node = fs["array_data"];
	FileNodeIterator fni = arr_node.begin(); 
	FileNodeIterator fniEnd = arr_node.end();
	int count = 0;
	for (; fni != fniEnd; fni++)
	{
		arr[count++] = (int)(*fni);
	}

//读入map
FileNode map_node = fs["map_data"];
m["curry"] = (int)map_node["curry"];
m["james"] = (int)map_node["james"];
m["kobe"] = (int)map_node["kobe"];

//读入结构体
FileNode struct_node = fs["struct_data"];
t.x = (int)struct_node["x"];
t.y = (int)struct_node["y"];
t.s = (string)struct_node["s"];

data_info_dump();

return 0;
}

打印如下:
在这里插入图片描述

一个复杂读入的例子
我们以读取上面所提到的student.xml为例,说明如何读取一个xml文件数据到内存。

#include<opencv2\opencv.hpp>   
#include<opencv2\highgui\highgui.hpp>

using namespace std;
using namespace cv;

typedef struct
{
	string phone_num;
	string address;
}contact_t;

typedef struct
{
	string name;
	int age;
}parents_t;

typedef struct
{
	string name;
	int age;
	int id;
	contact_t contact_ways;
	parents_t parents[2];
}student_t;

student_t st[3];

//打印出学生资料,来验证读取文件信息是否成功
void stu_info_dump()
{
	for (int i = 0; i < 3; i++)
	{
		printf("第%d个学生\n",i+1);
		cout << "name:" << st[i].name << endl;
		cout << "id:" << st[i].id << endl;
		cout << "age:" << st[i].age << endl;
		cout << "contact address:" << st[i].contact_ways.address << endl;
		cout << "contact number:" << st[i].contact_ways.phone_num << endl;
		cout << "father name:" << st[i].parents[0].name << endl;
		cout << "father age:" << st[i].parents[0].age << endl;
		cout << "mother name:" << st[i].parents[1].name << endl;
		cout << "mother age:" << st[i].parents[1].age << endl;
		printf("\n\n");
	}
}

int main(int argc, char** argv)
{

FileStorage fs("student.xml", FileStorage::READ); //填入读操作

memset(st, 0, sizeof(st));

FileNode student_node = fs["student"];//读取根节点
FileNodeIterator fni = student_node.begin(); //获取结构体数组迭代器
FileNodeIterator fniEnd = student_node.end();
int count = 0;
for (; fni != fniEnd; fni++)//遍历  
{

	st[count].name = (string)(*fni)["name"];
	st[count].id = (int)(*fni)["id"];
	st[count].age = (int)(*fni)["age"];

	//contact结构体内容
	FileNode contact = (*fni)["contact_ways"];
	st[count].contact_ways.address = (string)contact["address"];
	st[count].contact_ways.phone_num = (string)contact["phone_number"];

	//parents结构体数组内容
	FileNode parents = (*fni)["parents"];
	FileNodeIterator fni2 = parents.begin(); //获取结构体数组迭代器
	FileNodeIterator fniEnd2 = parents.end();
	int count2 = 0;
	for (; fni2 != fniEnd2; fni2++)//遍历  
	{
		st[count].parents[count2].name = (string)(*fni2)["name"];
		st[count].parents[count2].age = (int)(*fni2)["age"];
		count2++;
	}

	count++;
}


stu_info_dump();

return 0;
}

打印如下,这表明xml的数据已经成功读入内存了。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值