Opencv YAML和XML格式文件操做詳解


本系列文章由 @YhL_Leo 出品,轉載請註明出處。
文章連接: http://blog.csdn.net/yhl_leo/article/details/47660943


本文參考Opencv 2.4.11 documentation整理對YAMLXML文件實現I/O操做的方法。html

官網:YAML:http://www.yaml.org XML :http://www.w3c.org/XML編程

1.YAML與XML文件的打開和關閉數組

YAML格式的文件拓展名包括:.yml.yaml,兩個都表示YAML文件;
XML格式的文件拓展名爲: .xmlruby

1.1 文件打開markdown

在Opencv中,使用FileStorage進行文件讀寫。XML文件操做與YAML同樣,不過存在一些細小差異。數據結構

std::string fileName  = "E:\\test.yml"; // YAML
std::string fileName2 = "E:\\test.xml"; // XML
// write file
cv::FileStorage fs(fileName , cv::FileStorage::WRITE);
// read file
cv::FileStorage fs2(fileName , cv::FileStorage::READ);
// or use: cv::FileStorage::open
fs2.open(fileName , cv::FileStorage::READ);

FileStorage的文件操做模式一共分爲四種:READWRITEAPPENDMEMORYapp

文檔打開後很關心的一件事就是,進行確認是否成功。FileStorage有本身的成員函數返回文件打開狀態:jsp

// bool FileStorage::isOpened() const;
if ( !fs.isOpened() ) // failed
{
    std::cout<<"Save File Failed!"<<std::endl;
    return ;
}
else // succeed
{
    ...
}

1.2 文件關閉函數

FileStorage文件關閉比較簡單:ui

fs.release();

2.文件讀寫

FileStorage文件讀與寫的方法與C++語言中的文件流對象的使用很像,對>><<進行了重載,分別用於文件讀取和寫入。很棒的是,FileStorage支持一些經常使用格式的直接讀寫,例如字符、字符串、數字、cv::Mat等。對於不支持的數據結構,只能按照規則本身去寫啦~

2.1 寫入

fs << "frameCount" << 5;  // 字符和數字
cv::Mat_<double> cameraMat = cv::Mat_<double>::zeros(3, 3); 
fs << "Camera Intrinsic Matrix" << cameraMat; // cv::Mat

注意:

  • fs << "frameCount" <<5""內輸出的字符串是有限制的,對於YAML有效範圍是:[a-z],[A-Z],[0-9],」-「,」_」和空格。XML與YAML基本一致,可是YAML字符之間加空格是容許的,XML不容許。若是出現如下BUG,請不要慌張,檢查一下輸入的字符是否有效就OK~

2.2 讀取

文件讀取的方法有兩種:

// first method: use (type) operator on FileNode.
int frameCount = (int)fs2["frameCount"];
// second second method: use cv::FileNode::operator >>
int frameCount;
fs2["frameCount"] >> frameCount;

2.3 Mat的操做

這一點真的很不錯,並且與C++的輸入輸出方法很接近(連接:經常使用的三種Mat類型):

cv::Mat_<double> cameraMat = cv::Mat_<double>::zeros(3, 3);
cv::Mat_<double> distCoeffes = ( cv::Mat_<double>(5, 1)<< 0.1, 0.01, -0.001, 0.0, 0.0 );
// C++
std::cout<<"Camera Matrix"<<std::endl<<cv::Mat::Mat(cameraMat)<<std::endl;
std::cout<<"Distortion Coefficients"<<std::endl<<cv::Mat::Mat(distCoeffes)<<std::endl;
// cv::FileStorage
fs << "Camera Matrix" << cameraMat;
fs << "Distortion Coefficients"<<distCoeffes;

運行結果對好比下:

C++ C++
YAML YAML
XML YAML

2.4 集合的操做

Opencv中將集合分爲兩類:映射和序列。

映射集合(Mappings, 又稱named collections):每一個元素有一個名字或者說關鍵字,而且能夠經過名字訪問其數據,相似於Key-Value結構。使用方法爲:

// Mappings write
int x(1.0), y(0.0);
fs << "features" << "["; // also can be "[:"
fs <<"{:" << "x" << x << "y" << "}" << "]";
  • "{""{:"輸出的結果是不同的,YAML使用":"後,使輸出的文本具備Python的風格,映射集合會按照一行排列,不適用時,按照每一個元素與其值單獨一行的方法排列。XML使用":"後輸出結果會有不一樣,但基本能夠視爲把":"忽略。

YAML { Map1
YAML {: Map2
XML { Map3
XML {: Map4

// Mappings read
cv::FileNode features = fs2["features"];
// 遍歷查看
cv::FileNodeIterator it = features.begin();
std::cout<<
    "x="<<(int)(*it)["x"]<<
    " y="<<(int)(*it)["y"]<<
    " z="<<(int)(*it)["z"]<<std::endl;

輸出結果:Output

  • 編程的時候,不在Mapping的"{ }"外加上"[ ]"輸出的效果是不同的,並且在數據讀取的時候,加上"[
    ]"
    的Mapping結構會被認爲是Mapping結構,不然會出錯,以上述的Mappings write代碼爲例: 對於 fs <<
    "fearures" << "[" << "{" << ... << "}" << "]"
    結構,用上述方法能夠讀取成功; 對於 fs
    << "features" << "{" << ... << "}"
    結構,用上述方法時就會出錯:

序列集合(Sequences,又稱unnamed collections):數據沒有名字名字或者關鍵字,通常經過序號(indices)訪問數據,例如最多見的數組。

與映射相似,序列集合須要在輸出開始前加"[",結束後使用"]",而且"[:""["在輸出風格上與映射集合相似。

// Sequences write
int mySeq[5] = {0, 1, 2, 3, 4};
fs << "mySeq" << "[";
for ( int idx=0; idx<5; idx++ )
{
    fs << mySeq[idx];
}
fs << "]";
// Sequences read
cv::FileNode mySeq2 = fs2["mySeq"];
std::vector<int> seq;
cv::FileNodeIterator it = mySeq2.begin(), it_end = mySeq2.end();
for ( ; it != it_end; it++  )
{
    seq.push_back( (int)( *it ) );
    // std::cout<<(int)(*it)<<" "<<std::endl;
}

3.Opencv documentation 源碼示例

下面貼出Opencv documentation中的示例代碼,能夠做爲參考:

// file write
#include "opencv2/opencv.hpp"
#include <time.h>

using namespace cv;
using namespace std;

int main(int, char** argv)
{
    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, 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 << "distCoeffs" << 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;
}
// results
%YAML:1.0
frameCount: 5
calibrationDate: "Fri Jun 17 14:09:29 2011\n"
cameraMatrix: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [ 1000., 0., 320., 0., 1000., 240., 0., 0., 1. ]
distCoeffs: !!opencv-matrix
   rows: 5
   cols: 1
   dt: d
   data: [ 1.0000000000000001e-01, 1.0000000000000000e-02,
       -1.0000000000000000e-03, 0., 0. ]
features:
   - { x:167, y:49, lbp:[ 1, 0, 0, 1, 1, 0, 1, 1 ] }
   - { x:298, y:130, lbp:[ 0, 0, 0, 1, 0, 0, 1, 1 ] }
   - { x:344, y:158, lbp:[ 1, 1, 0, 0, 0, 0, 1, 0 ] }
// file read
FileStorage fs2("test.yml", FileStorage::READ);

// first method: use (type) operator on FileNode.
int frameCount = (int)fs2["frameCount"];

std::string date;
// second method: use FileNode::operator >>
fs2["calibrationDate"] >> date;

Mat cameraMatrix2, distCoeffs2;
fs2["cameraMatrix"] >> cameraMatrix2;
fs2["distCoeffs"] >> distCoeffs2;

cout << "frameCount: " << frameCount << endl
     << "calibration date: " << date << endl
     << "camera matrix: " << cameraMatrix2 << endl
     << "distortion coeffs: " << distCoeffs2 << endl;

FileNode features = fs2["features"];
FileNodeIterator it = features.begin(), it_end = features.end();
int idx = 0;
std::vector<uchar> lbpval;

// iterate through a sequence using FileNodeIterator
for( ; it != it_end; ++it, idx++ )
{
    cout << "feature #" << idx << ": ";
    cout << "x=" << (int)(*it)["x"] << ", y=" << (int)(*it)["y"] << ", lbp: (";
    // you can also easily read numerical arrays using FileNode >> std::vector operator.
    (*it)["lbp"] >> lbpval;
    for( int i = 0; i < (int)lbpval.size(); i++ )
        cout << " " << (int)lbpval[i];
    cout << ")" << endl;
}
fs.release();
相關文章
相關標籤/搜索