Improving Opencv 8: The Core Functionality :File Input and Output using XML and YAML files

目录

Goal

Explanation

XML/YAML File Open and Close.

Input and Output of text and numbers.

Input/Output of OpenCV Data structures. 

Read and write your own data structures

Python

C++


Goal

You'll find answers for the following questions:

  • How to print and read text entries to a file and OpenCV using YAML or XML files?
  • How to do the same for OpenCV data structures?
  • How to do this for your data structures?
  • Usage of OpenCV data structures such as cv::FileStorage , cv::FileNode or cv::FileNodeIterator .

Explanation

XML/YAML File Open and Close.

 Before you write any content to such file you need to open it and at the end to close it. The XML/YAML data structure in OpenCV is cv::FileStorage . 

Input and Output of text and numbers.

In C++, the data structure uses the << output operator in the STL library. In Python, cv::FileStorage::write() is used instead. For outputting any type of data structure we need first to specify its name. We do this by just simply pushing the name of this to the stream in C++. In Python, the first parameter for the write function is the name. For basic types you may follow this with the print of the value :

  fs << "iterationNr" << 100;



s.write('iterationNr', 100)

Reading in is a simple addressing (via the [] operator) and casting operation or a read via the >> operator. In Python, we address with getNode() and use real() :

        int itNr;
        //fs["iterationNr"] >> itNr;
        itNr = (int) fs["iterationNr"];

Input/Output of OpenCV Data structures. 

Well these behave exactly just as the basic C++ and Python types:

 Mat R = Mat_<uchar>::eye(3, 3),
            T = Mat_<double>::zeros(3, 1);
        fs << "R" << R;                                      // cv::Mat
        fs << "T" << T;
        fs["R"] >> R;                                      // Read cv::Mat
        fs["T"] >> T;




R = np.eye(3,3)
    T = np.zeros((3,1))
    s.write ('R_MAT', R)
    s.write ('T_MAT', T)
    R = s.getNode('R_MAT').mat()
    T = s.getNode('T_MAT').mat()

Read and write your own data structures

class MyData
{
public:
      MyData() : A(0), X(0), id() {}
public:   // Data Members
   int A;
   double X;
   string id;
};

 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"];
    }

//In C++, you need to add the following functions definitions outside the class:

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);
}



class MyData:
    def __init__(self):
        self.A = self.X = 0
        self.name = '

    def write(self, fs):
        fs.write('MyData','{')
        fs.write('A', self.A)
        fs.write('X', self.X)
        fs.write('name', self.name)
        fs.write('MyData','}')
    def read(self, node):
        if (not node.empty()):
            self.A = int(node.getNode('A').real())
            self.X = node.getNode('X').real()
            self.name = node.getNode('name').string()
        else:
            self.A = self.X = 0
            self.name = ''

Once you added these four functions use the >> operator for write and the << operator for read (or the defined input/output functions for Python):

  MyData m(1);
        fs << "MyData" << m;                                // your own data structures
        fs["MyData"] >> m;                                 // Read your own structure_
//Or to try out reading a non-existing read:

        cout << "Attempt to read NonExisting (should initialize the data structure with its default).";
        fs["NonExisting"] >> m;
        cout << endl << "NonExisting = " << endl << m << endl;
 m = MyData()
    m.write(s)
    m.read(s.getNode('MyData'))
Or to try out reading a non-existing read:

    print ('Attempt to read NonExisting (should initialize the data structure',
            'with its default).')
    m.read(s.getNode('NonExisting'))
    print ('\nNonExisting =','\n',m)

Python

from __future__ import print_function

import numpy as np
import cv2 as cv
import sys

def help(filename):
    print (
        '''
        {0} shows the usage of the OpenCV serialization functionality. \n\n
        usage:\n
            python3 {0} outputfile.yml.gz\n\n
        The output file may be either in XML, YAML or JSON. You can even compress it\n
        by specifying this in its extension like xml.gz yaml.gz etc... With\n
        FileStorage you can serialize objects in OpenCV.\n\n
        For example: - create a class and have it serialized\n
                     - use it to read and write matrices.\n
        '''.format(filename)
    )



