加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

xml文件学习

发布时间:2020-12-16 09:10:44 所属栏目:百科 来源:网络整理
导读:输入输出XML和YAML文件 目的 你将得到以下几个问题的答案: 如何将文本写入YAML或XML文件,及如何从从OpenCV中读取YAML或XML文件中的文本 如何利用YAML或XML文件存取OpenCV数据结构 如何利用YAML或XML文件存取自定义数据结构? OpenCV中相关数据结构的使用方法

输入输出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;
namespace std;

class MyData
{
public:
    MyData() : A(0), X(id()
    {}
    explicit MyData(int) 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"];
    }
:   // Data Members
    int A;
    double X;
    string id;
};

//These write and read functions must be defined for the serialization in FileStorage to work
& fs, const std::string&,32); font-weight:bold">const MyData& x)
{
    x.write(fs);
}
& node, MyData& x,102)">& 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,102)">& m) 
{ 
    out "{ id = " << m.id ",";
    out "X = " << m.X "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 <double>::zeros(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,102)">::READ);

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

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

        FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node
        for (; it != it_end; ++it)
            cout << (string)*it << endl;
        
        
        n "Mapping"];                                // Read mappings from a sequence
        cout "Two  " << (int)(n["Two"]) "; "; 
        cout "One  " "One"]) << 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 "MyData = " << m << 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 "NonExisting = " << endl;
    }

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

    0;
}

代码分析

这里我们仅讨论XML和YAML文件输入。你的输出(和相应的输入)文件可能仅具有其中一个扩展名以及对应的文件结构。XML和YAML的串行化分别采用两种不同的数据结构:mappings(就像STL map) 和element sequence(比如 STL vector>。二者之间的区别在map中每个元素都有一个唯一的标识名供用户访问;而在sequences中你必须遍历所有的元素才能找到指定元素。

  1. XMLYAML 文件的打开和关闭。在你写入内容到此类文件中前,你必须先打开它,并在结束时关闭它。在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();                                       // 显示关闭
    
  2. 输入输出文本和数字。数据结构使用与STL相同的 << 输出操作符。输出任何类型的数据结构时,首先都必须指定其标识符,这通过简单级联输出标识符即可实现。基本类型数据输出必须遵循此规则:

    fs 100;

    读入则通过简单的寻址(通过 [] 操作符)操作和强制转换或 >> 操作符实现:

    int itNr; fs["iterationNr"] >> itNr; itNr "iterationNr"];
  3. 输入输出OpenCV数据结构。其实和对基本类型的操作方法是相同的:

    Mat R <uchar >::eye (T 1); fs // 写 cv::Mat fs << T; fs[// 读 cv::Mat fs[>> T;
  4. 输入输出 vectors(数组)和相应的maps.之前提到我们也可以输出maps和序列(数组,vector)。同样,首先输出变量的标识符,接下来必须指定输出的是序列还是map。

    对于序列,在第一个元素前输出”[“字符,并在最后一个元素后输出”]“字符:

    // 文本 - 字符串序列 fs "baboon.jpg"; fs // 序列结束

    对于maps使用相同的方法,但采用”{“和”}“作为分隔符。

    // 文本 - mapping fs 1; fs "}";

    对于数据读取,可使用FileNode和FileNodeIterator数据结构。FileStorage的[] 操作符将返回一个FileNode数据类型。如果这个节点是序列化的,我们可以使用FileNodeIterator来迭代遍历所有元素。

    FileNode n // 读取字符串序列 - 获取节点 ::SEQ) { cerr << endl; 1; } FileNodeIterator it // 遍历节点 ++it) cout << endl;

    对于maps类型,可以用 [] 操作符访问指定的元素(或者 >> 操作符):

    n // 从序列中读取map cout "; "; cout << endl;
  5. 读写自定义数据类型。假设你定义了如下数据类型:

    : MyData() id() {} // 数据成员 int A; double X; string id; };

    添加内部和外部的读写函数,就可以使用OpenCV I/O XML/YAML接口对其进行序列化(就像对OpenCV数据结构进行序列化一样)。内部函数定义如下:

    //对自定义类进行写序列化 { fs "}"; } //从序列读取自定义类 { A "A"]; X "X"]; id "id"]; }

    接下来在类的外部定义以下函数:

    & x) { x.write(fs); } = MyData()) { if(node.empty()) x = default_value; else x.read(node); }

    这儿可以看到,如果读取的节点不存在,我们返回默认值。更复杂一些的解决方案是返回一个对象ID为负值的实例。

    一旦添加了这四个函数,就可以用 >> 操作符和 << 操作符分别进行读,写操作:

    MyData m(1); fs << m; // 写自定义数据结构 fs[// 读自定义数据结构

    或试着读取不存在的值:

    fs[>> m; // 请注意不是 fs << "NonExisting" << m cout << endl;

结果

好的,大多情况下我们只输出定义过的成员。在控制台程序的屏幕上,你将看到:

Write Done.

Reading:
100image1.jpg
Awesomeness
baboon.jpg
Two  2; One  1


R = [1,0;
  0,1,1]
T [0; 0; 0]

MyData =
{ id = mydata1234,X = 3.14159,213)">A = 97}

Attempt to read NonExisting (should initialize the data structure with its default).
NonExisting =,102)">= 0,102)">= 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 <cols>1<dt>d<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,1 ]
T: !!opencv-matrix
   rows: 3
   cols: 1
   dt: d
   data: [ 0.,0.,0. ]
