当保存浮点数据或XML/YML文件时,OpenCV的接口提供了FileStorage类。

       开始XML & YAML I/O 分析:

       下面贴上FileStorage类的源码。

class CV_EXPORTS_W FileStorage { public:     //! file storage mode     enum     {         READ=0, //! read mode         WRITE=1, //! write mode         APPEND=2, //! append mode         MEMORY=4,         FORMAT_MASK=(7<<3),         FORMAT_AUTO=0,         FORMAT_XML=(1<<3),         FORMAT_YAML=(2<<3)     };     enum     {         UNDEFINED=0,         VALUE_EXPECTED=1,         NAME_EXPECTED=2,         INSIDE_MAP=4     };     //! the default constructor     CV_WRAP FileStorage();     //! the full constructor that opens file storage for reading or writing     CV_WRAP FileStorage(const string& source, int flags, const string& encoding=string());     //! the constructor that takes pointer to the C FileStorage structure     FileStorage(CvFileStorage* fs);     //! the destructor. calls release()     virtual ~FileStorage();      //! opens file storage for reading or writing. The previous storage is closed with release()     CV_WRAP virtual bool open(const string& filename, int flags, const string& encoding=string());     //! returns true if the object is associated with currently opened file.     CV_WRAP virtual bool isOpened() const;     //! closes the file and releases all the memory buffers     CV_WRAP virtual void release();     //! closes the file, releases all the memory buffers and returns the text string     CV_WRAP string releaseAndGetString();      //! returns the first element of the top-level mapping     CV_WRAP FileNode getFirstTopLevelNode() const;     //! returns the top-level mapping. YAML supports multiple streams     CV_WRAP FileNode root(int streamidx=0) const;     //! returns the specified element of the top-level mapping     FileNode operator[](const string& nodename) const;     //! returns the specified element of the top-level mapping     CV_WRAP FileNode operator[](const char* nodename) const;      //! returns pointer to the underlying C FileStorage structure     CvFileStorage* operator *() { return fs; }     //! returns pointer to the underlying C FileStorage structure     const CvFileStorage* operator *() const { return fs; }     //! writes one or more numbers of the specified format to the currently written structure     void writeRaw( const string& fmt, const uchar* vec, size_t len );     //! writes the registered C structure (CvMat, CvMatND, CvSeq). See cvWrite()     void writeObj( const string& name, const void* obj );      //! returns the normalized object name for the specified file name     static string getDefaultObjectName(const string& filename);      Ptr fs; //!< the underlying C FileStorage structure     string elname; //!< the currently written element     vector structs; //!< the stack of written structures     int state; //!< the writer state }; 

