学习OpenCV范例(九)——输入输出XML和YAML文件

前端之家收集整理的这篇文章主要介绍了学习OpenCV范例(九)——输入输出XML和YAML文件前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

在OpenCV的学习中,经常会用到文件的输入输出,特别是XML和YAML格式的输出文件,如果大家有做过人脸识别就可以体会到,用主分量分析法得到的特征脸、平均脸等等数据都会被保存成为XML格式,方便下次使用时调用,OpenCV2版本比OpenCV1版本省去了很多函数,大家通过OpenCV中文网就可以查到,而且OpenCV2版本的输入输出使用与STL相同的 <</>> 输入/输出操作符,实现起来非常简单,在学习的过程中要特别注意,输入输出是map数据结构还是sequence数据结构,这两种结构上的操作会有所不同,现在我们就看看范例吧。

1、代码实现

#include "stdafx.h"


#include <opencv2/core/core.hpp>
#include <iostream>
#include <string>

using namespace cv;
using namespace std;

static void help()
{
	cout << endl
		<<" shows the usage of the OpenCV serialization functionality."         << endl
		<< "usage: "                                                                      << endl
		<<  " 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") // explicit to avoid implicit conversion
	{}
	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
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)
{

	string filename = "F:\\OpenCV2.4.8\\file_input_output\\file_input_output\\input_output.xml";
	{ //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();
			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;
	char ch=NULL;
	while (ch!='c')
	{
		cin>>ch;
	}
	return 0;
}

2、运行结果


图1、运行结果


图2、文件格式

3、总结

范例很简单,大家看看就可以明白了,这里强调的两点是:

①、输入输出sequence还是map

sequence:输入操作:在第一个元素前输出“[”字符,并在最后一个元素后输出“]”字符。如:

fs << "strings" << "[";                              // 文本 - 字符串序列
fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";
fs << "]";                                           // 序列结束
输出操作: 可使用 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;
map: 输入操作: 采用”{“和”}“作为分隔符。如:

fs << "Mapping";                              // 文本 - mapping
fs << "{" << "One" << 1;
fs <<        "Two" << 2 << "}";
输出操作: 可以用 [] 操作符访问指定的元素(或者 >> 操作符)。如:

n = fs["Mapping"];                                // 从序列中读取map
cout << "Two  " << (int)(n["Two"]) << "; ";
cout << "One  " << (int)(n["One"]) << endl << endl;

②、读写自定义类型

读写自定义类型时,需要自己写内部和外部的读写函数,学完后就可以使用OpenCV I/O XML/YAML接口对其进行序列化(就像对OpenCV数据结构进行序列化一样)。

4、用到的类和函数

FileStorage:

功能文件存储结构

当OpenCV想打开或保存文件时,可以使用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();

FileNode:

功能:体现了文件存储的每一个元素。

FileStorage 的[] 操作符将返回一个 FileNode 数据类型,它可以是一个矩阵、数据、头结点等等,包含了所有的文件内容,而文件节点的类型可以通过FileNode::type()方法获得。

FileNodeIterator:

功能文件迭代遍历

可以通过它迭代遍历所有元素,具体功能见前面代码,之前博客也有介绍过迭代遍历,功能方法都差不多。

猜你在找的XML相关文章