def main(argv):
    if len(argv) != 2:
        help(argv[0])
        exit(1)

    # write
    ## [iomati]
    R = np.eye(3,3)
    T = np.zeros((3,1))
    intNum = np.random.randint(0, 100, 6)


    filename = argv[1]

    ## [open]
    s = cv.FileStorage(filename, cv.FileStorage_WRITE)
    # or:
    # s = cv.FileStorage()
    # s.open(filename, cv.FileStorage_WRITE)
    ## [open]

    ## [writeNum]
    s.write('iterationNr', 100)
    ## [writeNum]



    ## [iomatw]
    s.write('R_MAT', R)
    s.write('T_MAT', T)
    s.write("intnum", intNum)
    ## [iomatw]


    s.release()
    ## [close]
    print ('Write Done.')

    # read
    print ('\nReading: ')
    s = cv.FileStorage()
    s.open(filename, cv.FileStorage_READ)

    ## [readNum]
    n = s.getNode('iterationNr')
    itNr = int(n.real())
    ## [readNum]
    print (itNr)

    R = s.getNode("R_MAT").mat()
    print('R=', R)

    num = s.getNode("intnum").mat()
    print('intnum = ', num)
    print(num.shape)



    if (not s.isOpened()):
        print ('Failed to open ', filename, file=sys.stderr)
        help(argv[0])
        exit(1)

    ## [readStr]
    n = s.getNode('strings')
    if (not n.isSeq()):
        print ('strings is not a sequence! FAIL', file=sys.stderr)
        exit(1)




if __name__ == '__main__':
    main(sys.argv)

按快捷键:alt+shift+F10调出运行窗口,之后选择Edit Configurations或者按0

Run/Debug Configurations->Configurations->Parameters

RWxml.xml

<?xml version="1.0"?>
<opencv_storage>
<iterationNr>100</iterationNr>
<R_MAT type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>d</dt>
  <data>
    1. 0. 0. 0. 1. 0. 0. 0. 1.</data></R_MAT>
<T_MAT type_id="opencv-matrix">
  <rows>3</rows>
  <cols>1</cols>
  <dt>d</dt>
  <data>
    0. 0. 0.</data></T_MAT>
<intnum type_id="opencv-matrix">
  <rows>6</rows>
  <cols>1</cols>
  <dt>i</dt>
  <data>
    5 73 58 52 91 43</data></intnum>
</opencv_storage>

结果

F:\Anaconda\envs\PythonBuffer\python.exe F:/PythonBuffer/first.py RWxml.xml
Write Done.
strings is not a sequence! FAIL

Reading: 
100
R= [[1. 0. 0.]
 [0. 1. 0.]
 [0. 0. 1.]]
intnum =  [[ 5]
 [73]
 [58]
 [52]
 [91]
 [43]]
(6, 1)

Process finished with exit code 1

C++

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

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") // explicit to avoid implicit conversion
	{}
	//! [inside]
	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"];
	}
	//! [inside]
public:   // Data Members
	int A;
	double X;
	string id;
};

//These write and read functions must be defined for the serialization in FileStorage to work
//! [outside]
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);
}
//! [outside]