MyData:
   A: 97
   X: 3.1415926535897931e+000
   id: mydata1234
 
  

OpenCV FileStorage类读写XML/YML文件

在OpenCV程序中,需要保存中间结果的时候常常会使用.xml / .yml文件,opencv2.0之前都是使用C风格的代码,当时读写XML文件分别使用函数cvLoad()和cvSave()。在2.0以后的OpenCV转为支持C++,这一举措大大减少了代码量以及编程时需要考虑的细节。

新版本的OpenCV的C++接口中,imwrite()和imread()只能保存整数数据,且需要以图像格式。当需要保存浮点数据或者XML/YML文件时,之前的C语言接口cvSave()函数已经在C++接口中被删除,代替它的是FileStorage类。这个类非常的方便,封装了很多数据结构的细节,编程的时候可以根据统一的接口对数据结构进行保存。

1. FileStorage类写XML/YML文件

?新建一个FileStorage对象,以FileStorage::WRITE的方式打开一个文件。

? 使用 << 操作对该文件进行操作。

?释放该对象,对文件进行关闭。

例子如下:

    FileStorage fs("test.yml",FileStorage::WRITE);
    fs << frameCount" << 5;
    time_t rawtime; time(&rawtime);
    fs << calibrationDate" << asctime(localtime(&rawtime));
    Mat cameraMatrix = (Mat_<double>(3,3) << 1000,128); line-height:1.5!important">0,128); line-height:1.5!important">320,128); line-height:1.5!important">240,128); line-height:1.5!important">1); //又一种Mat初始化方式
    Mat distCoeffs = (Mat_<5,128); line-height:1.5!important">1) << 0.1,128); line-height:1.5!important">0.01,-0.001,128); line-height:1.5!important">0);
    fs << cameraMatrix" << cameraMatrix << distCoeffs" << distCoeffs;
    
    features为一个大小为3的向量,其中每个元素由随机数x,y和大小为8的uchar数组组成
    fs << features[";
    for( int i = 0; i < 3; i++ )
    {
        int x = rand() % 640;
        int y = rand() % 480;
        uchar lbp = rand() % 256;
        fs << {:x" << x << y" << y << lbp[:";
        int j = 0; j < 8; j++ )
            fs << ((lbp >> j) & 1);
        fs << ]}";
    }
    fs << ";
    fs.release();

2. FileStorage类读XML/YML文件

FileStorage对存储内容在内存中是以层次的节点组成的,每个节点类型为FileNode,FileNode可以使单个的数值、数组或者一系列FileNode的集合。FileNode又可以看做是一个容器,使用iterator接口可以对该节点内更小单位的内容进行访问,例如访问到上面存储的文件中"features"的内容。步骤与写文件类似:

? 新建FileStorage对象,以FileStorage::READ 方式打开一个已经存在的文件

? 使用FileStorage::operator []()函数对文件进行读取,或者使用FileNode和FileNodeIterator

? 使用FileStorage::release()对文件进行关闭

例子如下:

方式一: []操作符 int frameCount = (int)fs["]; 方式二: FileNode::operator >>() string date; fs["] >> date; Mat cameraMatrix2,distCoeffs2; fs["] >> cameraMatrix2; fs["] >> distCoeffs2; 注意FileNodeIterator的使用,似乎只能用一维数组去读取里面所有的数据 FileNode features = fs["]; FileNodeIterator it = features.begin(),it_end = features.end(); int idx = 0; std::vector<uchar> lbpval; for( ; it != it_end; ++it,idx++ ) { cout << feature #" << idx << : "; cout << x=" << (int)(*it)["] << ,y="; (*it)["] >> lbpval; 直接读出一维向量 0; i < (int)lbpval.size(); i++ ) cout << " int)lbpval[i]; cout << )" << endl; } fs.release();

另外,注意在新建FileStorage对象之后,并以READ或WRITE模式打开文件之后,可以用FileStorage::isOpened()查看文件状态,判断是否成功打开了文件。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读