• Opencv探索之路(十九):读写xml和yml文件


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

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

    xml/yml的写操作

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

    一个简单数据写入的例子

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

    #include<opencv2opencv.hpp>   
    #include<opencv2highguihighgui.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<opencv2opencv.hpp>   
    #include<opencv2highguihighgui.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<opencv2opencv.hpp>   
    #include<opencv2highguihighgui.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<opencv2opencv.hpp>   
    #include<opencv2highguihighgui.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个学生
    ",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("
    
    ");
    	}
    }
    
    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的数据已经成功读入内存了。

  • 相关阅读:
    My97DatePicker使用说明文档
    内存溢出之Tomcat内存配置
    myeclipse控制台不显示tomcat信息
    修改 MyEclipse 编辑区域背景颜色
    window.open() 弹出窗体居中
    javascript控制页面控件隐藏显示的两种方法
    (转)MyEclipse7.5.0版注册码破解及激活操作
    [置顶] Android代码读取 android 设备的电池信息
    [置顶] Android代码获得我们手机的cpu序列号
    [置顶] Android高手进阶教程Android常用名令集锦(图文并茂)!
  • 原文地址:https://www.cnblogs.com/skyfsm/p/7182313.html
Copyright © 2020-2023  润新知