利用opencv的FileStorage类实现XML/YAML文件的读写
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; }