OpenCV_Tutorials——CORE MODULE.THE CORE FUNCTIONALITY—— File Input and Output using XML and YAML file

2.9XMLYAML格式做爲文件輸入輸出

目標

你會從文中找到下面問題的答案:node

一、如何從OpenCV使用的YAML或者XML文件中讀取和打印文字條目。?ios

二、對於OpenCV數據結構如何作到相同的事情?數組

三、對你的數據結構如何作到?數據結構

四、OpenCV的數據結構,例如FileStorageFileNode或者FileNodeIterator的使用方法。app

 

源代碼

你能夠從這裏下載代碼或者從OpenCV的源代碼庫的samples/cpp/tutorial_code/core/file_input_output_file_input_out_put位置查看代碼。函數

 

#include <opencv2/core/core.hpp>this

#include <iostream>spa

#include <string>code

 

using namespace cv;xml

using namespace std;

 

static void help(char** av)

{

    cout << endl

        << av[0] << " shows the usage of the OpenCV serialization functionality."         << endl

        << "usage: "                                                                      << endl

        <<  av[0] << " outputfile.yml.gz"                                                 << endl

        << "The output file may be either XML (xml) or YAML (yml/yaml). You can even compress it by "

        << "specifying this in its extension like xml.gz yaml.gz etc... "                  << endl

        << "With FileStorage you can serialize objects in OpenCV by using the << and >> operators" << endl

        << "For example: - create a class and have it serialized"                         << endl

        << "             - use it to read and write matrices."                            << endl;

}

 

class MyData

{

public:

    MyData() : A(0), X(0), id()

    {}

    explicit MyData(int) : A(97), X(CV_PI), id("mydata1234") // explicit to avoid implicit conversion

    {}

    void write(FileStorage& fs) const                        //Write serialization for this class

    {

        fs << "{" << "A" << A << "X" << X << "id" << id << "}";

    }

    void read(const FileNode& node)                          //Read serialization for this class

    {

        A = (int)node["A"];

        X = (double)node["X"];

        id = (string)node["id"];

    }

public:   // Data Members

    int A;

    double X;

    string id;

};

 

//These write and read functions must be defined for the serialization in FileStorage to work

static void write(FileStorage& fs, const std::string&, const MyData& x)

{

    x.write(fs);

}

static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()){

    if(node.empty())

        x = default_value;

    else

        x.read(node);

}

 

// This function will print our custom class to the console

static ostream& operator<<(ostream& out, const MyData& m)

{

    out << "{ id = " << m.id << ", ";

    out << "X = " << m.X << ", ";

    out << "A = " << m.A << "}";

    return out;

}

 

int main(int ac, char** av)

{

    if (ac != 2)

    {

        help(av);

        return 1;

    }

 

    string filename = av[1];

    { //write

        Mat R = Mat_<uchar>::eye(3, 3),

            T = Mat_<double>::zeros(3, 1);

        MyData m(1);

 

        FileStorage fs(filename, FileStorage::WRITE);

 

        fs << "iterationNr" << 100;

        fs << "strings" << "[";                              // text - string sequence

        fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";

        fs << "]";                                           // close sequence

 

        fs << "Mapping";                              // text - mapping

        fs << "{" << "One" << 1;

        fs <<        "Two" << 2 << "}";

 

        fs << "R" << R;                                      // cv::Mat

        fs << "T" << T;

 

        fs << "MyData" << m;                                // your own data structures

 

        fs.release();                                       // explicit close

        cout << "Write Done." << endl;

    }

 

    {//read

        cout << endl << "Reading: " << endl;

        FileStorage fs;

        fs.open(filename, FileStorage::READ);

 

        int itNr;

        //fs["iterationNr"] >> itNr;

        itNr = (int) fs["iterationNr"];

        cout << itNr;

        if (!fs.isOpened())

        {

            cerr << "Failed to open " << filename << endl;

            help(av);

            return 1;

        }

 

        FileNode n = fs["strings"];                         // Read string sequence - Get node

        if (n.type() != FileNode::SEQ)

        {

            cerr << "strings is not a sequence! FAIL" << endl;

            return 1;

        }

 

        FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node

        for (; it != it_end; ++it)

            cout << (string)*it << endl;

 

 

        n = fs["Mapping"];                                // Read mappings from a sequence

        cout << "Two  " << (int)(n["Two"]) << "; ";

        cout << "One  " << (int)(n["One"]) << endl << endl;

 

 

        MyData m;

        Mat R, T;

 

        fs["R"] >> R;                                      // Read cv::Mat

        fs["T"] >> T;

        fs["MyData"] >> m;                                 // Read your own structure_

 

        cout << endl

            << "R = " << R << endl;

        cout << "T = " << T << endl << endl;

        cout << "MyData = " << endl << m << endl << endl;

 

        //Show default behavior for non existing nodes

        cout << "Attempt to read NonExisting (should initialize the data structure with its default).";

        fs["NonExisting"] >> m;

        cout << endl << "NonExisting = " << endl << m << endl;

    }

 

    cout << endl

        << "Tip: Open up " << filename << " with a text editor to see the serialized data." << endl;

 

 

    return 0;

}

