• OpenCV 读写xml和yml文件


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

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

    xml/yml的写操作

    如何将我们的数据写入文件保存下来?

    一个简单数据写入的例子

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

     1 #include<opencv2opencv.hpp>   
     2 #include<opencv2highguihighgui.hpp>
     3 
     4 using namespace std;
     5 using namespace cv;
     6 
     7 typedef struct
     8 {
     9     int x;
    10     int y;
    11     string s;
    12 }test_t;
    13 
    14 
    15 int main(int argc, char** argv)
    16 {
    17     FileStorage fs("test.xml", FileStorage::WRITE); //填入写操作
    18 
    19     //测试数据
    20     int a1 = 2;
    21     char a2 = -1;
    22     string str = "hello sysu!";
    23     int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
    24     test_t t = { 3,4,"hi sysu" };
    25     map<string, int> m;
    26     m["kobe"] = 100;
    27     m["james"] = 99;
    28     m["curry"] = 98;
    29 
    30     //写入文件操作,先写标注在写数据
    31     fs << "int_data" << a1;
    32     fs << "char_data" << a2;
    33     fs << "string_data" << str;
    34 
    35     //写入数组
    36     fs <<"array_data"<< "["; //数组开始
    37     for (int i = 0; i < 10; i++)
    38     {
    39         fs << arr[i];
    40     }
    41     fs << "]"; //数组结束
    42 
    43     //写入结构体
    44     fs << "struct_data" << "{"; //结构体开始
    45     fs << "x" << t.x;
    46     fs << "y" << t.y;
    47     fs << "s" << t.s;
    48     fs << "}";  //结构结束
    49 
    50 
    51     //map的写入 
    52     fs << "map_data" << "{";  //map的开始写入
    53     map<string, int>::iterator it = m.begin();
    54     for (; it != m.end(); it++)
    55     {
    56         fs << it->first << it->second;
    57     }
    58     fs << "}";  //map写入结束
    59 
    60 
    61     return 0;
    62 }

    打开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文件却显得有点冗余和杂乱了。

    一个复杂写入的例子

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

     1 #include<opencv2opencv.hpp>   
     2 #include<opencv2highguihighgui.hpp>
     3 
     4 using namespace std;
     5 using namespace cv;
     6 
     7 typedef struct
     8 {
     9     string phone_num;
    10     string address;
    11 }contact_t;
    12 
    13 typedef struct
    14 {
    15     string name;
    16     int age;
    17 }parents_t;
    18 
    19 typedef struct
    20 {
    21     string name;
    22     int age;
    23     int id;
    24     contact_t contact_ways;
    25     parents_t parents[2];
    26 }student_t;
    27 
    28 int main(int argc, char** argv)
    29 {
    30 
    31     FileStorage fs("student.xml", FileStorage::WRITE); //填入写操作
    32 
    33     student_t st[3]; 
    34     memset(st, 0, sizeof(st));
    35 
    36     //测试数据填入
    37     st[0].name = "Kobe";
    38     st[0].age = 21;
    39     st[0].id = 1;
    40     st[0].contact_ways.address = "1st building";
    41     st[0].contact_ways.phone_num = "123";
    42     st[0].parents[0].name = "dad";
    43     st[0].parents[1].name = "mum";
    44     st[0].parents[0].age = 40;
    45     st[0].parents[1].age = 39;
    46 
    47     st[1].name = "James";
    48     st[1].age = 20;
    49     st[1].id = 2;
    50     st[1].contact_ways.address = "2st building";
    51     st[1].contact_ways.phone_num = "12223";
    52     st[1].parents[0].name = "daddy";
    53     st[1].parents[1].name = "mumy";
    54     st[1].parents[0].age = 44;
    55     st[1].parents[1].age = 38;
    56 
    57 
    58     fs << "student" << "["; //结构体数组的开始
    59     for (int i = 0; i < 3; i++)
    60     {
    61         fs <<"{"; //结构体的开始
    62         fs << "name" << st[i].name;
    63         fs << "age" << st[i].age;
    64         fs << "id" << st[i].id;
    65 
    66         fs << "contact_ways" << "{";  //嵌套结构体的开始
    67         fs << "phone_number" << st[i].contact_ways.phone_num;
    68         fs << "address" << st[i].contact_ways.address;
    69         fs << "}";  //结构体结束
    70 
    71         fs << "parents"<<"[";  //嵌套结构体数组开始
    72         for (int j = 0; j < 2; j++)
    73         {
    74             fs << "{";
    75             fs << "name" << st[i].parents[j].name;
    76             fs << "age" << st[i].parents[j].age;
    77             fs << "}";
    78         }
    79         fs << "]";  //嵌套结构体数组结束
    80 
    81         fs << "}"; //结构体结束
    82 
    83     }
    84     fs << "]"; // 结构体数组结束
    85 
    86     return 0;
    87 }

    打开student.xml文件,如下

     1 <?xml version="1.0"?>
     2 <opencv_storage>
     3 <student>
     4   <_>
     5     <name>Kobe</name>
     6     <age>21</age>
     7     <id>1</id>
     8     <contact_ways>
     9       <phone_number>"123"</phone_number>
    10       <address>"1st building"</address></contact_ways>
    11     <parents>
    12       <_>
    13         <name>dad</name>
    14         <age>40</age></_>
    15       <_>
    16         <name>mum</name>
    17         <age>39</age></_></parents></_>
    18   <_>
    19     <name>James</name>
    20     <age>20</age>
    21     <id>2</id>
    22     <contact_ways>
    23       <phone_number>"12223"</phone_number>
    24       <address>"2st building"</address></contact_ways>
    25     <parents>
    26       <_>
    27         <name>daddy</name>
    28         <age>44</age></_>
    29       <_>
    30         <name>mumy</name>
    31         <age>38</age></_></parents></_>
    32   <_>
    33     <name>""</name>
    34     <age>0</age>
    35     <id>0</id>
    36     <contact_ways>
    37       <phone_number>""</phone_number>
    38       <address>""</address></contact_ways>
    39     <parents>
    40       <_>
    41         <name>""</name>
    42         <age>0</age></_>
    43       <_>
    44         <name>""</name>
    45         <age>0</age></_></parents></_></student>
    46 </opencv_storage>

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

     1 %YAML:1.0
     2 student:
     3    -
     4       name: Kobe
     5       age: 21
     6       id: 1
     7       contact_ways:
     8          phone_number: "123"
     9          address: "1st building"
    10       parents:
    11          -
    12             name: dad
    13             age: 40
    14          -
    15             name: mum
    16             age: 39
    17    -
    18       name: James
    19       age: 20
    20       id: 2
    21       contact_ways:
    22          phone_number: "12223"
    23          address: "2st building"
    24       parents:
    25          -
    26             name: daddy
    27             age: 44
    28          -
    29             name: mumy
    30             age: 38
    31    -
    32       name: ""
    33       age: 0
    34       id: 0
    35       contact_ways:
    36          phone_number: ""
    37          address: ""
    38       parents:
    39          -
    40             name: ""
    41             age: 0
    42          -
    43             name: ""
    44             age: 0

    xml/yml的读操作

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

    一个简单读入的例子

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

     1 #include<opencv2opencv.hpp>   
     2 #include<opencv2highguihighgui.hpp>
     3 
     4 using namespace std;
     5 using namespace cv;
     6 
     7 typedef struct
     8 {
     9     int x;
    10     int y;
    11     string s;
    12 }test_t;
    13 
    14 int a1;
    15 int a2;
    16 string str;
    17 int arr[10];
    18 test_t t;
    19 map<string, int> m;
    20 
    21 //打印出学生资料,来验证读取文件信息是否成功
    22 void data_info_dump()
    23 {
    24     cout << "a1:" << a1 << endl;
    25     cout << "a2:" << a2 << endl;
    26     cout << "str:" << str << endl;
    27     cout << "t.x:" << t.x << endl;
    28     cout << "t.y:" << t.y << endl;
    29     cout << "t.s:" << t.s << endl;
    30     cout << "curry:" << m["curry"] << endl;
    31     cout << "kobe:" << m["kobe"] << endl;
    32     cout << "james:" << m["james"] << endl;
    33     for (int i = 0; i < 10; i++)
    34     {
    35         cout << arr[i] << endl;
    36     }
    37 }
    38 
    39 int main(int argc, char** argv)
    40 {
    41     FileStorage fs("test.xml", FileStorage::READ); //填入读操作
    42     a1 = (int)fs["int_data"];
    43     a2 = (int)fs["char_data"];
    44     str = (string)fs["string_data"];
    45 
    46     //读入数组
    47     FileNode arr_node = fs["array_data"];
    48     FileNodeIterator fni = arr_node.begin(); 
    49     FileNodeIterator fniEnd = arr_node.end();
    50     int count = 0;
    51     for (; fni != fniEnd; fni++)
    52     {
    53         arr[count++] = (int)(*fni);
    54     }
    55 
    56     //读入map
    57     FileNode map_node = fs["map_data"];
    58     m["curry"] = (int)map_node["curry"];
    59     m["james"] = (int)map_node["james"];
    60     m["kobe"] = (int)map_node["kobe"];
    61 
    62     //读入结构体
    63     FileNode struct_node = fs["struct_data"];
    64     t.x = (int)struct_node["x"];
    65     t.y = (int)struct_node["y"];
    66     t.s = (string)struct_node["s"];
    67 
    68     data_info_dump();
    69 
    70     return 0;
    71 }

    打印如下:

    一个复杂读入的例子

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

     1 #include<opencv2opencv.hpp>   
     2 #include<opencv2highguihighgui.hpp>
     3 
     4 using namespace std;
     5 using namespace cv;
     6 
     7 typedef struct
     8 {
     9     string phone_num;
    10     string address;
    11 }contact_t;
    12 
    13 typedef struct
    14 {
    15     string name;
    16     int age;
    17 }parents_t;
    18 
    19 typedef struct
    20 {
    21     string name;
    22     int age;
    23     int id;
    24     contact_t contact_ways;
    25     parents_t parents[2];
    26 }student_t;
    27 
    28 student_t st[3];
    29 
    30 //打印出学生资料,来验证读取文件信息是否成功
    31 void stu_info_dump()
    32 {
    33     for (int i = 0; i < 3; i++)
    34     {
    35         printf("第%d个学生
    ",i+1);
    36         cout << "name:" << st[i].name << endl;
    37         cout << "id:" << st[i].id << endl;
    38         cout << "age:" << st[i].age << endl;
    39         cout << "contact address:" << st[i].contact_ways.address << endl;
    40         cout << "contact number:" << st[i].contact_ways.phone_num << endl;
    41         cout << "father name:" << st[i].parents[0].name << endl;
    42         cout << "father age:" << st[i].parents[0].age << endl;
    43         cout << "mother name:" << st[i].parents[1].name << endl;
    44         cout << "mother age:" << st[i].parents[1].age << endl;
    45         printf("
    
    ");
    46     }
    47 }
    48 
    49 int main(int argc, char** argv)
    50 {
    51 
    52     FileStorage fs("student.xml", FileStorage::READ); //填入读操作
    53 
    54     memset(st, 0, sizeof(st));
    55 
    56     FileNode student_node = fs["student"];//读取根节点
    57     FileNodeIterator fni = student_node.begin(); //获取结构体数组迭代器
    58     FileNodeIterator fniEnd = student_node.end();
    59     int count = 0;
    60     for (; fni != fniEnd; fni++)//遍历  
    61     {
    62 
    63         st[count].name = (string)(*fni)["name"];
    64         st[count].id = (int)(*fni)["id"];
    65         st[count].age = (int)(*fni)["age"];
    66     
    67         //contact结构体内容
    68         FileNode contact = (*fni)["contact_ways"];
    69         st[count].contact_ways.address = (string)contact["address"];
    70         st[count].contact_ways.phone_num = (string)contact["phone_number"];
    71 
    72         //parents结构体数组内容
    73         FileNode parents = (*fni)["parents"];
    74         FileNodeIterator fni2 = parents.begin(); //获取结构体数组迭代器
    75         FileNodeIterator fniEnd2 = parents.end();
    76         int count2 = 0;
    77         for (; fni2 != fniEnd2; fni2++)//遍历  
    78         {
    79             st[count].parents[count2].name = (string)(*fni2)["name"];
    80             st[count].parents[count2].age = (int)(*fni2)["age"];
    81             count2++;
    82         }
    83 
    84         count++;
    85     }
    86 
    87 
    88     stu_info_dump();
    89 
    90     return 0;
    91 }

    打印如下,这表明xml的数据已经成功读入内存了。

  • 相关阅读:
    Jenkins+ant循环执行jmeter文件
    Jmeter接口模版说明
    jenkins与远程服务器配置SSH免密登录
    xcode developer tools简介
    MySQL之模糊查询
    MySQL排名函数
    openblas下载安装与使用
    CVX安装使用
    AMD包下载及使用
    Python及相应软件安装
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/14177703.html
Copyright © 2020-2023  润新知