有时候我们处理完图像后需要保存一下数据到文件上,以供下一步的处理。一个比较广泛的需求场景就是:我们对一幅图像进行特征提取之后,需要把特征点信息保存到文件上,以供后面的机器学习分类操作。那么如果遇到这样的场景,我们有什么好方法,搭建这类的小型数据库文件?我第一时间想到的是把这些数据全写到文件上,下次我们需要这些数据就把他们从文件里读出来就好了。
其实更好的办法是使用 xml 和 yml,因为他们更具有可读性,简直就是为保存数据结构而生的好方法!OpenCV 提供了很好用的读写 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
我们的数据已经稳妥地写入文件保存下来了,接下来我们想从该文件中读取出我们的数据,该如何操作呢?我们继续以上述的例子数据为例,讲解读操作。
我们举个简单例子,读入上面提到 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 的数据已经成功读入内存了。
来源: http://www.cnblogs.com/skyfsm/p/7182313.html