【C++】42.使用YAML文件进行参数配置、读取与生成YAML文件

关于配置文件的使用,除了本文的yaml的方法,经常使用的还有proto的方法,请参考我另一篇博客:proto相关用法:方法2.。


c++中如果要使用YAML,需要安装yaml-cpp库,安装完成后使用时还需要包含下面的头文件:

#include "yaml-cpp/yaml.h"

关于安装以及语法,可以参考下面两篇博客
C++ 解析yaml文件的使用方法:https://blog.csdn.net/sunlin972913894/article/details/103038082

c++ 开发中利用yaml-cpp读写yaml配置文件:https://cloud.tencent.com/developer/article/1423468


1. 读取解析yaml文件的参数

下面举一个C++使用yaml文件配置参数的实例:

// 函数的参数是yaml文件的路径
bool LoadConfigFile(const std::string &file_name) {
  YAML::Node config = YAML::LoadFile(file_name);
  if (!config) {
    std::cout << "Open config File:" << file_name << " failed.";
    return false;
  }
  if (!config["transform"]) {
    std::cout << "Open config File:" << file_name << " has no transform.";
    return false;
  }
  
  if (config["transform"]["translation"]) {
    // 读取yaml文件中的transform下的translation的x的值
    x_ = config["transform"]["translation"]["x"].as<float>();
  } else {
    std::cout << "config File:" << file_name << " has no transform:translation.";
    return false;
  }
  return true;
}

以下是yaml文件,上面的函数是示范了读取下面yaml文件中的transform下的translationx的值,其他值的读取也是同理。

%YAML:1.0
---
header:
   seq: 0
   frame_id: aaa
   stamp:
      secs: 0
      nsecs: 0
transform:
   translation:
      x: 1.2799999713897705e+00
      y: 2.5614136457443237e-01
      z: 5.7490050792694092e-01
   euler:
     yaw: 2.5469255447387695e+00
     pitch: -2.7205293178558350e+00
     roll: 3.1672728061676025e-01

2. 给yaml文件中写入数据:

如果你要创建一个新的“mapping”(键/值对),可以使用特殊符号大括号{。一旦开始创建,就可以为其添加元素,最终以}结束一个mapping。一旦完成创建一个mapping,需要按顺序输入条目名以及对应的值。

如果你要创建一个新的“sequence”(一系列未命名的条目),可以使用特殊符号中括号[。一旦开始创建,就可以为其添加元素,最终以]结束一个sequence。一旦完成创建一个sequence,只需要一个接一个地输入元素即可,直到sequence结束。

有时候mappingsequence的所有数据在一行,有时候每个元素一行。这并不是自动格式化造成的,而是由于mapping的起始字符{:},sequence的起始字符[:]的变化造成的。这个特点只对YAML格式的输出有意义,如果输出文件是XML格式,那么这些细微的差别将会被忽略,mapping与sequence的存储将不会有区别。

一旦完成写工作,便可以使用成员函数cv::FileStorage::release()关闭文件。

关于{}符号和[]的使用,可以参考:https://blog.csdn.net/learning_tortosie/article/details/97815514,有例子,有截图,推荐观看。

c++代码:

void WriteExtrinsics(const std::string& file_name) {
  float height = 0, lateral = 0;
  // 函数的第二个参数READ表示读取file_name
  cv::FileStorage fs_in(file_name, cv::FileStorage::READ);
  //  >> height 表示把yaml文件中的对应值赋值给 height_tmp
  fs_in["location"]["height"] >> height_tmp;
  fs_in["location"]["lateral"] >> lateral_tmp;
  fs_in.release();   //cv::FileStorage::release()关闭文件

  // 函数的第二个参数WRITE表示写入file_name
  cv::FileStorage fs_out(file_name,cv::FileStorage::WRITE);  
  // 把 camera_name_写入camera_name
  fs_out << "camera_name" << camera_name_;
  
  // 下面的大括号{}用法在代码前介绍过,最终在文件中是不会有大括号的.如果想有大括号,就加个冒号 {:
  fs_out << "transform"
         << "{"
         << "translation"
         << "{";
         
  fs_out << "x" << params_[3];  // std::vector params_;
  fs_out << "y" << params_[4];

  fs_out << "z" << params_[5] 
         << "}";

  fs_out << "euler"
         << "{";
  fs_out << "yaw" << params_[0];
  fs_out << "pitch" << params_[1];
  fs_out << "roll" << params_[2] << "}"
         << "}";

  fs_out << "location"
         << "{";
  fs_out << "height" << height_tmp;
  fs_out << "lateral" << params_[4] << "}";
  
  // matrix_是3x3的Mat,cv::Mat matrix_;,写在yaml文件中就写成了一排[,,,,,,,]
  fs_out << "K" << "[:" << matrix_.at<double>(0, 0);
  fs_out << matrix_.at<double>(0, 1);
  fs_out << matrix_.at<double>(0, 2);
  fs_out << matrix_.at<double>(1, 0);
  fs_out << matrix_.at<double>(1, 1);
  fs_out << matrix_.at<double>(1, 2);
  fs_out << matrix_.at<double>(2, 0);
  fs_out << matrix_.at<double>(2, 1);
  fs_out << matrix_.at<double>(2, 2);
  fs_out << "]";
  fs_out.release();
}

上面的代码生成的yaml文件如下:

camera_name: "aaa"
transform:
   translation:
      x: 1.2799999713897705e+00
      y: 2.5614136457443237e-01
      z: 5.7490050792694092e-01
   euler:
     yaw: 2.5469255447387695e+00
     pitch: -2.7205293178558350e+00
     roll: 3.1672728061676025e-01
location:
   height: 2.3749005794525146e+00
   lateral: 2.5614136457443237e-01
K: [1.8756049476213811e+03, 0.0, 9.4676147405235554e+02, 0.0, 1.8718221660532543e+03, 5.6894635478118289e+02, 0.0, 0.0, 1.0]

你可能感兴趣的:(c++,c++)