 FileNode 存储XML或YAML文件中的每个节点,并用于读写。

class CV_EXPORTS_W_SIMPLE FileNode { public:     //! type of the file storage node     enum     {         NONE=0, //!< empty node         INT=1, //!< an integer         REAL=2, //!< floating-point number         FLOAT=REAL, //!< synonym or REAL         STR=3, //!< text string in UTF-8 encoding         STRING=STR, //!< synonym for STR         REF=4, //!< integer of size size_t. Typically used for storing complex dynamic structures where some elements reference the others         SEQ=5, //!< sequence         MAP=6, //!< mapping         TYPE_MASK=7,         FLOW=8, //!< compact representation of a sequence or mapping. Used only by YAML writer         USER=16, //!< a registered object (e.g. a matrix)         EMPTY=32, //!< empty structure (sequence or mapping)         NAMED=64 //!< the node has a name (i.e. it is element of a mapping)     };     //! the default constructor     CV_WRAP FileNode();     //! the full constructor wrapping CvFileNode structure.     FileNode(const CvFileStorage* fs, const CvFileNode* node);     //! the copy constructor     FileNode(const FileNode& node);     //! returns element of a mapping node     FileNode operator[](const string& nodename) const;     //! returns element of a mapping node     CV_WRAP FileNode operator[](const char* nodename) const;     //! returns element of a sequence node     CV_WRAP FileNode operator[](int i) const;     //! returns type of the node     CV_WRAP int type() const;      //! returns true if the node is empty     CV_WRAP bool empty() const;     //! returns true if the node is a "none" object     CV_WRAP bool isNone() const;     //! returns true if the node is a sequence     CV_WRAP bool isSeq() const;     //! returns true if the node is a mapping     CV_WRAP bool isMap() const;     //! returns true if the node is an integer     CV_WRAP bool isInt() const;     //! returns true if the node is a floating-point number     CV_WRAP bool isReal() const;     //! returns true if the node is a text string     CV_WRAP bool isString() const;     //! returns true if the node has a name     CV_WRAP bool isNamed() const;     //! returns the node name or an empty string if the node is nameless     CV_WRAP string name() const;     //! returns the number of elements in the node, if it is a sequence or mapping, or 1 otherwise.     CV_WRAP size_t size() const;     //! returns the node content as an integer. If the node stores floating-point number, it is rounded.     operator int() const;     //! returns the node content as float     operator float() const;     //! returns the node content as double     operator double() const;     //! returns the node content as text string     operator string() const;      //! returns pointer to the underlying file node     CvFileNode* operator *();     //! returns pointer to the underlying file node     const CvFileNode* operator* () const;      //! returns iterator pointing to the first node element     FileNodeIterator begin() const;     //! returns iterator pointing to the element following the last node element     FileNodeIterator end() const;      //! reads node elements to the buffer with the specified format     void readRaw( const string& fmt, uchar* vec, size_t len ) const;     //! reads the registered object and returns pointer to it     void* readObj() const;      // do not use wrapper pointer classes for better efficiency     const CvFileStorage* fs;     const CvFileNode* node; }; 
节点操作申明。

/*!  File Node Iterator   The class is used for iterating sequences (usually) and mappings.  */ class CV_EXPORTS FileNodeIterator { public:     //! the default constructor     FileNodeIterator();     //! the full constructor set to the ofs-th element of the node     FileNodeIterator(const CvFileStorage* fs, const CvFileNode* node, size_t ofs=0);     //! the copy constructor     FileNodeIterator(const FileNodeIterator& it);     //! returns the currently observed element     FileNode operator *() const;     //! accesses the currently observed element methods     FileNode operator ->() const;      //! moves iterator to the next node     FileNodeIterator& operator ++ ();     //! moves iterator to the next node     FileNodeIterator operator ++ (int);     //! moves iterator to the previous node     FileNodeIterator& operator -- ();     //! moves iterator to the previous node     FileNodeIterator operator -- (int);     //! moves iterator forward by the specified offset (possibly negative)     FileNodeIterator& operator += (int ofs);     //! moves iterator backward by the specified offset (possibly negative)     FileNodeIterator& operator -= (int ofs);      //! reads the next maxCount elements (or less, if the sequence/mapping last element occurs earlier) to the buffer with the specified format     FileNodeIterator& readRaw( const string& fmt, uchar* vec,                                size_t maxCount=(size_t)INT_MAX );      const CvFileStorage* fs;     const CvFileNode* container;     CvSeqReader reader;     size_t remaining; }; 


测试源码:

// open file storage for writing. Type of the file is determined from the extension  FileStorage fs("test.yml", FileStorage::WRITE);  fs << "test_int" << 5 << "test_real" << 3.1 << "test_string" << "ABCDEFGH";  fs << "test_mat" << Mat::eye(3,3,CV_32F);   fs << "test_list" << "[" << 0.0000000000001 << 2 << CV_PI << -3435345 << "2-502 2-029 3egegeg" <<  "{:" << "month" << 12 << "day" << 31 << "year" << 1969 << "}" << "]";  fs << "test_map" << "{" << "x" << 1 << "y" << 2 << "width" << 100 << "height" << 200 << "lbp" << "[:";   const uchar arr[] = {0, 1, 1, 0, 1, 1, 0, 1};  fs.writeRaw("u", arr, (int)(sizeof(arr)/sizeof(arr[0])));   fs << "]" << "}";
读入数据如下:

\verbatim
 %YAML:1.0
 test_int: 5
 test_real: 3.1000000000000001e+00
 test_string: ABCDEFGH
 test_mat: !!opencv-matrix
     rows: 3
     cols: 3
     dt: f
     data: [ 1., 0., 0., 0., 1., 0., 0., 0., 1. ]
 test_list:
     - 1.0000000000000000e-13
     - 2
     - 3.1415926535897931e+00
     - -3435345
     - "2-502 2-029 3egegeg"
     - { month:12, day:31, year:1969 }
 test_map:
     x: 1
     y: 2
     width: 100
     height: 200
     lbp: [ 0, 1, 1, 0, 1, 1, 0, 1 ]
 \endverbatim

读入源码:

// open file storage for reading.  // Type of the file is determined from the content, not the extension  FileStorage fs("test.yml", FileStorage::READ);  int test_int = (int)fs["test_int"];  double test_real = (double)fs["test_real"];  string test_string = (string)fs["test_string"];   Mat M;  fs["test_mat"] >> M;   FileNode tl = fs["test_list"];  CV_Assert(tl.type() == FileNode::SEQ && tl.size() == 6);  double tl0 = (double)tl[0];  int tl1 = (int)tl[1];  double tl2 = (double)tl[2];  int tl3 = (int)tl[3];  string tl4 = (string)tl[4];  CV_Assert(tl[5].type() == FileNode::MAP && tl[5].size() == 3);   int month = (int)tl[5]["month"];  int day = (int)tl[5]["day"];  int year = (int)tl[5]["year"];   FileNode tm = fs["test_map"];   int x = (int)tm["x"];  int y = (int)tm["y"];  int width = (int)tm["width"];  int height = (int)tm["height"];   int lbp_val = 0;  FileNodeIterator it = tm["lbp"].begin();   for(int k = 0; k < 8; k++, ++it)     lbp_val |= ((int)*it) << k;

1、XML和YAML可以嵌套的两种集合类型:映射(mappings)、序列(sequences)。映射集合类似STL中的std::map和Python中的字典,序列集合类似STL中std::vector和 Python的序列;

2、当写入映射结构的数据时,节点的值(value)紧跟着节点的键(key);当写入序列结构的数据时,逐一写入即可;

3、写入映射结构数据时,格式如下:fs << "{" << element_key << element_value << "}"

4、写入序列结构数据时,格式如下:fs << "[" << element_value << …… << "]"

5、写入映射、序列嵌套的数据时,以"{:"代替"{","[:" 代替 "["。