XML/YAML/JSONファイルストレージ
ファイルストレージへの書き込み
さまざまなOpenCVのデータ構造を、XML (http://www.w3c.org/XML)、YAML (http://www.yaml.org)、JSON (http://www.json.org/) 形式へ保存し、また復元することができる。さらに、OpenCVのデータ構造はもちろん、プリミティブなデータ型(整数や浮動小数点数、テキスト文字列)を要素とする任意の複雑なデータ構造を保存・読み込みすることも可能である。
XML、YAML、JSONに何かを書き込むには、以下の手順を用いる:
- 新しい FileStorage を作成し、書き込み用に開く。これは、ファイル名を引数に取る FileStorage::FileStorage コンストラクタの一回の呼び出しで行うか、あるいはデフォルトコンストラクタを使った後に FileStorage::open を呼び出すことで行える。ファイルの形式(XML、YAML、JSON)はファイル名の拡張子(それぞれ ".xml"、".yml"/".yaml"、".json")から決定される。
- STLストリームの場合と同様に、ストリーミング演算子
<< を使って書き込みたいデータをすべて書き込む。
- FileStorage::release を使ってファイルを閉じる。FileStorage のデストラクタもファイルを閉じる。
以下に例を示す:
#include <time.h>
int main(
int,
char** argv)
{
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);
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 << "]";
return 0;
}
XML/YAML/JSON file storage class that encapsulates all the information necessary for writing or readi...
Definition persistence.hpp:261
@ WRITE
value, open the file for writing
Definition persistence.hpp:267
Template matrix class derived from Mat.
Definition mat.hpp:2581
Comma-separated Matrix Initializer.
Definition mat.hpp:964
void release()
Decrements the reference counter and deallocates the matrix if needed.
uint8_t uchar
Definition interface.h:35
int main(int argc, char *argv[])
Definition highgui_qt.cpp:3
上記のサンプルは、整数、テキスト文字列(キャリブレーション日付)、2つの行列、そして特徴座標とLBP (local binary pattern) 値を含むカスタム構造体「feature」をYMLに保存する。以下はサンプルの出力である:
%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 ] }
練習として、上記のサンプルで ".yml" を ".xml" や ".json" に置き換えて、対応するXMLファイルがどのように見えるかを確認するとよい。
サンプルコードと出力を見ると、いくつかのことに気づく:
生成されるYAML(およびXML/JSON)は、ネスト可能な異種コレクションから構成される。コレクションには2種類ある: 名前付きコレクション(マッピング)と名前なしコレクション(シーケンス)である。マッピングでは各要素が名前を持ち、名前でアクセスされる。これはC/C++の構造体やstd::map、Pythonの辞書に似ている。シーケンスでは要素は名前を持たず、インデックスでアクセスされる。これはC/C++の配列やstd::vector、Pythonのリストやタプルに似ている。「異種」とは、1つのコレクション内の各要素が異なる型を持ちうることを意味する。
YAML/XML/JSONの最上位コレクションはマッピングである。各行列はマッピングとして保存され、行列の要素はシーケンスとして保存される。次に特徴のシーケンスがあり、各特徴はマッピングとして表現され、lbp値はネストされたシーケンスとして表現される。
- マッピング(構造体)に書き込むときは、要素名に続けてその値を書く。シーケンスに書き込むときは、要素を1つずつ単純に書いていく。OpenCV のデータ構造(cv::Mat など)は、単純な C のデータ構造とまったく同じように
<< 演算子を使って書き込まれる。
- マッピングを書き込むには、まず特殊文字列
{ をストレージに書き込み、次に要素をペア(fs << <element_name> << <element_value>)として書き込み、最後に閉じる } を書き込む。
- シーケンスを書き込むには、まず特殊文字列
[ を書き込み、次に要素を書き込み、最後に閉じる ] を書き込む。
- YAML/JSON(ただしXMLは除く)では、マッピングとシーケンスをコンパクトなPythonライクのインライン形式で記述できる。上記のサンプルでは、行列の要素や、lbp値を含む各特徴が、このようなインライン形式で保存されている。マッピング/シーケンスをコンパクトな形式で保存するには、開始文字の後に
: を置く。例えば { の代わりに {: を、[ の代わりに [: を使う。データがXMLに書き込まれる際には、これらの余分な : は無視される。
ファイルストレージからのデータの読み込み
以前に書き込んだXML、YAML、JSONファイルを読み込むには、以下の手順を行う:
- FileStorage::FileStorage コンストラクタまたは FileStorage::open メソッドを使ってファイルストレージを開く。現在の実装では、ファイル全体が解析され、ファイルストレージ全体の表現がファイルノードの階層としてメモリ上に構築される(FileNode を参照)。
- 関心のあるデータを読み込む。FileStorage::operator []、FileNode::operator [] や FileNodeIterator を使用する。
- FileStorage::release を使ってストレージを閉じる。
上記のコードサンプルで作成したファイルを読み込む方法は以下のとおりである:
int frameCount = (int)fs2["frameCount"];
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;
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();
used to iterate through sequences and mappings.
Definition persistence.hpp:602
File Storage Node class.
Definition persistence.hpp:448
FileNodeIterator begin() const
returns iterator pointing to the first node element
FileNodeIterator end() const
returns iterator pointing to the element following the last node element
@ READ
value, open the file for reading
Definition persistence.hpp:266
std::string String
Definition cvstd.hpp:151
フォーマット仕様
([count]{u|c|w|s|i|f|d})... ここで各文字はC++の基本型に対応する:
u 8ビット符号なし数値
c 8ビット符号付き数値
w 16ビット符号なし数値
s 16ビット符号付き数値
i 32ビット符号付き数値
f 単精度浮動小数点数
d 倍精度浮動小数点数
r ポインタ。下位32ビットが符号付き整数として書き込まれる。この型は要素間のリンクを持つ構造体を保存するために使用できる。
count は指定された型の値の個数を表す省略可能なカウンタである。例えば 2if は、各配列要素が2つの整数とそれに続く1つの単精度浮動小数点数からなる構造体であることを意味する。上記仕様の等価な表記は iif、2i1f などである。その他の例: u は配列がバイト列で構成されることを意味し、2d は配列がdoubleのペアで構成されることを意味する。
- 参照
- samples/cpp/tutorial_code/core/file_input_output/file_input_output.cpp