小记:静默如初,安之若素

opencv中的FileStorage使用

1. FileStorage的定义
FileStorage是opencv中提供的一种序列化与反序列化的机制,用于将不同数据类型的数据以YAML或者XML格式写入磁盘或者从磁盘中读取,这些方法可以用来加载或者保存任何opnecv的数据变量(包括基本数据变量,例如int 和 float等)

2. FileStorage的写入

1):声明对象
	FileStorage::FileStorage();
	FileStorage::FileStorage(string filename, int flag);
	//filename : 表示写入的文件名, 
	//flag设为:cv::FileStorage::WRITE 或者 cv::FileStorage::APPEND
2):打开文件: 调用cv::FileStorage::open()函数;
3):写入数据: 调用cv::FileStorage::operator<<();
//cv::FilsStorage内部数据的存储形式:“mapping”(键/值对)和 “sequence”(一系列未命名的条目)
4):关闭文件:调用cv::FileStorage::release()函数关闭文件。

示例程序

1 #include <iostream>
  2 #include <opencv2/opencv.hpp>
  3 #include <ctime>
  4 using namespace std;
  5 
  6 int main(int argc, char * argv[])
  7 {
      //数据写入
  8   cv::FileStorage fs("test.yaml", cv::FileStorage::WRITE);
  9 
 10   fs << "frameCount" << 5;
 11 
 12   time_t rawtime;
 13   time(&rawtime);
 14   fs<< "calibrationDate" << asctime(localtime(&rawtime));
 15 
 16   cv::Mat cameraMatrix = (
 17    cv::Mat_<double>(3, 3)
 18    << 1000, 0, 320, 0, 1000, 240, 0, 0, 1
 19   );
 20 
 21   cv::Mat distCoeffs = (
 22     cv::Mat_<double>(5, 1)
 23     << 0.1, 0.01, -0.001, 0, 0
 24   );
 25  
 26   fs << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs;
 27  
 28   fs << "features" << "[";
 29   for(int i = 0; i < 3; i++)
 30   {
 31     int x = rand() % 640;
 32     int y = rand() % 480;
 33     uchar lbp = rand() % 256; 
 34     fs << "{:" << "x" << x << "y" << y << "lbp" << "[:";
 35     for(int j = 0; j < 8; j++)
 36     {
 37       fs << ((lbp >> j) & 1);
 38     }
 39     fs << "]" << "}";
 40   }
 41  
 42   fs << "]";
 43   fs.release();
 44   return 0;
 45  }

3. 使用cv::FileStorage读取文件

1):声明对象,此处与打开的区别是flag的参数设为:cv::FileStorage::READ
	FileStorage::FileStorage();
	FileStorage::FileStorage(string filename, int flag);
2):打开文件: 调用cv::FileStorage::open()函数;
3):读取数据: 
3.1)读取数据时首先需要确认要读取的数据名,即FileStorage最顶层的mapping关键字
     可以通过调用cv::FileStorage::operator获取所需的数据;
    (注:操作符直接返回的值是一个FileNode对象,而不是所想要的数据,需要进一步转换才可以)
3.2)数据转换:
     基本类型可以直接进行强制类型转换;
     mapping对象需要通过重载操作符[],并给定所需关键字进行访问;
     sequence对象可以通过重载的[]和一个整型参数进行数据访问,也可以通过cv::FileNodeIterator迭代器进行数据访问。
//cv::FilsStorage内部数据的存储形式:“mapping”(键/值对)和 “sequence”(一系列未命名的条目)
4):关闭文件:调用cv::FileStorage::release()函数关闭文件。

示例程序

1 #include <iostream>
  2 #include <opencv2/opencv.hpp>
  3 #include <ctime>
  4 using namespace std;
  5 
  6 int main(int argc, char * argv[])
  7 {     
	  //数据读取
 45   cv::FileStorage fs2("test.yaml", cv::FileStorage::READ);
 46   
 47   int frameCount = (int)fs2["frameCount"];
 48   
 49   std::string data;
 50   fs2["calibrationDatea"] >> data;
 51   
 52   cv::Mat cameraMatrix2, distCoeffs2;
 53   fs2["cameraMatrix"] >> cameraMatrix2;
 54   fs2["distCoeffs"] >> distCoeffs2;
 55   
 56   cout << "frameCount : " << frameCount << endl
 57        << "calibration date : " << data << endl
 58        << "camera Matrix : " << cameraMatrix2 <<endl
 59        << "distCoeffs : " << distCoeffs2 << endl;
 60   cv::FileNode features = fs2["features"];
 61 
 62   cv::FileNodeIterator it = features.begin(), it_end = features.end();
 63   int idx = 0;
 64 
 65   std::vector<uchar> lbpval;
 66 
 67   for(; it != it_end; ++it, idx++)
 68   {
 69     cout << "features # " << idx << ":";
 70     cout << "x = " << (int)(*it)["x"] << ", y = " << (int)(*it)["y"] << ", lbp : (";
 71     (*it)["lbp"] >> lbpval;
 72     for(int i = 0; i < (int)lbpval.size(); i++)
 73     {
 74       cout << " " << (int)lbpval[i];
 75     }
 76     cout << ")" <<endl;
 77   }
 78   fs2.release();
 79   return 0;
 80 }

编译上述程序需要使用opencv库函数,下面提供一种通过CMakeList.txt进行编译的方式:
CMakeList.txt

1 cmake_minimum_required( VERSION 2.8 )
  2 project( opencvTest )
  3 
  4 set( CMAKE_BUILD_TYPE "Debug" )
  5 set( CMAKE_CXX_FLAGS "-std=c++11" )
  6 
  7 find_package(OpenCV REQUIRED)
  8 message(STATUS "Found Opencv: ${OpenCV_VERSION}")
  9 
 10 add_executable(opencvTest main.cc )
 11   target_link_libraries(opencvTest ${OpenCV_LIBS}

运行

mkdir build
cd build
./opencvTest

4. FileNode解释
CvFileNode;此结构只用于从文件存储器中检索数据使用(也就是用于从文件载入数据)。当数据被写入文件中时它将使用最小的缓存,顺序的完成。没有数据被存在文件存储器这结构中。
相反,当从文件中读数据时,所有文件在内存中像树一样被解析和描绘。树的每一个节点被CvFileNode表现出来。文件节点N的类型能够通过CV_NODE_TYPE(N->tag) 被重新找到。一些节点(叶结点)作为变量:字符串文本,整数,浮点数。其它的文件节点是集合文件节点,有两个类型集合:序列和图表 (我们这里使用 YAML 符号,无论用哪种方法,对于XML符号流也是同样有效)。序列(不要与CvSeq混淆) 是由有序的非指定文件节点(注:没有关键字)构成的,图表是由无序的指定文件节点(注:有关键字)构成的。因而 ,序列的数据是通过索引(cvGetSepElem)来存取,图形的数据是通过名字(cvGetFileNodeByName)来存取 。下表描述不同类型的节点:

/* 文件节点类型 */
#define CV_NODE_NONE        0
#define CV_NODE_INT         1
#define CV_NODE_INTEGER     CV_NODE_INT
#define CV_NODE_REAL        2
#define CV_NODE_FLOAT       CV_NODE_REAL
#define CV_NODE_STR         3
#define CV_NODE_STRING      CV_NODE_STR
#define CV_NODE_REF         4 /* not used */
#define CV_NODE_SEQ         5
#define CV_NODE_MAP         6
#define CV_NODE_TYPE_MASK   7

/* 可选标记 */
#define CV_NODE_USER        16
#define CV_NODE_EMPTY       32
#define CV_NODE_NAMED       64

#define CV_NODE_TYPE(tag)  ((tag) & CV_NODE_TYPE_MASK)

#define CV_NODE_IS_INT(tag)        (CV_NODE_TYPE(tag) == CV_NODE_INT)
#define CV_NODE_IS_REAL(tag)       (CV_NODE_TYPE(tag) == CV_NODE_REAL)
#define CV_NODE_IS_STRING(tag)     (CV_NODE_TYPE(tag) == CV_NODE_STRING)
#define CV_NODE_IS_SEQ(tag)        (CV_NODE_TYPE(tag) == CV_NODE_SEQ)
#define CV_NODE_IS_MAP(tag)        (CV_NODE_TYPE(tag) == CV_NODE_MAP)
#define CV_NODE_IS_COLLECTION(tag) (CV_NODE_TYPE(tag) >= CV_NODE_SEQ)
#define CV_NODE_IS_FLOW(tag)       (((tag) & CV_NODE_FLOW) != 0)
#define CV_NODE_IS_EMPTY(tag)      (((tag) & CV_NODE_EMPTY) != 0)
#define CV_NODE_IS_USER(tag)       (((tag) & CV_NODE_USER) != 0)
#define CV_NODE_HAS_NAME(tag)      (((tag) & CV_NODE_NAMED) != 0)

#define CV_NODE_SEQ_SIMPLE 256
#define CV_NODE_SEQ_IS_SIMPLE(seq) (((seq)->flags & CV_NODE_SEQ_SIMPLE) != 0)

typedef struct CvString
{
    int len;
    char* ptr;
}
CvString;

/*所有已读存储在文件元素的关键字被存储在hash表中,这样可以加速查找操作 */
typedef struct CvStringHashNode
{
    unsigned hashval;
    CvString str;
    struct CvStringHashNode* next;
}
CvStringHashNode;

/* 文件存储器的基本元素是-标量或集合*/
typedef struct CvFileNode
{
    int tag;
    struct CvTypeInfo* info; /* 类型信息(只能用于用户自定义对象,对于其它对象它为0) */
    union
    {
        double f; /* 浮点数*/
        int i;    /* 整形数 */
        CvString str; /* 字符文本 */
        CvSeq* seq; /* 序列 (文件节点的有序集合) */
        struct CvMap* map; /*图表 (指定的文件节点的集合 ) */
    } data;
}
CvFileNode;