OpenCV讀寫xml和yml文件

原文鏈接:https://www.cnblogs.com/skyfsm/p/7182313.html?utm_source=itdadao&utm_medium=referral

     有時候我們處理完圖像後需要保存一下數據到文件上,以供下一步的處理。一個比較廣泛的需求場景就是:我們對一幅圖像進行特徵提取之後,需要把特徵點信息保存到文件上,以供後面的機器學習分類操作。那麼如果遇到這樣的場景,我們有什麼好方法,搭建這類的小型數據庫文件?我第一時間想到的是把這些數據全寫到文件上,下次我們需要這些數據就把他們從文件裏讀出來就好了。

     其實更好的辦法是使用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的數據已經成功讀入內存了。

文章寫得很好,遂轉載記錄一下,轉載過程中難免出錯,如有問題請在評論區指出,下面附上原文鏈接~
轉自

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章