cv::FileStorage读写文件

#转载于https://blog.csdn.net/learning_tortosie/article/details/97815514

文章目录

  • 数据存储
    • cv::FileStorage的写入
    • 使用cv::FileStorage读取文件
    • cv::FileNode
  • 参考

数据存储

OpenCV提供了一种序列化和反序列化的机制,用于将不同数据类型的数据以YAML或XML格式写入磁盘或者从磁盘读取。这种方法可以用来加载或者保存任何OpenCV的数值变量(包括基本数据变量,像int和float等)到一个文件中。

上述文件读写的基本机制是建立在cv::FileStorage对象基础上的,cv::FileStorage实际代表磁盘中的一个文件,但与普通方式不同的是,它让人们以一种简单而自然的方式访问文件中的数据。

cv::FileStorage的写入

cv::FileStorage对象代表一个YAML或XML格式的文件。你可以给定文件名参数创建一个cv::FileStorage对象或者使用默认构造函数创建一个未打开的cv::FileStorage对象,稍后再使用cv::FileStorage::open()函数打开。flag参数可以为cv::FileStorage::WRITE或cv::FileStorage::APPEND。

FileStorage::open(string fileName, int flag);

   
     
     
     
     
  • 1

一旦成功打开了你想要写入的文件,便可以像对标准输出流输出数据一样使用操作符cv::FileStorage::operator<<()进行写入操作。你可以以这种简单的方式写入,是因为函数内部为你完成了许多复杂的工作。

cv::FileStorage内部数据的存储主要有两种方式,“mapping”(键/值对)和“sequence”(一系列未命名的条目)。在最顶层,你写入的数据都在一个mapping中,你可以放置其他的mapping或sequence,甚至在mapping中继续放入mapping等,只要你愿意。

myFileStorage << "someInteger" << 27;                               //保存一个整数
myFileStorage << "anArray" << cv::Mat::eye(3,3,CV_32F);             //保存一个数组

   
     
     
     
     
  • 1
  • 2

如果要创建一个序列条目,首先你得为它提供一个string类型的名字,接下来才是序列数据。条目内容可以是数字(整型或浮点型等),一个字符串或别的OpenCV数据类型。

如果你要创建一个新的mapping或sequence,可以使用特殊符号{(用于mapping)或[(用于sequence)。一旦开始创建,就可以为其添加元素,最终以}或]分别结束一个mapping或sequence。

myFileStorage << "theCat" << "{";
myFileStorage << "fur" << "gray" << "eyes" << "green" << "weightLbs" << 16;
myFileStorage << "}";

   
     
     
     
     
  • 1
  • 2
  • 3

一旦完成创建一个mapping,需要按顺序输入条目名以及对应的值。如果创建的是sequence,只需要一个接一个地输入元素即可,知道sequence结束。

myFileStorage << “theTeam" << "[";
myFileStorage << "eddie" << "tom" << "scott";
myFileStorage << "]";

   
     
     
     
     
  • 1
  • 2
  • 3

一旦完成写工作,便可以使用成员函数cv::FileStorage::release()关闭文件。

示例:使用cv::FileStorage创建一个test.yaml文件

#include 
#include 

using namespace cv;

int main() {

FileStorage fs("test.yaml", FileStorage::WRITE);

fs << "frameCount" << 5;

time_t rawtime; time(&rawtime);
fs << "calibrationDate" << asctime(localtime(&rawtime));

Mat cameraMatrix = (
        Mat_<double>(3,3)
                << 1000, 0, 320, 0, 1000, 240, 0, 0, 1
        );

Mat distCoeffs = (
        Mat_<double>(5,1)
                << 0.1, 0.01, -0.001, 0, 0
        );

fs << "cameraMatrix" << cameraMatrix << "distCoffes" << distCoeffs;

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" << "[:";
    for(int j = 0; j < 8; j++)
        fs << ((lbp >> j) & 1);
    fs << "]" << "}";
}
fs << "]";

fs.release();
return 0;

}

  • 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

CmakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project(write_yaml_using_FileStorage)

set(CMAKE_CXX_STANDARD 14)

set(OpenCV_DIR “/opt/ros/kinetic/share/OpenCV-3.3.1-dev”)
message(${ OpenCV_DIR})
find_package( OpenCV 3 REQUIRED )

add_executable(write_yaml_using_FileStorage main.cpp)

target_link_libraries( write_yaml_using_FileStorage ${ OpenCV_LIBS} )

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

程序运行结果如下:

%YAML:1.0
---
frameCount: 5
calibrationDate: "Tue Jul 30 20:48:34 2019\n"
cameraMatrix: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 1000., 0., 320., 0., 1000., 240., 0., 0., 1. ]
distCoffes: !!opencv-matrix
   rows: 5
   cols: 1
   dt: d
   data: [ 1.0000000000000001e-01, 1.0000000000000000e-02,
       -1.0000000000000000e-03, 0., 0. ]
