ファイルへのXML/YAML形式でのデータ保存/読み込み
C
データの保存
#include <cv.h>
int
main (int argc, char **argv)
{
char filename[] = "save_cv.xml"; // file name
int i;
int a;
float b;
CvMat** mat;
CvFileStorage *cvfs;
// (1)create sample data
a = 10;
b = 0.1;
mat = (CvMat**)cvAlloc(3*sizeof(CvMat*));
for(i=0;i<3;i++){
mat[i] = cvCreateMat(3,3,CV_32FC1);
cvSet(mat[i], cvScalarAll(i), NULL);
}
// (2)open file storage
cvfs = cvOpenFileStorage(filename,NULL,CV_STORAGE_WRITE);
// (3)write data to file
cvWriteInt(cvfs, "a", a);
cvWriteReal(cvfs, "b", b);
cvStartWriteStruct(cvfs, "mat_array", CV_NODE_SEQ, NULL, cvAttrList(NULL, NULL)); // create node
for(i=0; i<3; i++){
cvWrite(cvfs, NULL, mat[i], cvAttrList(NULL, NULL));
}
cvEndWriteStruct(cvfs);
// (4)close file storage
cvReleaseFileStorage(&cvfs);
// release mat
for(i=0; i<3; i++){
cvReleaseMat(mat+i);
}
cvFree(mat);
return 0;
}
// (1)サンプルデータを作成します.
ここではファイルに保存するサンプルデータを生成しています.このサンプルでは,int型データが1つ,float型データが1つ,CvMat型構造体の配列(要素数3)を保存します.
// (2)ファイルストレージを開きます.
関数cvOpenFileStorageを用いて,書き込みモードでファイルを開きます. 第1引数に指定したファイル名が,拡張子”.xml”ならばXML形式で,”.yaml”,”.yml”,”.txt”などであればYAML形式で保存します.第3引数で書き込みモードであることを指定します.
// (3)データをファイルへ書きこみます.
(2)で開いたファイルに対し,データを書きこみます.OpenCVにおけるデータの保存は,tree型の階層構造をとります.この例では,トップノードの下にint型データaとfloat型データbを,またトップノードの下に”mat_array”というノードを作成し,その下にCvMat型配列matのそれぞれの要素を格納しています. int型のデータに対しては関数cvWriteInt,float等の浮動小数点型データに対しては関数cvWriteRealを使用します. どちらの関数も第1引数にファイルストレージへのポインタ,第2引数に保存するデータの名前,第3引数に実際に保存するデータを指定します.
新しくノードを作成するには関数cvStartWriteStructを使用します.第1引数はファイルストレージへのポインタ,第2引数は作成するノードの名前,第3引数は”CV_NODE_SEQ”が指定されたときはノードの下の要素は名前を持たずに連続的に保存され,”CV_NODE_MAP”の時はノードの下の各要素は名前を持ちます.今回は配列の保存なので”CV_NODE_SEQ”を指定しました.cvStartWriteStructで作成されたノードは,ノード内にデータの書き込みが終了したら必ずcvEndWriteStructで閉じる必要があります.ここで作成した”mat_array”ノードの下に関数cvWriteを使ってデータの書き込みを行います.cvWriteはOpenCVで定義された構造体を保存するための関数です.
// (4)ファイルストレージを閉じます.
関数cvOpenFileStorageを用いて開いたファイルを,関数cvReleaseFileStorageを用いて閉じます.
データの読み込み
#include <stdio.h>
#include <cv.h>
int
main (int argc, char **argv)
{
char filename[] = "save_cv.xml"; // file name
int i,j,k;
CvFileStorage *cvfs;
CvFileNode *node, *fn;
CvSeq *s;
int total;
// (1)memory space for loading data
int a;
float b;
CvMat** mat = (CvMat**)cvAlloc(3*sizeof(CvMat*));
// (2)open file storage
cvfs = cvOpenFileStorage(filename, NULL, CV_STORAGE_READ);
// (3)read data from file storage
node = cvGetFileNodeByName(cvfs, NULL, ""); // Get Top Node
a = cvReadIntByName(cvfs, node, "a", 0);
b = cvReadRealByName(cvfs, node, "b", 0);
fn = cvGetFileNodeByName(cvfs,node,"mat_array");
s = fn->data.seq;
total = s->total;
for(i=0;i<total;i++){
mat[i] = (CvMat*)cvRead(cvfs,(CvFileNode*)cvGetSeqElem(s,i), NULL);
}
// (4)close file storage
cvReleaseFileStorage(&cvfs);
// (5)print loaded data
printf("a:%d\n", a);
printf("b:%f\n", b);
for(i=0; i<3; i++){
printf("mat%d:\n",i);
for(j=0;j<mat[i]->rows;j++){
for(k=0;k<mat[i]->cols;k++){
printf("%f,",cvmGet(mat[i],j,k));
}
printf("\n");
}
}
// release mat
for(i=0; i<3; i++){
cvReleaseMat(mat+i);
}
cvFree(mat);
return 0;
}
// (1)データを読み込むデータ領域を確保します.
ここでは先程保存したファイルを読み込み,そのデータを保存するための領域を確保しています.
// (2)ファイルストレージを開きます.
関数cvOpenFileStorageを用いて,読み込みモードでファイルを開きます.第3引数で読み込みモードであることを指定します.
// (3)データをファイルから読みこみます.
(2)で開いたファイルから,データを読みこみます.まずcvGetFileNodeByNameでファイルに格納されたtree型データ構造のトップノードを取得します.第1引数が(2)で取得したファイルストレージへのポインタ,第2引数が親ノードへのポインタでここではトップノードなのでNULLを指定,第3引数はノードの名前(ここでは特に名前をつけていないため空文字列)を指定します.データの読み込みは int型のデータに対しては関数cvReadIntByName,float等の浮動小数点型データに対しては関数cvReadRealByNameを使用します. どちらの関数も第1引数にファイルストレージへのポインタ,第2引数にノードへのポインタ,第3引数に保存時に付与したデータの名前を指定します.
次に関数cvGetFileNodeByNameを使用して”mat_array”ノードを取得します.第2引数には親ノードであるトップノードのポインタを指定します.保存時に”CV_NODE_SEQ”と指定したノードはCvSeq構造体としてデータを取得することで,それぞれの要素にアクセスすることが可能になります.
// (4)ファイルストレージを閉じます.
関数cvOpenFileStorageを用いて開いたファイルを,関数cvReleaseFileStorageを用いて閉じます.
// (5)データを出力します.
データが正しく読み取れたかの確認のために,データを標準出力で表示します.
C++
データの保存
#include <cv.h>
using namespace std;
int
main (int argc, char **argv)
{
char filename[] = "save_cv.xml"; // file name
// (1)create sample data
int a = 10;
float b = 0.1;
cv::Mat mat[3];
for(int i=0; i<3; i++){
mat[i].create(3,3,CV_32FC1);
mat[i].setTo(cv::Scalar(i));
}
// (2)open file storage
cv::FileStorage cvfs(filename,CV_STORAGE_WRITE);
// (3)write data to file
cv::write(cvfs,"a",a);
cv::write(cvfs,"b",b);
cv::WriteStructContext ws(cvfs, "mat_array", CV_NODE_SEQ); // create node
for(int i=0; i<3; i++){
cv::write(cvfs,"",mat[i]);
}
return 0;
}
// (1)サンプルデータを作成します.
ここではファイルに保存するサンプルデータを生成しています.このサンプルでは,int型データが1つ,float型データが1つ,cv::Matクラス配列(要素数3)に格納したデータを保存します.
// (2)ファイルストレージを開きます.
関数cv::FileStorageクラスのインスタンスを書き込みモードで生成することでファイルを開きます.このインスタンスのデストラクタが呼び出されたときに,自動的にファイルは閉じられます.第1引数に指定したファイル名が,拡張子”.xml”ならばXML形式で,”.yaml”,”.yml”,”.txt”などであればYAML形式で保存します.第2引数で書き込みモードであることを指定します.
// (3)データをファイルへ書きこみます.
(2)で開いたファイルに対し,データを書きこみます.OpenCVにおけるデータの保存は,tree型の階層構造をとります.この例では,トップノードの下にint型データaとfloat型データbを,またトップノードの下に”mat_array”というノードを作成し,その下にcv::Mat型配列のそれぞれの要素を格納しています. C++インターフェースでのデータ保存は,全て関数cv::writeを使用します. 第1引数にファイルストレージへのポインタ,第2引数に保存するデータの名前,第3引数に実際に保存するデータを指定します.
C++インターフェースで新しくノードを作成するにはcv::WriteStructContextクラスのインスタンスを生成します.コンストラクタの第1引数はファイルストレージへのポインタ,第2引数は作成するノードの名前,第3引数は”CV_NODE_SEQ”が指定されたときはノードの下の要素は名前を持たずに連続的に保存され,”CV_NODE_MAP”の時はノードの下の各要素は名前を持ちます.今回は配列の保存なので”CV_NODE_SEQ”を指定しました.ここで作成されたノードは,インスタンスwsのデストラクタが呼び出された時に自動的に閉じられます.ここで作成した”mat_array”ノードの下に関数cv::writeを使ってMat配列データの書き込みを行っています.
データの読み込み
#include <iostream>
#include <cv.h>
using namespace std;
int
main (int argc, char **argv)
{
char filename[] = "save_cv.xml"; // file name
int i,j,k;
// (1)memory space for loading data
int a;
float b;
cv::Mat mat[3];
// (2)open file storage
cv::FileStorage cvfs(filename,CV_STORAGE_READ);
// (3)read data from file storage
cv::FileNode node(cvfs.fs, NULL); // Get Top Node
a = node["a"];
b = node["b"];
cv::FileNode fn = node[string("mat_array")];
for(i=0;i<fn.size();i++){
cv::read(fn[i], mat[i]);
}
// (4)print loaded data
cout << "a:" << a << endl;
cout << "b:" << b << endl;
for(i=0; i<3; i++){
cout << "mat" << i << ":" << endl;
for(j=0;j<mat[i].rows;j++){
for(k=0;k<mat[i].cols;k++){
cout << mat[i].at<float>(j,k) << ",";
}
cout << endl;
}
}
return 0;
}
// (1)データを読み込むデータ領域を確保します.
ここでは先程保存したファイルを読み込み,そのデータを保存するための領域を確保しています.
// (2)ファイルストレージを開きます.
関数cv::FileStorageクラスのインスタンスを読み込みモードで生成することでファイルを開きます.このインスタンスのデストラクタが呼び出されたときに,自動的にファイルは閉じられます.第1引数に指定したファイル名,第2引数で読み込みモードであることを指定します.
// (3)データをファイルから読みこみます.
(2)で開いたファイルから,データを読みこみます.まずcv::FileNodeインスタンスを生成することで,ファイルに格納されたtree型データのトップノードを取得します.第1引数が(2)で生成したcv::FileStorageインスタンスのメンバであるCvFileStorage構造体へのポインタ,第2引数が親ノードへのポインタでここではトップノードなのでNULLを指定します.この例のようにノードからint型やfloat型のデータや子ノードを読み込む場合はcv::FileNodeのインスタンスにデータ名やノード名を添字で指定することで読み込むことが可能です.また,OpenCVのC++インターフェースで定義されたクラスは関数cv::readで読み込むことが可能です.
// (4)データを出力します.
データが正しく読み取れたかの確認のために,データを標準出力で表示します.
実行結果例
生成したXMLファイル
<?xml version="1.0"?>
<opencv_storage>
<a>10</a>
<b>0.1000000014901161</b>
<mat_array>
<_ type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>f</dt>
<data>
0. 0. 0. 0. 0. 0. 0. 0. 0.</data></_>
<_ type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>f</dt>
<data>
1. 1. 1. 1. 1. 1. 1. 1. 1.</data></_>
<_ type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>f</dt>
<data>
2. 2. 2. 2. 2. 2. 2. 2. 2.</data></_></mat_array>
</opencv_storage>
読み込んだデータの出力結果
a:10 b:0.100000 mat0: 0.000000,0.000000,0.000000, 0.000000,0.000000,0.000000, 0.000000,0.000000,0.000000, mat1: 1.000000,1.000000,1.000000, 1.000000,1.000000,1.000000, 1.000000,1.000000,1.000000, mat2: 2.000000,2.000000,2.000000, 2.000000,2.000000,2.000000, 2.000000,2.000000,2.000000,

