OpenCV学习笔记:输入输出XML和YAML文件
2013-08-18 21:22
519 查看
你将得到以下几个问题的答案:
如何将文本写入YAML或XML文件,及如何从OpenCV中读取YAML或XML文件中的文本
如何利用YAML或XML文件存取OpenCV数据结构
如何利用YAML或XML文件存取自定义数据结构?
OpenCV中相关数据结构的使用方法,如 :xmlymlpers:FileStorage <filestorage>, FileNode 或 FileNodeIterator.
你可以 点击此处下载 或直接从OpenCV代码库中找到源文件。 samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp 。
以下用简单的示例代码演示如何逐一实现所有目的.
这里我们仅讨论XML和YAML文件输入。你的输出(和相应的输入)文件可能仅具有其中一个扩展名以及对应的文件结构。XML和YAML的串行化分别采用两种不同的数据结构: mappings (就像STL map) 和 element sequence (比如 STL vector>。二者之间的区别在map中每个元素都有一个唯一的标识名供用户访问;而在sequences中你必须遍历所有的元素才能找到指定元素。
XML\YAML 文件的打开和关闭。 在你写入内容到此类文件中前,你必须先打开它,并在结束时关闭它。在OpenCV中标识XML和YAML的数据结构是 FileStorage 。要将此结构和硬盘上的文件绑定时,可使用其构造函数或者 open() 函数:
无论以哪种方式绑定,函数中的第二个参数都以常量形式指定你要对文件进行操作的类型,包括:WRITE, READ 或 APPEND。文件扩展名决定了你将采用的输出格式。如果你指定扩展名如 .xml.gz ,输出甚至可以是压缩文件。
当 FileStorage 对象被销毁时,文件将自动关闭。当然你也可以显示调用 release 函数:
输入\输出文本和数字。 数据结构使用与STL相同的 << 输出操作符。输出任何类型的数据结构时,首先都必须指定其标识符,这通过简单级联输出标识符即可实现。基本类型数据输出必须遵循此规则:
读入则通过简单的寻址(通过 [] 操作符)操作和强制转换或 >> 操作符实现:
输入\输出OpenCV数据结构。 其实和对基本类型的操作方法是相同的:
输入\输出 vectors(数组)和相应的maps. 之前提到我们也可以输出maps和序列(数组, vector)。同样,首先输出变量的标识符,接下来必须指定输出的是序列还是map。
对于序列,在第一个元素前输出”[“字符,并在最后一个元素后输出”]“字符:
对于maps使用相同的方法,但采用”{“和”}“作为分隔符。
对于数据读取,可使用 FileNode 和 FileNodeIterator 数据结构。 FileStorage 的[]
操作符将返回一个 FileNode 数据类型。如果这个节点是序列化的,我们可以使用 FileNodeIterator 来迭代遍历所有元素。
对于maps类型,可以用 [] 操作符访问指定的元素(或者 >> 操作符):
读写自定义数据类型。 假设你定义了如下数据类型:
添加内部和外部的读写函数,就可以使用OpenCV I/O XML/YAML接口对其进行序列化(就像对OpenCV数据结构进行序列化一样)。内部函数定义如下:
接下来在类的外部定义以下函数:
这儿可以看到,如果读取的节点不存在,我们返回默认值。更复杂一些的解决方案是返回一个对象ID为负值的实例。
一旦添加了这四个函数,就可以用 >> 操作符和 << 操作符分别进行读,写操作:
或试着读取不存在的值:
好的,大多情况下我们只输出定义过的成员。在控制台程序的屏幕上,你将看到:
然而, 在输出的xml文件中看到的结果将更加有趣:
或YAML文件:
如何将文本写入YAML或XML文件,及如何从OpenCV中读取YAML或XML文件中的文本
如何利用YAML或XML文件存取OpenCV数据结构
如何利用YAML或XML文件存取自定义数据结构?
OpenCV中相关数据结构的使用方法,如 :xmlymlpers:FileStorage <filestorage>, FileNode 或 FileNodeIterator.
代码
你可以 点击此处下载 或直接从OpenCV代码库中找到源文件。 samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp 。以下用简单的示例代码演示如何逐一实现所有目的.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | #include <opencv2/core/core.hpp> #include <iostream> #include <string> using namespace cv; using namespace std; class MyData { public: MyData(): A(0), X(0), id() {} explicit MyData(int) : A(97), X(CV_PI), id("mydata1234") // explicit 避免隐式类型转换 {} void write(FileStorage& fs) const //Write serialization for this class { fs << "{" << "A" << A << "X" << X << "id" << id << "}"; } void read(const FileNode& node) //Read serialization for this class { A = (int)node["A"]; X = (double)node["X"]; id = (string)node["id"]; } public: // Data Members int A; double X; string id; }; //These write and read functions must be defined for the serialization in FileStorage to work 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); } // This function will print our custom class to the console ostream& operator<<(ostream& out, const MyData& m) { out << "{ id = " << m.id << ", "; out << "X = " << m.X << ", "; out << "A = " << m.A << "}"; return out; } int main(int ac, char** av) { if (ac != 2) { help(av); return 1; } string filename = av[1]; { //write Mat R = Mat_<uchar>::eye(3, 3), T = Mat_<double>::zeros(3, 1); MyData m(1); FileStorage fs(filename, FileStorage::WRITE); fs << "iterationNr" << 100; fs << "strings" << "["; // text - string sequence fs << "image1.jpg" << "Awesomeness" << "baboon.jpg"; fs << "]"; // close sequence fs << "Mapping"; // text - mapping fs << "{" << "One" << 1; fs << "Two" << 2 << "}"; fs << "R" << R; // cv::Mat fs << "T" << T; fs << "MyData" << m; // your own data structures fs.release(); // explicit close cout << "Write Done." << endl; } {//read cout << endl << "Reading: " << endl; FileStorage fs; fs.open(filename, FileStorage::READ); int itNr; //fs["iterationNr"] >> itNr; itNr = (int) fs["iterationNr"]; cout << itNr; if (!fs.isOpened()) { cerr << "Failed to open " << filename << endl; help(av); return 1; } FileNode n = fs["strings"]; // Read string sequence - Get node if (n.type() != FileNode::SEQ) { cerr << "strings is not a sequence! FAIL" << endl; return 1; } FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node for (; it != it_end; ++it) cout << (string)*it << endl; n = fs["Mapping"]; // Read mappings from a sequence cout << "Two " << (int)(n["Two"]) << "; "; cout << "One " << (int)(n["One"]) << endl << endl; MyData m; Mat R, T; fs["R"] >> R; // Read cv::Mat fs["T"] >> T; fs["MyData"] >> m; // Read your own structure_ cout << endl << "R = " << R << endl; cout << "T = " << T << endl << endl; cout << "MyData = " << endl << m << endl << endl; //Show default behavior for non existing nodes cout << "Attempt to read NonExisting (should initialize the data structure with its default)."; fs["NonExisting"] >> m; cout << endl << "NonExisting = " << endl << m << endl; } cout << endl << "Tip: Open up " << filename << " with a text editor to see the serialized data." << endl; return 0; } |
代码分析
这里我们仅讨论XML和YAML文件输入。你的输出(和相应的输入)文件可能仅具有其中一个扩展名以及对应的文件结构。XML和YAML的串行化分别采用两种不同的数据结构: mappings (就像STL map) 和 element sequence (比如 STL vector>。二者之间的区别在map中每个元素都有一个唯一的标识名供用户访问;而在sequences中你必须遍历所有的元素才能找到指定元素。XML\YAML 文件的打开和关闭。 在你写入内容到此类文件中前,你必须先打开它,并在结束时关闭它。在OpenCV中标识XML和YAML的数据结构是 FileStorage 。要将此结构和硬盘上的文件绑定时,可使用其构造函数或者 open() 函数:
string filename = "I.xml"; FileStorage fs(filename, FileStorage::WRITE); \\... fs.open(filename, FileStorage::READ);
无论以哪种方式绑定,函数中的第二个参数都以常量形式指定你要对文件进行操作的类型,包括:WRITE, READ 或 APPEND。文件扩展名决定了你将采用的输出格式。如果你指定扩展名如 .xml.gz ,输出甚至可以是压缩文件。
当 FileStorage 对象被销毁时,文件将自动关闭。当然你也可以显示调用 release 函数:
fs.release(); // 显示关闭
输入\输出文本和数字。 数据结构使用与STL相同的 << 输出操作符。输出任何类型的数据结构时,首先都必须指定其标识符,这通过简单级联输出标识符即可实现。基本类型数据输出必须遵循此规则:
fs << "iterationNr" << 100;
读入则通过简单的寻址(通过 [] 操作符)操作和强制转换或 >> 操作符实现:
int itNr; fs["iterationNr"] >> itNr; itNr = (int) fs["iterationNr"];
输入\输出OpenCV数据结构。 其实和对基本类型的操作方法是相同的:
Mat R = Mat_<uchar >::eye (3, 3), T = Mat_<double>::zeros(3, 1); fs << "R" << R; // 写 cv::Mat fs << "T" << T; fs["R"] >> R; // 读 cv::Mat fs["T"] >> T;
输入\输出 vectors(数组)和相应的maps. 之前提到我们也可以输出maps和序列(数组, vector)。同样,首先输出变量的标识符,接下来必须指定输出的是序列还是map。
对于序列,在第一个元素前输出”[“字符,并在最后一个元素后输出”]“字符:
fs << "strings" << "["; // 文本 - 字符串序列 fs << "image1.jpg" << "Awesomeness" << "baboon.jpg"; fs << "]"; // 序列结束
对于maps使用相同的方法,但采用”{“和”}“作为分隔符。
fs << "Mapping"; // 文本 - mapping fs << "{" << "One" << 1; fs << "Two" << 2 << "}";
对于数据读取,可使用 FileNode 和 FileNodeIterator 数据结构。 FileStorage 的[]
操作符将返回一个 FileNode 数据类型。如果这个节点是序列化的,我们可以使用 FileNodeIterator 来迭代遍历所有元素。
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"]) << "; "; cout << "One " << (int)(n["One"]) << endl << endl;
读写自定义数据类型。 假设你定义了如下数据类型:
class MyData { public: MyData() : A(0), X(0), id() {} public: // 数据成员 int A; double X; string id; };
添加内部和外部的读写函数,就可以使用OpenCV I/O XML/YAML接口对其进行序列化(就像对OpenCV数据结构进行序列化一样)。内部函数定义如下:
void write(FileStorage& fs) const //对自定义类进行写序列化 { fs << "{" << "A" << A << "X" << X << "id" << id << "}"; } void read(const FileNode& node) //从序列读取自定义类 { A = (int)node["A"]; X = (double)node["X"]; id = (string)node["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); }
这儿可以看到,如果读取的节点不存在,我们返回默认值。更复杂一些的解决方案是返回一个对象ID为负值的实例。
一旦添加了这四个函数,就可以用 >> 操作符和 << 操作符分别进行读,写操作:
MyData m(1); fs << "MyData" << m; // 写自定义数据结构 fs["MyData"] >> m; // 读自定义数据结构
或试着读取不存在的值:
fs["NonExisting"] >> m; // 请注意不是 fs << "NonExisting" << m cout << endl << "NonExisting = " << endl << m << endl;
结果
好的,大多情况下我们只输出定义过的成员。在控制台程序的屏幕上,你将看到:Write Done. Reading: 100image1.jpg Awesomeness baboon.jpg Two 2; One 1 R = [1, 0, 0; 0, 1, 0; 0, 0, 1] T = [0; 0; 0] MyData = { id = mydata1234, X = 3.14159, A = 97} Attempt to read NonExisting (should initialize the data structure with its default). NonExisting = { id = , X = 0, A = 0} Tip: Open up output.xml with a text editor to see the serialized data.
然而, 在输出的xml文件中看到的结果将更加有趣:
<?xml version="1.0"?> <opencv_storage> <iterationNr>100</iterationNr> <strings> image1.jpg Awesomeness baboon.jpg</strings> <Mapping> <One>1</One> <Two>2</Two></Mapping> <R type_id="opencv-matrix"> <rows>3</rows> <cols>3</cols> <dt>u</dt> <data> 1 0 0 0 1 0 0 0 1</data></R> <T type_id="opencv-matrix"> <rows>3</rows> <cols>1</cols> <dt>d</dt> <data> 0. 0. 0.</data></T> <MyData> <A>97</A> <X>3.1415926535897931e+000</X> <id>mydata1234</id></MyData> </opencv_storage>
或YAML文件:
%YAML:1.0 iterationNr: 100 strings: - "image1.jpg" - Awesomeness - "baboon.jpg" Mapping: One: 1 Two: 2 R: !!opencv-matrix rows: 3 cols: 3 dt: u data: [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ] T: !!opencv-matrix rows: 3 cols: 1 dt: d data: [ 0., 0., 0. ] MyData: A: 97 X: 3.1415926535897931e+000 id: mydata1234
相关文章推荐
- OpenCV_(4):输入输出XML和YAML文件
- (17)Air Band OpenCV2.4.13_用xml和yaml文件进行输入和输出
- OpenCV之core 模块. 核心功能(2)基本绘图 随机数发生器&绘制文字 离散傅立叶变换 输入输出XML和YAML文件 与 OpenCV 1 同时使用
- OpenCV实践(7)- XML和YAML文件的输入输出
- OpenCV 输入输出XML和YAML文件
- 输入输出XML和YAML文件
- OpenCV学习笔记(六)——对XML和YAML文件实现I/O操作
- (转)MyBatis框架的学习(四)——Mapper.xml文件中的输入和输出映射以及动态sql
- opencv学习笔记(二)-对xml和yaml文件的读写操作
- 数据库操作_连接SQL Server数据库示例;连接ACCESS数据库;连接到 Oracle 数据库示例;SqlCommand 执行SQL命令示例;SqlDataReader 读取数据示例;使用DataAdapter填充数据到DataSet;使用DataTable存储数据库表;将数据库数据填充到 XML 文件;10 使用带输入参数的存储过程;11 使用带输入、输出参数的存储过程示;12 获得数据库中表的数目和名称;13 保存图片到SQL Server数据库示例;14 获得插入记录标识号;Exce
- opencv(c++)文件输入和输出使用XML和YAML文件
- MyBatis框架的学习(四)——Mapper.xml文件中的输入和输出映射以及动态sql
- MyBatis框架的学习(四)——Mapper.xml文件中的输入和输出映射以及动态sql
- Opencv输出XML和YAML文件
- 使用XML文件输入和输出和YAML文件 目标 你会发现以下问题的答案: 如何打印和阅读文本条目文件和OpenCV使用YAML或XML文件? 如何为OpenCV做同样的数据结构?
- OpenCV学习笔记——对XML和YAML文件实现I/O操作
- 输入输出文件
- 使用XlmWrite把一个xml文件写入输出流中。在(demo2.aspx运行时显示xml文档)
- Java实现读取键盘输入保存到txt文件,再统计并输出每个单词出现次数的方法
- C例程:文件读写 拷贝 标准输入输出等