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

其实更好的办法是使用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的数据已经成功读入内存了。

Opencv探索之路(十九):读写xml和yml文件的更多相关文章

  1. OpenCV探索之路(九):模板匹配

    模板匹配的作用在图像识别领域作用可大了.那什么是模板匹配? 模板匹配,就是在一幅图像中寻找另一幅模板图像最匹配(也就是最相似)的部分的技术. 说的有点抽象,下面给个例子说明就很明白了. 在上面这幅全明 ...

  2. OpenCV FileStorage类读写XML/YML文件

    本文转自:http://www.cnblogs.com/summerRQ/articles/2524560.html 在OpenCV程序中,需要保存中间结果的时候常常会使用.xml / .yml文件, ...

  3. 【VS开发】【计算机视觉】OpenCV读写xml文件《C++版本》

    OpenCV FileStorage类读写XML/YML文件 在OpenCV程序中,需要保存中间结果的时候常常会使用.xml / .yml文件,opencv2.0之前都是使用C风格的代码,当时读写XM ...

  4. python第二十九课——文件读写(复制文件)

    自定义函数:实现文件复制操作有形参(2个) 没有返回值相似版(不用) def copyFile(src,dest): #1.打开两个文件:1个关联读操作,1个关联写操作 fr=open(src,'rb ...

  5. python第二十九课——文件读写(读取读取中文字符)

    演示:读取中文字符 结论: 1).如果不设置encoding,默认使用gbk进行编解码 2).如果编码和解码不一致,最终导致报错,但是一旦设置了errors='ingore',那么就不会报错,而采取乱 ...

  6. 【黑金原创教程】【FPGA那些事儿-驱动篇I 】实验十九:SDRAM模块② — 多字读写

    实验十九:SDRAM模块② — 多字读写 表示19.1 Mode Register的内容. Mode Register A12 A11 A10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A ...

  7. centos MySQL主从配置 ntsysv chkconfig setup命令 配置MySQL 主从 子shell MySQL备份 kill命令 pid文件 discuz!论坛数据库读写分离 双主搭建 mysql.history 第二十九节课

    centos  MySQL主从配置 ntsysv   chkconfig  setup命令  配置MySQL 主从 子shell  MySQL备份  kill命令  pid文件  discuz!论坛数 ...

  8. OpenCV探索之路(二十四)图像拼接和图像融合技术

    图像拼接在实际的应用场景很广,比如无人机航拍,遥感图像等等,图像拼接是进一步做图像理解基础步骤,拼接效果的好坏直接影响接下来的工作,所以一个好的图像拼接算法非常重要. 再举一个身边的例子吧,你用你的手 ...

  9. KALI LINUX WEB 渗透测试视频教程—第十九课-METASPLOIT基础

    原文链接:Kali Linux Web渗透测试视频教程—第十九课-metasploit基础 文/玄魂 目录 Kali Linux Web 渗透测试视频教程—第十九课-metasploit基础..... ...

随机推荐

  1. VR全景智慧城市,开启“上帝视角”体验‘身临其境’

    VR全景把不同的场景 分为若干个VR视角点 进入一个视角点,用户便能开启"上帝视角" 转动手机,身临其境地360度转动察看,对场景的全貌和细节一目了然.   人生处处有尴尬 比如大 ...

  2. Python教程(2.4)——字符串

    2.2节讲过,Python中有字符串类型.在Python中,字符串用'或"括起,例如'abc'."qwerty"等都是字符串.注意'和"并不是字符串的内容. A ...

  3. Java之线程同步练习

    1.有一张银行卡:*属性:name,money(账户余额)* 多线程操作同一张银行卡: 金额:x(每次存钱取钱的数额,取钱时x为负数,存钱时x为整数) 定义一个add方法:用于存取钱,参数为x,即每次 ...

  4. Java NIO学习笔记一 Java NIO概述

    Java NIO概述 Java NIO(新的IO)是Java的替代IO API(来自Java 1.4),这意味着替代标准的 java IO和java Networking API.Java NIO提供 ...

  5. JavaScript数组去重方法及测试结果

    最近看到一些人的去面试web前端,都说碰到过问JavaScript数组去重的问题,我也学习了一下做下总结. 实际上最有代表性也就三种方法:数组双重循环,对象哈希,排序后去重. 这三种方法我都做了性能测 ...

  6. ecshop屏蔽wap功能

    用手机打开ecshop网店,就会被重定向到mobile文件夹,如果打开wap功能,就能看到wap版的网站.但现在智能手机横行,iphone.安卓可以跟电脑一样浏览和购物,这个wap功能就有点鸡肋.现在 ...

  7. java源码学习(三)Enum

    Enum Enum类是java.lang包中一个类,他是Java语言中所有枚举类型的公共基类. 一.定义 public abstract class Enum<E extends Enum< ...

  8. 来吧学学.Net Core之登录认证与跨域资源使用

    序言 学习core登录认证与跨域资源共享是越不过的砍,所以我在学习中同样也遇到啦这两个问题,今天我们就用示例来演示下使用下这2个技术点吧. 本篇主要内容如下: 1.展示一个登录认证的简单示例 2.跨域 ...

  9. php Base64编码文件二进制流主要使用

    <?php header( "Content-type: image/jpeg"); //$filename='1.jpg'; //$content=file_get_con ...

  10. 利用 Traceview 精准定位启动时间测试的异常方法 (工具开源)

    机智的防爬虫标识原创博客地址:http://www.cnblogs.com/alexkn/p/7095855.html博客求关注: http://www.cnblogs.com/alexkn 1.启动 ...