パラメータ(カメラパラメータや学習したパラメータ)をOpenCVを通じて保存する方法~
大体こちらに&note{XML-opencvjp:[[ファイルへのXML/YAML形式でのデータ保存/読み込み | OpenCV.jp>http://opencv.jp/opencv2-x-samples/xml_yaml]]};に書いてある内容で充分


#contents

*void write(FileStorage &fs, variable v); [#e898d82e]

variable v の型に応じて多重定義されてる

**引数 [#k6a478fd]
-fs:FileStorageクラス.
-v:保存したいデータが格納されてる変数

**返り値 [#j56cb872]
-だいたいvoid

*void cvWrite( CvFileStorage *fs, const char* name, const void* ptr, CvAttrList attributes) [#t663291f]
Cインタフェース版

**引数 [#hb591a16]
-fs:CvFileStorage型のポインタ.FILE*だと思えば分かりやすい
-name:const char*型の文字列.変数の名前や意味を書きだす.NULLでも大丈夫.
-ptr:書きだすオブジェクトのポインタ
-attributes:省略可能

**返り値 [#s2b26292]
-void型なのでなし

*解説 [#uccf88f6]
-cvOpenFileStorage か cv::FileStorage で FileStorage型を作る
-そののち,cvWrite や cv::Write 関数で実際のファイルに書き出す
-単なる連続データはCV_NODE_SEQ,オブジェクト構造の場合はCV_NODE_MAPを使うと良い
-ファイル名が xml で終わる場合はXMLフォーマットで,それ以外の場合はYAMLフォーマットで書きだす
-CV_NODE_FLOWはYAML形式の場合だけ意味を持つ&note{YAML-FLOW:persistence.cpp 内の icvYMLWrite 内で処理が分岐している};

*サンプルコード1 [#r405bedb]
#geshi(c++,number){{
#include "opencv2/core/core.hpp"

int main(){
	cv::FileStorage fs;
	fs.open("test.xml", cv::FileStorage::WRITE);
	// READ と WRITE と APPEND は FileStorage 内にて enum で定義されてる

	// indexという名前で値を保存
	int index = 1;
	cv::write(fs, "index", index);

	// 複数のデータを書き出す場合
	cv::Rect aRect(200, 300, 100, 100);
	cv::WriteStructContext ws(fs, "Rectangles", CV_NODE_SEQ + CV_NODE_FLOW);
	for(int i = 0;i < 10;i++){
		cv::write(fs, aRect);
	}
	return 0;
}
}}

**実行結果1 [#a22b614a]
 <?xml version="1.0"?>
 <opencv_storage>
 <index>1</index>
 <Rectangles>
   200 300 100 100 200 300 100 100 200 300 100 100 200 300 100 100 200
   300 100 100 200 300 100 100 200 300 100 100 200 300 100 100 200 300
   100 100 200 300 100 100</Rectangles>
 </opencv_storage>

-変数名とデータが保存されているのが分かる
-読みやすいように適宜改行が入れられてるのも良い.

*サンプルコード2 [#f7073474]
オブジェクトで書き出そうとしたらハマった

#geshi(c++,number){{
#include "opencv2/core/core.hpp"

int main(){
	cv::FileStorage fs;
	fs.open("test.xml", cv::FileStorage::WRITE);
	// READ と WRITE と APPEND は FileStorage 内にて enum で定義されてる

	cv::WriteStructContext ws(fs, "Region1", CV_NODE_SEQ + CV_NODE_FLOW);
	cv::Rect aRect(200, 300, 100, 100);
	cv::write(fs, "region1", aRect);

	return -1;
}
}};

**実行結果2
-実行時エラー
 OpenCV Error: Bad argument (An attempt to add element without a key to a map,
  or add element with key to sequence) in unknown function, file 
 ..\..\..\modules\core\src\persistence.cpp, line 2198
-ファイルも出力されず
-どうやら, CV_NODE_SEQ で出力できるのは配列のような連続したデータだけ
-名前を振るためには CV_NODE_MAP を使用せよとのこと

*サンプルコード3
名前を降らなくても,配列を複数書き出そうとしたらこける

#geshi(c++,number){{
#include "opencv2/core/core.hpp"

int main(){
	cv::FileStorage fs;
	fs.open("test.xml", cv::FileStorage::WRITE);

	cv::Rect aRect(200, 300, 100, 100);
	cv::WriteStructContext ws(fs, "Faces1", CV_NODE_SEQ);
	for(int i = 0;i < 10;i++){
		cv::write(fs, aRect);
	}
	cv::WriteStructContext ws2(fs, "Faces2", CV_NODE_SEQ); // <- ここで死ぬ
	for(int i = 0;i < 10;i++){
		cv::write(fs, aRect);
	}

	return -1;
}
}}
**実行結果3 [#c366a371]
-実行時エラー
 OpenCV Error: Bad argument (An attempt to add element without a key to a map,
  or add element with key to sequence) in unknown function, file 
 ..\..\..\modules\core\src\persistence.cpp, line 2198
-ファイルの中身
 <?xml version="1.0"?>
 <opencv_storage>
 <Faces1>
   200 300 100 100 200 300 100 100 200 300 100 100 200 300 100 100 200
   300 100 100 200 300 100 100 200 300 100 100 200 300 100 100 200 300
-Faces1タグが閉じられてないことが分かる
-どうやら,ws(Faces1タグ)を閉じるためには cvEndWriteStruct か cvStartNextStream をcallしないといけないっぽい.
-しかし,どちらをcallしても,今度はプログラム終了時に
 OpenCV Error: Unspecified error (An extra closing tag) in unknown function, 
 file ..\..\..\modules\core\src\persistence.cpp, line 2320
-というエラーが出てしまう

*サンプルコード4 [#z6338d12]
配列を複数書きだす場合はこう書く

#geshi(c++,number){{
#include "opencv2/core/core.hpp"

int main(){
	cv::FileStorage fs;
	fs.open("test.xml", cv::FileStorage::WRITE);


	cv::Rect aRect(200, 300, 100, 100);
	{
		cv::WriteStructContext ws(fs, "Faces1", CV_NODE_SEQ);
		for(int i = 0;i < 10;i++){
			cv::write(fs, aRect);
		}
	} // <- ****ここで無駄にブラケットで区切ることにより ws がここで消滅してデストラクタが呼ばれる
	{
		cv::WriteStructContext wsq(fs, "Faces2", CV_NODE_SEQ);
		for(int i = 0;i < 10;i++){
			cv::write(fs, aRect);
		}
	}
	return -1;
}}
**実行結果4 [#l93741a9]
 <?xml version="1.0"?>
 <opencv_storage>
 <Faces1>
   200 300 100 100 200 300 100 100 200 300 100 100 200 300 100 100 200
   300 100 100 200 300 100 100 200 300 100 100 200 300 100 100 200 300
   100 100 200 300 100 100</Faces1>
 <Faces2>
   200 300 100 100 200 300 100 100 200 300 100 100 200 300 100 100 200
   300 100 100 200 300 100 100 200 300 100 100 200 300 100 100 200 300
   100 100 200 300 100 100</Faces2>
 </opencv_storage>
-デコンストラクタでしかcallできないので,ブラケットを挟むはめになり,ちょっと不恰好?
- features2d/src/planardetect.cpp 内の 710 行目, FernClassifier::write 内に良いサンプルがある.
*実体ファイル [#w7bff25e]
-[[:OpenCV 2.3]]
--modules/core/include/opencv2/core/operations.hpp 
--modules/core/include/opencv2/core/core.hpp 
--modules/core/src/persistence.cpp


ジャンル[[:OpenCV 2.3]][[:OpenCV]]準拠

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS