パラメータ(カメラパラメータや学習したパラメータ)をOpenCVを通じて保存する方法
大体こちらに*1に書いてある内容で充分

void write(FileStorage &fs, variable v);

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

引数

  • fs:FileStorageクラス.
  • v:保存したいデータが格納されてる変数

返り値

  • だいたいvoid

void cvWrite( CvFileStorage *fs, const char* name, const void* ptr, CvAttrList attributes)

Cインタフェース版

引数

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

返り値

  • void型なのでなし

解説

  • cvOpenFileStorage か cv::FileStorage で FileStorage型を作る
  • そののち,cvWrite や cv::Write 関数で実際のファイルに書き出す
  • 単なる連続データはCV_NODE_SEQ,オブジェクト構造の場合はCV_NODE_MAPを使うと良い
  • ファイル名が xml で終わる場合はXMLフォーマットで,それ以外の場合はYAMLフォーマットで書きだす
  • CV_NODE_FLOWはYAML形式の場合だけ意味を持つ*2

サンプルコード1

  1. #include "opencv2/core/core.hpp"
  2.  
  3. int main(){
  4. cv::FileStorage fs;
  5. fs.open("test.xml", cv::FileStorage::WRITE);
  6. // READ と WRITE と APPEND は FileStorage 内にて enum で定義されてる
  7.  
  8. // indexという名前で値を保存
  9. int index = 1;
  10. cv::write(fs, "index", index);
  11.  
  12. // 複数のデータを書き出す場合
  13. cv::Rect aRect(200, 300, 100, 100);
  14. cv::WriteStructContext ws(fs, "Rectangles", CV_NODE_SEQ + CV_NODE_FLOW);
  15. for(int i = 0;i < 10;i++){
  16. cv::write(fs, aRect);
  17. }
  18. return 0;
  19. }

実行結果1

<?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

オブジェクトで書き出そうとしたらハマった

  1. #include "opencv2/core/core.hpp"
  2.  
  3. int main(){
  4. cv::FileStorage fs;
  5. fs.open("test.xml", cv::FileStorage::WRITE);
  6. // READ と WRITE と APPEND は FileStorage 内にて enum で定義されてる
  7.  
  8. cv::WriteStructContext ws(fs, "Region1", CV_NODE_SEQ + CV_NODE_FLOW);
  9. cv::Rect aRect(200, 300, 100, 100);
  10. cv::write(fs, "region1", aRect);
  11.  
  12. return -1;
  13. }

実行結果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

名前を降らなくても,配列を複数書き出そうとしたらこける

  1. #include "opencv2/core/core.hpp"
  2.  
  3. int main(){
  4. cv::FileStorage fs;
  5. fs.open("test.xml", cv::FileStorage::WRITE);
  6.  
  7. cv::Rect aRect(200, 300, 100, 100);
  8. cv::WriteStructContext ws(fs, "Faces1", CV_NODE_SEQ);
  9. for(int i = 0;i < 10;i++){
  10. cv::write(fs, aRect);
  11. }
  12. cv::WriteStructContext ws2(fs, "Faces2", CV_NODE_SEQ); // <- ここで死ぬ
  13. for(int i = 0;i < 10;i++){
  14. cv::write(fs, aRect);
  15. }
  16.  
  17. return -1;
  18. }

実行結果3

  • 実行時エラー
    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

配列を複数書きだす場合はこう書く

  1. #include "opencv2/core/core.hpp"
  2.  
  3. int main(){
  4. cv::FileStorage fs;
  5. fs.open("test.xml", cv::FileStorage::WRITE);
  6.  
  7.  
  8. cv::Rect aRect(200, 300, 100, 100);
  9. {
  10. cv::WriteStructContext ws(fs, "Faces1", CV_NODE_SEQ);
  11. for(int i = 0;i < 10;i++){
  12. cv::write(fs, aRect);
  13. }
  14. } // <- ****ここで無駄にブラケットで区切ることにより ws がここで消滅してデストラクタが呼ばれる
  15. {
  16. cv::WriteStructContext wsq(fs, "Faces2", CV_NODE_SEQ);
  17. for(int i = 0;i < 10;i++){
  18. cv::write(fs, aRect);
  19. }
  20. }
  21. return -1;

実行結果4

<?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 内に良いサンプルがある.

実体ファイル

  • :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準拠


*1  ファイルへのXML/YAML形式でのデータ保存/読み込み | OpenCV.jp
*2  persistence.cpp 内の icvYMLWrite 内で処理が分岐している

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2012-09-28 (金) 16:15:50 (1879d)