内容简介:输入输出(input out),也称io操作。在c++编程里有学过io的知识点,主要是两种,一个是控制台io,即std::cout与std::cin等标准输入输出流的操作。这一种io的操作作用是实现数据在内存与控制台显示的传输。另一个是文件io,即iftream与ofstream对象文件输入输出流的操作,这一种io操作的作用是实现数据在内存与硬盘文件的传输。那么在opencv里面也是一样的,一样拥有这控制台与文件的两种io操作方式。只不过有所不同的是,opencv里面的数据结构有所不同,io操作的输入输出
输入输出(input out),也称io操作。在c++编程里有学过io的知识点,主要是两种,一个是控制台io,即std::cout与std::cin等标准输入输出流的操作。这一种io的操作作用是实现数据在内存与控制台显示的传输。另一个是文件io,即iftream与ofstream对象文件输入输出流的操作,这一种io操作的作用是实现数据在内存与硬盘文件的传输。
那么在opencv里面也是一样的,一样拥有这控制台与文件的两种io操作方式。只不过有所不同的是,opencv里面的数据结构有所不同,io操作的输入输出流对象、文件流对象有所不一样,即被定制化了而已。原理与使用方式在本质上是一只的。
源代码程序
下面先附上代码解释
//包含头文件 #include <opencv2/core.hpp> #include <iostream> #include <string> //使用命名空间,不建议这么做,建议显示使用,如cv::imshow using namespace cv; using namespace std; //显示帮助信息 static void help(char** av) { cout << endl << av[0] << " shows the usage of the OpenCV serialization functionality." << endl << "usage: " << endl << av[0] << " outputfile.yml.gz" << endl << "The output file may be either XML (xml) or YAML (yml/yaml). You can even compress it by " << "specifying this in its extension like xml.gz yaml.gz etc... " << endl << "With FileStorage you can serialize objects in OpenCV by using the << and >> operators" << endl << "For example: - create a class and have it serialized" << endl << " - use it to read and write matrices." << endl; } //数据类 class MyData { public: MyData() : A(0), X(0), id()//构造函数 {} explicit MyData(int) : A(97), X(CV_PI), id("mydata1234") // 显示构造函数,防止隐式调用 {} 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"]; } public: // Data Members //数据成员 int A; double X; string id; }; //写数据函数,为静态函数,函数内调用类内成员函数 static void write(FileStorage& fs, const std::string&, const MyData& x) { x.write(fs); } //读取数据函数,为静态函数,函数内调用类内成员函数 static 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 //重载<<运算符 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 ac, char** av) { //检查输入参数 if (ac != 2) { help(av); return 1; } string filename = av[1];//文件路径名 //把MyData类对象的数据写到文件里面 { 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" << "../data/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 //打开文件读取数据到MyData类对象 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; //读取MyData类数据 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; }
程序详解
下面来一步一步地学习解读程序
自定义数据类
-
首先,程序声明里一个数据类来作为后面的io操作提供数据封装的实体。类的声明如下
//数据类 class MyData { public: MyData() : A(0), X(0), id()//构造函数 {} explicit MyData(int) : A(97), X(CV_PI), id("mydata1234") // 显示构造函数,防止隐式调用 {} 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"]; } public: // Data Members //数据成员 int A; double X; string id; };
类包含了三个不同类型的数据成员,默认构造函数与显示构造函数,以及write和read两个成员函数,分别承担写入与读取功能。需要明白的是,write写入函数是将MyData的数据成员写入到FileStorage对象fs中,read读取函数是从FileNode对象node读取数据存到MyData之中。Filestorage与FileNode即为opencv中所“定制化的io操作类”。附上解释
FileStorage&FileNode
//FileStorage XML/YAML/JSON file storage class that encapsulates all the information necessary for writing or reading data to/from a file. //FileNode File Storage Node class. The node is used to store each and every element of the file storage opened for reading. When XML/YAML file is read, it is first parsed and stored in the memory as a hierarchical collection of nodes. Each node can be a "leaf" that is contain a single number or a string, or be a collection of other nodes. There can be named collections (mappings) where each element has a name and it is accessed by a name, and ordered collections (sequences) where elements do not have names but rather accessed by index. Type of the file node can be determined using FileNode::type method. Note that file nodes are only used for navigating file storages opened for reading. When a file storage is opened for writing, no data is stored in memory after it is written.
而且,还在类外对读写两个函数再次进行了封装
//写数据函数,为静态函数,函数内调用类内成员函数 static void write(FileStorage& fs, const std::string&, const MyData& x) { x.write(fs); } //读取数据函数,为静态函数,函数内调用类内成员函数 static 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 //重载<<运算符 static ostream& operator<<(ostream& out, const MyData& m) { out << "{ id = " << m.id << ", "; out << "X = " << m.X << ", "; out << "A = " << m.A << "}"; return out; }
这个重载的作用英文注释已经解释了,作用即将MyData类对象m里面的数据打印显示到控制台屏幕上面,从函数的原型也可以看得出,参数包含ostream对象与MyData对象,从而把MyData对象数据传到输出流ostream对象上面,结果自然是与std::cout一样内容显示到控制台屏幕上面。
文件读写
-
最后我们来看看本次主题,opencv怎么进行文件的读写操作。
程序中读文件和写文件所用到的类是FileStorage
//FileStorage XML/YAML/JSON file storage class that encapsulates all the information necessary for writing or reading data to/from a file.
这里可以看到,FileStorage读写文件的格式是XML/YAML/JSON类型的数据格式,这些数据格式有着比较明显的特点
//XML <!-- Copyright w3school.com.cn --> <note> <to>George</to> <from>John</from> <heading>Reminder</heading> <body>Don't forget the meeting!</body> </note> //YAML --- # 一位职工记录 name: Example Developer job: Developer skill: Elite employed: True foods: - Apple - Orange - Strawberry - Mango languages: ruby: Elite python: Elite dotnet: Lame //JSON "firstName" : "John" { "firstName":"John" , "lastName":"Doe" } { "employees": [ { "firstName":"John" , "lastName":"Doe" }, { "firstName":"Anna" , "lastName":"Smith" }, { "firstName":"Peter" , "lastName":"Jones" } ] }
程序中读写操作的是json格式的文件。来学习一下具体的文件读写操作
首先是文件的打开方式
FileStorage fs(filename, FileStorage::WRITE);//以写的方式打开文件 FileStorage fs; fs.open(filename, FileStorage::READ);//以读的方式打开文件
接着是读写json格式文件
//一对一键值对读写 fs << "iterationNr" << 100;//写到文件 itNr = (int) fs["iterationNr"];//从文件读取出来 cout << itNr; //中括号数组形式的读写 //写到文件 fs << "strings" << "["; // text - string sequence fs << "image1.jpg" << "Awesomeness" << "../data/baboon.jpg"; fs << "]"; // close sequence //从文件读取出来 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; //花括号json对象的读写 //写文件 fs << "Mapping"; // text - mapping fs << "{" << "One" << 1; fs << "Two" << 2 << "}"; //读文件 n = fs["Mapping"]; // Read mappings from a sequence cout << "Two " << (int)(n["Two"]) << "; "; cout << "One " << (int)(n["One"]) << endl << endl; //矩阵以及MyData类数据的读写 fs << "R" << R; // cv::Mat fs << "T" << T; fs << "MyData" << m; fs["R"] >> R; // Read cv::Mat fs["T"] >> T; //读取MyData类数据 fs["MyData"] >> m;
程序运行的结果如下
控制台会显示如下内容
打开写入的文件,内容如下
重载运算符
-
最后,来学习一下如何给自定义类去重载<<、>>运算符
重载>>
class Date { int mo, da, yr; public: Date(int m, int d, int y) { mo = m; da = d; yr = y; } friend ostream& operator<<(ostream& os, const Date& dt); }; istream& operator>> ( istream& is, Date& dt ) { is >> dt.mo >> dt.da >> dt.yr; return is; }
重载<<
ostream& operator<<(ostream& os, const Date& dt) { os << dt.mo << '/' << dt.da << '/' << dt.yr; return os; }
总结回顾
io操作一般有内存变量与控制台和内存变量与硬盘文件两类,opencv中实现操作的类为FileStorage和FileNode等。FileStorage支持读写的文件格式为XML/YAML/JSON,json数据格式有单一键值对、中括号数组格式和花括号json对象格式。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- laravel自带用户认证
- Mac自带apache配置
- opencv自带例子学习-图像混合
- Golang中自带的强大命令工具
- Android调用系统自带的分享功能
- 使用oracle自带的命令进行导入导出
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Deep Learning
Ian Goodfellow、Yoshua Bengio、Aaron Courville / The MIT Press / 2016-11-11 / USD 72.00
"Written by three experts in the field, Deep Learning is the only comprehensive book on the subject." -- Elon Musk, co-chair of OpenAI; co-founder and CEO of Tesla and SpaceX Deep learning is a for......一起来看看 《Deep Learning》 这本书的介绍吧!