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;

 

结果

很好的输出了大部分咱们定好的数字。在控制台的屏幕上,你能够看到:

相关文章
相关标签/搜索