当保存浮点数据或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<CvFileStorage> fs; //!< the underlying C FileStorage structure string elname; //!< the currently written element vector<char> 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、写入映射、序列嵌套的数据时,以"{:"代替"{","[:" 代替 "["。