features:
   - { x:103, y:166, lbp:[ 1, 0, 0, 1, 0, 1, 1, 0 ] }
   - { x:115, y:113, lbp:[ 1, 1, 1, 1, 1, 1, 1, 1 ] }
   - { x:586, y:12, lbp:[ 1, 0, 0, 1, 0, 1, 0, 0 ] }

 
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这个示例代码中,你会注意到有时候mapping或sequence的所有数据在一行,有时候每个元素一行。这并不是自动格式化造成的,而是由于mapping的起始字符"{:“和”}",sequence的起始字符"[:“和”]"的变化造成的。这个特点只对YAML格式的输出有意义,如果输出文件是XML格式,那么这些细微的差别将会被忽略,mapping与sequence的存储将不会有区别。

使用cv::FileStorage读取文件

cv::FileStorage对象在打开之后,既可以用来写入,也可以用来读取。唯一的区别是flag的值为cv::FileStorage::READ。跟写入时一样,也可以用默认构造函数创建一个未打开的FileStorage对象,之后再通过调用cv::FileStorage::open()函数打开。

FileStorage::open(string fileName, int flag);

 
   
   
   
   
  • 1

一旦文件被打开,接下来便可对其中的数据进行读取,首先需要确定你要访问的数据名
,即FileStorage最顶层的mapping中的关键字,可以通过重载操作符cv::FileStorage::operator获取自己需要的数据。然而,该操作符的返回值并不是你想要的数据,而是一个FileNode对象。

接下里,如果该值是基本数据类型,则可以通过强制类型转换直接读取,如果该数据是一个mapping对象,可以通过重载操作符[ ],并给定所需关键字访问,如果该数据为sequence对象,可以通过重载的[ ]和一个整型参数访问其中的数据,也可以通过cv::FileNodeIterator迭代器进行访问。在完成读取之后,记得调用成员函数cv::FileStorage::release()关闭文件。

cv::FileNode

当成功构建一个cv::FileNode对象后,便可以用它来完成许多工作。如果它直接表示一个实际的对象(或者一个数字或字符串),你就可以直接使用重载操作符cv::FileNode::operator>>(),将它的值加载到对应类型的变量中。

cv::Mat anArray;
myFileStorage["calibrationMatrix"] >> anArray;

 
   
   
   
   
  • 1
  • 2

cv::FileNode对象同样支持直接赋值给一些基本数据类型。

int aNumber;
myFileStorage["someInteger"] >> aNumber;

 
   
   
   
   
  • 1
  • 2

与下面这种方式等价:

int aNumber;
aNumber = (int)myFileStorage["someInteger"];

 
   
   
   
   
  • 1
  • 2

使用迭代器可以完成对FileNode的遍历。给定一个cv::FileNode对象,成员函数cv::FileNode::begin()和cv::FileNode::end()可以分别返回该mapping或sequence的首元素的迭代器和末尾元素的迭代器。该迭代对象可以通过cv::FileNodeIterator::operator*()操作符来进行解引用操作并返回迭代器对应的位置的FileNode对象。这些迭代器支持常见的自增以及自减操作符。

示例:使用cv::FileNode读取test.yaml文件

#include 

using namespace cv;
using namespace std;

int main(){
cv::FileStorage fs2(“test.yaml”, cv::FileStorage::READ);

int frameCount = (int)fs2["frameCount"];

std::string date;
fs2["calibrationDate"] >> date;

cv::Mat cameraMatrix, distCoeffs2;
fs2["cameraMatrix"] >> cameraMatrix;
fs2["distCoffes"] >> distCoeffs2;


cout << "frameCount: "         << frameCount     << endl
      << "calibration date: "   << date          << endl
      << "camera matrix: "      << cameraMatrix  << endl
      << "distoration coeffs: " << distCoeffs2   << endl;

cv::FileNode features = fs2["features"];
cv::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)["x"] << ", y=" << (int)(*it)["y"] << ", lbp: (";

    (*it)["lbp"] >> lbpval;
    for(int i = 0; i < (int)lbpval.size(); i++)
        cout << " " << (int)lbpval[i];
    cout << ")" << endl;
}
fs2.release();

}

  • 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

程序运行结果如下:
cv::FileStorage读写文件_第1张图片

参考

《学习OpenCV 3》(中文版)

你可能感兴趣的:(opencv,opencv)