這裏的例子向咱們展現如何在目標列中枚舉全部。

 

#include<opencv2/core/core.hpp>

#inclued<iostream>

#include<string>

 

using namespace std’

using namespace cv;

 

Class MyDate

{

public:

  MyData():A(0),X(0),id()

{
}

Explicit MyData(int):A(97),X(CV_PI),id(「mydata1234」)

{
}

void write(FileStorage&fs)const

{

fs<<」{「<<」A」<<A<<」X」<<X<<」id」<<id<<」}」;
}

 

void read(const FileNode&node)

{

A=(int)node[「A」];

X=(double)node[「X」];

Id=(string)node[「id」];
}   

 

public:

int  A;

double X;

string id;

 
};

 

static void write(FileStorage&fs,const std::string&,const MyData&x)

{

x.write(fs);
}

 

static void read(const FileNode&node,MyData&x,const MyData&default_value=MyData())

{

if(node.empty())

x=default_value;

else

x.read(node);
}

 

static ostream&opeartor<<(ostream&out,const MyData&m)

{

out<<」{id=」<<m.id<<」,」;

out<<」X=」<<m.X<<」,」;

out<<」A=」<<m.A<<」}」;

return out;


}

 

int main(int ac,char**av)

{

if(ac!=2)

{

help(av);

return 1;


}

string filename=av[1];

{

Mat R=Mat_<uchar>::eye(3,3);

Mat T=Mat_<double>::zeros(3,1):

myData m(1);

FileStorage fs(filseNmae,FileStorage::WRITE);

fs<<」iterationNr」<<100;

fs<<」strings」<<」[「;

fs<<」image1.jpg」<<」Awesomeness」<<」baboon,jpg」;

fs<<」]」;

fs<<」Mapping」;

fs<<」{「<<」One」<<1;

fs<<」Two」<<2<<」}」;

fs<<」R」<<R;

fs<<」T」<<T;

fs<<」MyData」<<m;

fs.release();

cout<<」Write Done.」<<endl;

}

{

cout<<endl<<」Reading」<<endl;

FileStorage fs;

fs.open(filename,FileStorage::READ);

int itNr;

itNr=(int) fs[「iterationNr」];

cout<<itNr;

if(!fs.isOpened())

{

cerr<<」Failed to open」<<filename<<endl;

help(av);

return 1;


}

FIleNode n=fs[「strings」];

If(n.type()!=FileNode::SEQ)

{

cerr<<」string is not a sequence FAIL」<<endl;

return 1;

}

FIleNodeIterator it=n.begin(),it_end=n.end();

for(;it!=it_end;++it)

{

cout<<(string)*it<<endl;
}

n=fs[「Mapping」];

cout<<」Two」<<(int)(n[「Two])<<」;」;

cout<<」One」<<(int)(n[「One])<<endl<<endl;

 

MyData m;

Mat R,T;

fs[「R」]>>R;

fs[「T」]>>T;

fs[「MyData」]>>m;

cout<<endl<<」R=」<<R<<endl;

cout<<」T=」<<T<<endl<<endl;;

 

cout<<」Attempt ro read NonExisting (should initialize the data structure with its default).」;

Fs[「NonExisting」]>>m;

cout<<endl<<」Nonexisting=」<<endl<<m<<endl;
}

cout<<endl<<」Tip: Open up」<<filename<<」with a text editor to see the serialized data.」<<endl;

return 0;


}

 

解釋

咱們在這裏討論XMLYAML文件的輸入問題。你的輸出(以及它的各自的輸出)文件可能只會有例子中的一個或者幾個例子。他們有兩種類型的數據結構你能夠序列化:mappings(相似STL中的map)和元素序列(相似STL中的vector)。這二者的不一樣之處在於map中你能夠經過每個元素的獨一無二的名字來讀取元素。對於序列來講,你須要遍歷他們來查詢到一個具體的事例。

一、XML\YAML文件的打開和關閉。你在向這樣的文件中寫任何內容以前須要先打開文件,而且在使用完畢後須要關閉它。XMLYAMLOpenCV中的數據結構是FIleStorage。爲了綁定那些你想要使用的硬盤中的文件,你能夠使用FileStorage的構造函數或者open()函數,例如:

 

string filename=」I.xml」;