// 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];
	string filename = "xmlFile.xml";
	{ //write
		//! [iomati]
		Mat R = Mat_<uchar>::eye(3, 3),
			T = Mat_<double>::zeros(3, 1);
		//! [iomati]
		//! [customIOi]
		MyData m(1);
		//! [customIOi]

		//! [open]
		FileStorage fs(filename, FileStorage::WRITE);
		// or:
		// FileStorage fs;
		// fs.open(filename, FileStorage::WRITE);
		//! [open]

		//! [writeNum]
		fs << "iterationNr" << 100;
		//! [writeNum]
		//! [writeStr]
		fs << "strings" << "[";                              // text - string sequence
		fs << "image1.jpg" << "Awesomeness" << "../data/baboon.jpg";
		fs << "]";                                           // close sequence
		//! [writeStr]

		fs << "poem" << "[";
		fs << "丙辰中秋,欢饮达旦,大醉,作此篇,兼怀子由。" << \
			"明月几时有?把酒问青天。不知天上宫阙,今夕是何年。" << \
			"我欲乘风归去,又恐琼楼玉宇,高处不胜寒。" << \
			"起舞弄清影,何似在人间。转朱阁,低绮户,照无眠。" << \
			"不应有恨,何事长向别时圆 ?" << \
			"人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。";
		fs << "]";



		//! [writeMap]
		fs << "Mapping";                              // text - mapping
		fs << "{" << "One" << 1;
		fs << "Two" << 2 << "}";
		//! [writeMap]

		//! [iomatw]
		fs << "R" << R;                                      // cv::Mat
		fs << "T" << T;
		//! [iomatw]

		//! [customIOw]
		fs << "MyData" << m;                                // your own data structures
		//! [customIOw]

		//! [close]
		fs.release();                                       // explicit close
		//! [close]
		cout << "Write Done." << endl;
	}

	{//read
		cout << endl << "Reading: " << endl;
		FileStorage fs;
		fs.open(filename, FileStorage::READ);

		//! [readNum]
		int itNr;
		//fs["iterationNr"] >> itNr;
		itNr = (int)fs["iterationNr"];
		//! [readNum]
		cout << itNr << endl;
		if (!fs.isOpened())
		{
			cerr << "Failed to open " << filename << endl;
			help(av);
			return 1;
		}

		////! [readStr]
		//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;
		////! [readStr]

		//! [readStr]
		FileNode poem = fs["poem"];                         // Read string sequence - Get node
		if (poem.type() != FileNode::SEQ)
		{
			cerr << "strings is not a sequence! FAIL" << endl;
			return 1;
		}

		FileNodeIterator it = poem.begin(), it_end = poem.end(); // Go through the node
		for (; it != it_end; ++it)
			cout << (string)*it << endl;
		//! [readStr]


		//! [readMap]
		//n = fs["Mapping"];                                // Read mappings from a sequence
		//cout << "Two  " << (int)(n["Two"]) << "; ";
		//cout << "One  " << (int)(n["One"]) << endl << endl;
		//! [readMap]


		MyData m;
		Mat R, T;

		//! [iomat]
		fs["R"] >> R;                                      // Read cv::Mat
		fs["T"] >> T;
		//! [iomat]
		//! [customIO]
		fs["MyData"] >> m;                                 // Read your own structure_
		//! [customIO]

		cout << endl
			<< "R = " << R << endl;
		cout << "T = " << T << endl << endl;
		cout << "MyData = " << endl << m << endl << endl;

		//Show default behavior for non existing nodes
		//! [nonexist]
		cout << "Attempt to read NonExisting (should initialize the data structure with its default).";
		fs["NonExisting"] >> m;
		cout << endl << "NonExisting = " << endl << m << endl;
		//! [nonexist]
	}

	cout << endl
		<< "Tip: Open up " << filename << " with a text editor to see the serialized data." << endl;

	return 0;
}

xmlFile.xml

<?xml version="1.0"?>
<opencv_storage>
<iterationNr>100</iterationNr>
<strings>
  image1.jpg Awesomeness "../data/baboon.jpg"</strings>
<poem>
  "丙辰中秋,欢饮达旦,大醉,作此篇,兼怀子由。"
  "明月几时有?把酒问青天。不知天上宫阙,今夕是何年。"
  "我欲乘风归去,又恐琼楼玉宇,高处不胜寒。"
  "起舞弄清影,何似在人间。转朱阁,低绮户,照无眠。"
  "不应有恨,何事长向别时圆 ?"
  "人有悲欢离合,月有阴晴圆缺,此事古难全。但愿人长久,千里共婵娟。"</poem>
<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>

猜你喜欢

转载自blog.csdn.net/moonlightpeng/article/details/107162557