OpenCV程式設計->FileStorage解析
當儲存浮點資料或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、寫入對映、序列巢狀的資料時,以"{:"代替"{","[:" 代替 "["。