ファイルへの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,