FileStorage fs(filename,FileStorage:WRITE);

fs.open(filename,FIleStorage::READ);

上面出現的你使用的第二個參數是一個常量來指定你將要進行什麼操做:寫,讀或者附加。文件名後面指定反的擴轉名用來決定要用什麼輸出格式。若是你指定了類如.xml.gz的擴展名,輸出可能會被壓縮。

FileStorage對象被析構,文件就會自動關閉。然而,你能夠明確的調用release函數:

fs.release();

 

 

 

 

二、文字和數字的輸入輸出。FileStorage數據結構使用和STL同樣的<<輸出操做。爲了輸出任何類型的數據結構,咱們須要一開始指定它的名字。咱們經過簡單的輸出它的名字來完成這項任務。對於基本類型你能夠像下面那樣輸出數值:

  fs<<」iterationNr」<<100;

 

讀取操做是一個簡單的定位(經過[]操做符)和轉換操做或者經過>>操做符來進行。

 

Int itNr;

Fs[「iterationNr」]>>itNr;

itNr=(int) fs[「iterationNr」];

 

三、輸入或輸出OpenCV數據結構。下面的這些行爲就像是對C++的基礎類型的操做:

 

Mat R=Mat_<uchar>::eye(3,3);

Mat T=Mat_<double>::zeros(3,1);

fs<<」R」<<R;

fs<<」T」<<T;

fs[「R」]>>R;

fs[「T」]>>T;

 

4、輸入或輸出向量(數組)以及相關聯的map。像以前說起的。咱們也能夠輸出map和序列(數組,向量)。一樣的咱們首先輸出變量的名字而後咱們必須指定咱們的輸出是map類型仍是序列。

 

對於序列,在輸出第一個元素以前,咱們須要輸出」[「字符,在最後一個元素輸出以後在後面添加」]」字符。

fs<<」strings」<<」[「;

fs<<」image1.jpg」<<」Awesomeness」MM」baboon,jpg」l

fs<<」]」;

 

對於map

 

Fs<<」Mapping」;

Fs<<」{「<<」One」<<1;

Fs<<」Two」」<<2<<」}」;

 

爲了讀取他們,咱們使用FileNodeFileNodeIterator數據結構。FileStorage類的[]操做符返回了FileNode數據類型。若是節點是序列化的,咱們能夠使用FIleNodeIterator來遍歷他們:

FileNode n=fs[「strings」];

If(n.type()!=FileNode::SEQ)

{

cerr<<」string is not sequence!Fail」<<endl;

return 1;
}

FileNodeIterator it=n.begin(),it_end=n.end();

for(;it!=it_end;++it)

cout<<(string)*it<<endl;

 

對於map你能夠再次使用[]操做符讀取他們(或者再次使用>>操做符):

N=fs[「Mapping」];

Cout<<」Two」<<(int)(n[「Two」])<<」;」;

Cout<<」One」<<(int)(n[「One」])<<endl<<endl;

 

五、讀寫你本身的數據結構。假設你有這樣的數據結構:

Class MyData

{

Public:

MyData():A(0),X(0),id(){}

Public:

Int A;

Double X;

String id;
};

 

經過添加在你的類中和類外添加一個read函數和一個write函數使用OpenCVI/O XML或者YAML接口(就像是OpenCV數據結構同樣)也能夠將其序列化:

Void write(FileStorage&fs)const

{

fs<<」{「<<」A」<<A<<」X」<<X<<」id」<<id<<」}」;
}

 

Void read(const FileNode&node)

{

A=(int)node[「A」];

X=(double)node[「X」];

Id=(string)node[「id」];
}

你一樣須要在類外添加這樣的函數定義:

 

Void write(FileStorage&fs,const std::string&,const MyData&x)

{

X.write(fs);
}

Void read(const FileNode&noe,MyData&x,const MyData&default_value=MyData()) 

{

If(node.empyt())

X=default_value;

Else

X.read(node);
}

在這裏,你能夠看到在讀的層次咱們定義出了若是用戶試圖去讀一個不存在的借點的狀況。這這個狀況下,咱們只是返回了默認的初始化值。然而一個更冗長的解決辦法應該是返回一個負的對象ID實例的數值。

你一旦添加了這四個,就能夠使用>>操做符用於寫以及<<操做符用於讀:

 

MyData m(1);

Fs<<」MyData」<<m;

Fs[「MyData」]>>m;

 

或者去嘗試讀取一個不存在的:

Fs[「NonExisting」]>>m;

Cout<<endl<<」NonExisting=」<<endl<<m<<endl;

 

結果

很好的輸出了大部分咱們定好的數字。在控制檯的屏幕上,你能夠看到:

相關文章
相關標籤/搜索