• OpenCV持久化(二)


    如何利用OpenCV持久化自己的数据结构?我们来看看OpenCV中的一个例子

    MyData.hpp定义自己的数据结构MyData如下:

    #ifndef MYDATA_HPP
    #define MYDATA_HPP
    
    #include <opencv2/core/core.hpp>
    #include <iostream>
    #include <string>
    
    using namespace std;
    using namespace cv;
    
    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;
    }
    
    #endif // MYDATA_HPP

    注意,外部静态函数 write 和 read 必须定义,即:

    static void write(FileStorage& fs, const std::string&, const MyData& x);
    static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData());

    原因稍后说明。

    主函数main.cpp如下:
     1 #include <QtCore/QCoreApplication>
     2 #include "MyData.hpp"
     3 
     4 int main(int argc, char *argv[])
     5 {
     6 //    QCoreApplication a(argc, argv);
     7 //    return a.exec();
     8 
     9       string filename = "../file/test.xml";
    10       { //write
    11           Mat R = Mat_<uchar>::eye(3, 3),
    12               T = Mat_<double>::zeros(3, 1);
    13           MyData m(1);
    14 
    15           FileStorage fs(filename, FileStorage::WRITE);
    16 
    17           fs << "iterationNr" << 100;
    18           fs << "strings" << "[";                              // text - string sequence
    19           fs << "image1.jpg" << "Awesomeness" << "baboon.jpg";
    20           fs << "]";                                           // close sequence
    21 
    22           fs << "Mapping";                              // text - mapping
    23           fs << "{" << "One" << 1;
    24           fs <<        "Two" << 2 << "}";
    25 
    26           fs << "R" << R;                                      // cv::Mat
    27           fs << "T" << T;
    28 
    29           fs << "MyData" << m;                                // your own data structures
    30 
    31           fs.release();                                       // explicit close
    32           cout << "Write Done." << endl;
    33       }
    34 
    35       {//read
    36           cout << endl << "Reading: " << endl;
    37           FileStorage fs;
    38           fs.open(filename, FileStorage::READ);
    39 
    40           int itNr;
    41           //fs["iterationNr"] >> itNr;
    42           itNr = (int) fs["iterationNr"];
    43           cout << itNr;
    44           if (!fs.isOpened())
    45           {
    46               cerr << "Failed to open " << filename << endl;
    47               //help(av);
    48               return 1;
    49           }
    50 
    51           FileNode n = fs["strings"];                         // Read string sequence - Get node
    52           if (n.type() != FileNode::SEQ)
    53           {
    54               cerr << "strings is not a sequence! FAIL" << endl;
    55               return 1;
    56           }
    57 
    58           FileNodeIterator it = n.begin(), it_end = n.end(); // Go through the node
    59           for (; it != it_end; ++it)
    60               cout << (string)*it << endl;
    61 
    62 
    63           n = fs["Mapping"];                                // Read mappings from a sequence
    64           cout << "Two  " << (int)(n["Two"]) << "; ";
    65           cout << "One  " << (int)(n["One"]) << endl << endl;
    66 
    67 
    68           MyData m;
    69           Mat R, T;
    70 
    71           fs["R"] >> R;                                      // Read cv::Mat
    72           fs["T"] >> T;
    73           fs["MyData"] >> m;                                 // Read your own structure_
    74 
    75           cout << endl
    76               << "R = " << R << endl;
    77           cout << "T = " << T << endl << endl;
    78           cout << "MyData = " << endl << m << endl << endl;
    79 
    80           //Show default behavior for non existing nodes
    81           cout << "Attempt to read NonExisting (should initialize the data structure with its default).";
    82           fs["NonExisting"] >> m;
    83           cout << endl << "NonExisting = " << endl << m << endl;
    84       }
    85 
    86       cout << endl
    87           << "Tip: Open up " << filename << " with a text editor to see the serialized data." << endl;
    88 
    89       return 0;
    90 }

    可以看到第29行: fs << "MyData" << m; 

    当执行到 fs << "MyData" 时,将调用OpenCV源码operations.hpp中的输出操作符:

    static inline FileStorage& operator << (FileStorage& fs, const char* str)

    返回 FileStorage 的引用,继续输入自定义的数据m时,将调用operations.hpp中的模板函数:

     1 template<typename _Tp> static inline FileStorage& operator << (FileStorage& fs, const _Tp& value)
     2 {
     3     if( !fs.isOpened() )
     4         return fs;
     5     if( fs.state == FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP )
     6         CV_Error( CV_StsError, "No element name has been given" );
     7     write( fs, fs.elname, value );
     8     if( fs.state & FileStorage::INSIDE_MAP )
     9         fs.state = FileStorage::NAME_EXPECTED + FileStorage::INSIDE_MAP;
    10     return fs;
    11 }

    可以看到第7行:write( fs, fs.elname, value );

    在operations.hpp中,可以看到两个OpenCV导出函数:

    CV_EXPORTS_W void write( FileStorage& fs, const string& name, const Mat& value );
    CV_EXPORTS void write( FileStorage& fs, const string& name, const SparseMat& value );
    CV_EXPORTS_W void read(const FileNode& node, Mat& mat, const Mat& default_mat=Mat() );
    CV_EXPORTS void read(const FileNode& node, SparseMat& mat, const SparseMat& default_mat=SparseMat() );

    回到上面的问题,为什么必须要定义外部静态函数write和read:

    static void write(FileStorage& fs, const std::string&, const MyData& x);
    static void read(const FileNode& node, MyData& x, const MyData& default_value = MyData());

    因此,我们在MyData.hpp中定义的外部静态函数write和read重载了OpenCV中operations.hpp的read和write函数。

    所以,上述调用第7行:write( fs, fs.elname, value ) 将调用我们自己定义的 write和read 函数。然后如MyData.hpp所示,在MyData类内部定义方法实现自定义数据结构的持久化。

    而对外接口用起来就像 fs << "MyData" << m; 这句这么简单。

    最后输出结果如下:

    当你心中只有一个目标时,全世界都会给你让路!Read more! Write more! Practise more! 新浪微博:liu_军
  • 相关阅读:
    android学习日记28--Android中常用设计模式总结
    android学习日记27--Dialog使用及其设计模式
    android学习日记26--AIDL之进程间的通信
    android学习日记25--ANR和Hander消息机制
    android学习日记24--Android 菜单开发
    android学习日记23--Android XML解析
    android学习日记22--Animation动画简介
    android学习日记21--消息提示之Toast和Notification
    编写高质量JS代码中
    博客建站的几点思考
  • 原文地址:https://www.cnblogs.com/liu-jun/p/3495872.html
Copyright © 2020-2023  润新知