FileStorage是opencv2.0以后專門用來讀寫XML/YAML文件的類,標准的C++實現。利用好XML文件可以極大地方便我們對中間數據的處理。
官方文檔:
(2) http://docs.opencv.org/modules/core/doc/xml_yaml_persistence.html#filestorage
利用FileStorage主要可以完成對以下幾種數據的的輸入和輸出:數字、文本(字符串)、數組(vector)、maps、自定義數據類型(類)。與C++標准輸入輸出流的操作方法基本一致: 建立流對象-->打開文件(建立流與文件的連接)-->進行讀或寫操作-->關閉文件(斷開流與文件的連接)。
使用過程中需要注意以下幾點:
(1)打開文件的時候要指定是"WRITE"還是"READ",一旦指定就只能讀或寫。寫完了要讀或者讀完了要寫前,要先對流對象進行重定向(可以使用FileStorage::open()方法);
(2)讀寫可以使用重載的<<和>>操作符,與C++風格保持了一致;
(3)FileStorage的[]操作符返回一個FileNode數據類型,如果該節點是序列化的(vector),可以使用FileNodeIterator來迭代遍歷該節點所有元素;
(4)每次將FileStorage對象重定向到"WRITE"后,都會從頭開始寫,即會覆蓋之前的全部內容;
(5)讀寫自定義的數據類型(自定義類)時,要分別添加內部和外部的讀寫函數,外部的讀寫函數相當於對FileStorage對象的插入“<<”和提取“>>”運算符的重載,它們又調用了自定義類的內部讀寫函數,完成對數據成員的讀寫。
以下是我的實驗代碼:
#include <opencv2/core/core.hpp> #include <iostream> #include <string> using namespace std; using namespace cv; class MyData //用戶自定義類 { public: MyData() : A(0), X(0), id() {} MyData(int i) : X(0), id() { A = i; } public: int A; double X; string id; public: //添加內部讀寫函數 void write(FileStorage& fs) const { fs << "{" ; fs << "A" << A ; fs << "X" << X ; fs << "id" << id; fs << "}"; } void read(const FileNode& node) { A = (int)(node["A"]); X = (double)(node["X"]); id = (string)(node["id"]); /*node["A"] >> A; node["X"] >> X; node["id"] >> id;*/ } }; //添加外部讀寫函數 void write(FileStorage& fs, const std::string&, const MyData& x) { x.write(fs); } void read(const FileNode& node, MyData& x, const MyData& default_value = MyData()) { if(node.empty()) x = default_value; else x.read(node); } //重載<<操作符用於向標准輸出流輸出自定義類 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 argc, char* argv[]) { //打開XML文件 string filename = "I.xml"; //------------(1)------------ FileStorage fs(filename, FileStorage::WRITE); //------------(2)------------ //fs.open(filename, FileStorage::READ); //----------------簡單數據結構輸入輸出---------------- //輸出數字和文本 fs << "iterationNr" << 100; //輸入數字和文本 //fs.open(filename, FileStorage::READ); //不要忘記將fs重定向為"READ" //int itNr; //------------(1)------------ //fs["iterationNr"] >> itNr; //------------(2)------------ //itNr = (int)fs["iterationNr"]; //cout<<"iterationNr "<<itNr; //輸出大型數據結構Mat Mat R = Mat_<uchar >::eye (3, 3), T = Mat_<double>::zeros(3, 1); fs << "R" << R; fs << "T" << T; //輸入Mat //fs.open(filename, FileStorage::READ); //不要忘記將fs重定向為"READ" //fs["R"] >> R; //fs["T"] >> T; //---------------------------------------------------------- //----------------復雜數據結構輸入輸出---------------- //輸出數組(vector) fs<<"strings"; fs<<"["; fs<<"image1.jpg"<<"Awesomeness"<<"baboon.jpg"; fs<<"]"; //輸出maps fs<<"Mapping"; fs<<"{"; fs<<"One"<<1; fs<<"Two"<<2; fs<<"}"; //輸入數組 //fs.open(filename, FileStorage::READ); //不要忘記將fs重定向為"READ" //FileNode n = fs["strings"]; // 讀取字符串序列 - 獲取節點 //if (n.type() != FileNode::SEQ) //{ // cerr << "strings 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; ////輸入maps //n = fs["Mapping"]; // 從序列中讀取map //cout << "Two " << (int)(n["Two"]) << endl; //cout << "One " << (int)(n["One"]) << endl; //---------------------------------------------------------- //----------------自定義類輸入輸出---------------- MyData m(1); //向文件輸出 fs << "MyData" << m; //由文件輸入 fs.open(filename, FileStorage::READ); //不要忘記將fs重定向為"READ" fs["MyData"] >> m; fs["NonExisting"] >> m; // 請注意不是 fs << "NonExisting" << m cout << endl << "NonExisting = " << endl << m << endl; //---------------------------------------------------------- //關閉XML文件 fs.release(); return 0; }