yaml文件用法总结
总结一下就是为了读写出多种多样格式并且减少依赖可以选择std::fstream的ifstream和ofstream)。
使用yaml-cpp库可以将yaml文件以节点YAML::Node的形式载入YAML::LoadFile,然后用std::fstream的ofstream写入文件。
读文件的时候首选cv::fileStorage因为可以很好的提取矩阵,其次选择std::fstream的ifstream麻烦在于要一行一行的读取解析耗费心力。
整齐划一的格式例如文件路径适合std::fstream例如ORB_SLAM2中载入图片和字典。
ORB_SLAM2中用到的地方
多种多样的配置参数和相机参数适合用cv::fileStorage可以更好的解析供OpenCV使用。
ORB_SLAM2的LoadImages函数用std::ifstream读取txt文件中的图片。
ORB_SLAM2的saved_trajectory函数用std::ofstream保存轨迹和位姿到txt文件。
ORB_SLAM2的fsSettings函数用cv::FileStorage::READ读取读取yaml文件中的相机和配置参数。
下面是一些常见的yaml文件格式
Multi-Camera Parallel Tracking and Mapping (MCPTAM)的标定文件
MultiCol-SLAM is a multi-fisheye camera SLAM system的标定文件
ROS Navigation的参数文件
安装yaml-cpp库
git clone https://github.com/jbeder/yaml-cpp.git
cd yaml-cpp
mkdir build && cd build
cmake -DYAML_BUILD_SHARED_LIBS=ON ..
make -j4
sudo make install
YAML基本语法
大小写敏感
使用空格缩进表示层级关系
同层级的元素左侧对齐
#表示注释
对象
键值对的集合 key: value冒号后面要加一个空格
可以一行只写一个键值对
也可以把所有键值对写成一个行内对象
hash: { name: Steve, foo: bar }
还可以使用缩进表示层级关系
key:
child-key: value
child-key2: value2
较为复杂的对象格式,可以使用问号加一个空格代表一个复杂的 key,配合一个冒号加一个空格代表一个 value:意思即对象的属性是一个数组 [complexkey1,complexkey2],对应的值也是一个数组 [complexvalue1,complexvalue2]
?
- complexkey1
- complexkey2
:
- complexvalue1
- complexvalue2
数组
一组连词线 - 开头按次序排列的值,构成一个数组。
- A
- B
- C
YAML 支持多维数组,可以使用行内表示:
key: [value1, value2, ...]
数据结构的子成员是一个数组
-
- A
- B
- C
一个相对复杂的例子,意思是 companies 属性是一个数组,每一个数组元素又是由 id、name、price 三个属性构成。
companies:
-
id: 1
name: company1
price: 200W
-
id: 2
name: company2
price: 500W
数组也可以使用流式(flow)的方式表示
companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]
复合结构
数组和对象可以构成复合结构
languages:
- Ruby
- Perl
- Python
websites:
YAML: yaml.org
Ruby: ruby-lang.org
Python: python.org
Perl: use.perl.org
常量
纯量是最基本的不可再分的值
布尔值
boolean:
- TRUE #true,True都可以
- FALSE #false,False都可以
浮点数
float:
- 3.14
- 6.8523015e+5 #可以使用科学计数法
整数
int:
- 123
- 0b1010_0111_0100_1010_1110 #二进制表示
Null
null:
nodeName: 'node'
parent: ~ #使用~表示null
字符串
string:
- 哈哈
- 'Hello world' #可以使用双引号或者单引号包裹特殊字符
- newline
newline2 #字符串可以拆成多行,每一行会被转化成一个空格
日期
date:
- 2018-02-17 #日期必须使用ISO 8601格式,即yyyy-MM-dd
时间
datetime:
- 2018-02-17T15:02:31+08:00 #时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区
Node 是 yaml-cpp 中的核心概念,是最重要的数据结构,它用于存储解析后的 yaml 信息,有以下几种type
Null 空节点
Sequence 对应YAML格式中的数组
Map 对应YAML格式中的对象
Scalar 对应YAML格式中的常量
生成 Node 的形式有很多种, loadFile() 是最常见的一种。
Node LoadFile(const std::string& filename)
filename是配置文件的路径,有了Node之后,所有信息都可以检索到
cout << "name:" << config["name"].as() << endl;
as()表示将解析的内容使用模板方法转换成 string 类型
Node可以使用文件流的方式写入文件
std::ofstream fout("config.yaml");
fout << node <<:endl>
fout.close();
Opencv中的FileStorage
cv::FileStorage fsi(fileName , cv::FileStorage::READ);
cv::FileStorage fso(fileName , cv::FileStorage::WRITE);
FileStorage文件关闭比较简单
fs.release();
FileStorage文件读与写的方法与C++语言中的文件流对象的使用很像,对>>和<
// 字符和数字
fs << "frameCount" << 5;
cv::Mat_ cameraMat = cv::Mat_::zeros(3, 3);
// cv::Mat
fs << "Camera Intrinsic Matrix" << cameraMat;
写入的时候要注意不可以写"." 这个符号,YAML有效字符是:[a-z],[A-Z],[0-9],”-“,”_”和空格。文件读取的方法有两种:
// first method: use operator on FileNode.
int frameCount = (int)fs2["frameCount"];
// second second method: use cv::FileNode::operator >>
int frameCount;
fs2["frameCount"] >> frameCount;
Mat的操作与C++的输入输出方法很接近
cv::Mat_ cameraMat = cv::Mat_::zeros(3, 3);
cv::Mat_ distCoeffes = ( cv::Mat_(5, 1)<< 0.1, 0.01, -0.001, 0.0, 0.0 );
// C++
std::cout<
std::cout<
// cv::FileStorage
fs << "Camera Matrix" << cameraMat;
fs << "Distortion Coefficients"<
集合的操作
// Mappings write
int x(1.0), y(0.0);
fs << "features" << "["; // also can be "[:"
fs <
// Mappings read
cv::FileNode features = fs2["features"];
// 遍历查看
cv::FileNodeIterator it = features.begin();
std::cout<<
"x="<
" y="<
" z="<
融合三种方法的yaml文件读写程序
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
int main() {
/*********************************************************
* std::ifstream Input file stream 读取文件
* std::ofstream Output file stream 写入文件
*********************************************************/
std::ifstream std_in_file_txt("../rgb.txt");
std::ofstream std_out_file_txt("../std_out_file_txt.txt");
std::ofstream std_out_file_yaml("../std_out_file_yaml.yaml");
vector vTimestamps;
// 前三行是注释,跳过
string s0;
getline(std_in_file_txt, s0);
getline(std_in_file_txt, s0);
getline(std_in_file_txt, s0);
while (!std_in_file_txt.eof()) {
string s;
getline(std_in_file_txt, s);
if (!s.empty()) {
stringstream ss;
ss << s;
double t;
ss >> t;
// 把时间戳写入文件
// std::setprecision(9) c++浮点数位数
// std::fixed 一般的方式输出浮点数 不是科学计数法
std_out_file_txt << std::setprecision(19) << std::fixed;
std_out_file_txt << t << std::endl;
// 虽然可以生成 .yaml 文件但是格式不是yaml的格式因为没有文件头"%YAML:1.0"
std_out_file_yaml << t << endl;
std_out_file_yaml << t << endl;
}
}
std::ifstream std_in_file_yaml("../read_no_yaml_head.yaml");
std::ofstream std_out_file_yaml_txt("../std_out_file_yaml_txt.txt");
std::ofstream std_out_file_yaml_yaml("../std_out_file_yaml_yaml.yaml");
while (!std_in_file_yaml.eof()) {
string s;
getline(std_in_file_yaml, s);
std_out_file_yaml_txt << s << endl;
std_out_file_yaml_yaml << s << endl;
}
/***********************************************************************************
* cv::FileStorage cv_file_in("cv_file_read.yaml", FileStorage::READ); 读取文件
* cv::FileStorage cv_file_out("cv_file_out.yaml", FileStorage::WRITE); 写入文件
***********************************************************************************/
// --------------------------------- FileStorage 读取文件的方式 --------------------------------
cv::FileStorage fsSettings("../read_with_yaml_head.yaml", cv::FileStorage::READ);
// 用 std::ofstream 生成的 yaml 文件是不能被 cv::FileStorage 正常读取的
// 因为使用 cv::FileStorage 加载的yaml文件第一行必须是 %YAML:1.0
if(!fsSettings.isOpened()){
cerr << "ERROR: Wrong path at : " << endl;
exit(-1);
}
// first method: use (type) operator on FileNode.
float fx = fsSettings["Camera.fx"];
float fy = fsSettings["Camera.fy"];
float cx = fsSettings["Camera.cx"];
float cy = fsSettings["Camera.cy"];
cout << fx << fy << cx << cy << endl;
// second method: use FileNode::operator ">>"
cv::Mat DistCoef(5,1,CV_32F);
fsSettings["Camera.k1"] >> DistCoef.at(0);
fsSettings["Camera.k2"] >> DistCoef.at(1);
fsSettings["Camera.p1"] >> DistCoef.at(2);
fsSettings["Camera.p2"] >> DistCoef.at(3);
fsSettings["Camera.k3"] >> DistCoef.at(4);
cout << DistCoef << endl;
cv::Mat cameraMatrix, camera_matrix;
fsSettings["cameraMatrix"] >> cameraMatrix;
cout << "cameraMatrix\n" << cameraMatrix << endl;
fsSettings["camera_matrix"] >> camera_matrix;
std::cout << camera_matrix << std::endl;
fsSettings.release();
// --------------------------------- FileStorage 写入文件的方式 -----------------------------------
cv::FileStorage cv_file_write("../out_with_yaml_head.yaml", cv::FileStorage::WRITE);
float fx_out = fsSettings["Camera.fx"];
float fy_out = fsSettings["Camera.fy"];
float cx_out = fsSettings["Camera.cx"];
float cy_out = fsSettings["Camera.cy"];
cv::Mat K = cv::Mat::eye(3, 3, CV_32F);
K.at(0, 0) = fx_out;
K.at(1, 1) = fy_out;
K.at(0, 2) = cx_out;
K.at(1, 2) = cy_out;
// 写入的时候一定要注意"键"的格式不能有英文的符号"." 写入的时候一定要同时有键和值
cv_file_write << "Camera_fx" << fx;
// 构造矩阵写入
Mat cameraMatrix_out = (Mat_(3, 3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1);
Mat distCoeffs = (Mat_(5, 1) << 0.1, 0.01, -0.001, 0, 0);
cv_file_write << "cameraMatrix" << cameraMatrix << "distCoeffs" << distCoeffs;
cv_file_write.release();
/*******************************************************************************************
* YAML::Node config = YAML::LoadFile("../read_no_yaml_head.yaml"); 读取文件
*
* std::fstream fstream("/home/q/CLionProjects/4-yaml/yaml/read_no_head_out.yaml"); 写入文件
* fstream << node << std::endl; 写入文件
*******************************************************************************************/
YAML::Node config = YAML::LoadFile("../read_no_yaml_head.yaml");
// 这里要注意 文件内容要严格遵守yaml语法特别是key: value之间的空格
cout << "image_width: " << config["image_width"].as() << endl;
cout << "age: " << config["age"].as() << endl;
cout << "skills c++: " << config["skills"]["c++"].as() << endl;
cout << "camera_matrix: \n" << config["camera_matrix"] << endl;
cout << "data: \n" << config["camera_matrix"]["data"] << endl;
cout << "distortion_coefficients: " << config["distortion_coefficients"] << endl;
cout << "rectification_matrix: " << config["rectification_matrix"] << endl;
cout << "projection_matrix: " << config["projection_matrix"] << endl;
// 创建节点准备写入文件
YAML::Node node;
// 创建一个字典 value的值是常量
node["number"] = 66;
// 创建一个字典字典的值是序列
node["seq"].push_back("xiaoqiu");
node["seq"].push_back("slambiji");
cout << node << endl;
// std::fstream 写入文件--------------------------------------------------------------------
std::ofstream ofstream("../read_no_head_out.yaml");
// 设置配置文件node数据
ofstream << "camera_matrix:" << std::endl;
ofstream << config["camera_matrix"] << endl;
ofstream << node << std::endl;
ofstream.close();
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
SET(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_STANDARD 11)
project(yaml)
find_package(OpenCV)
# Installing: /usr/local/lib/libyaml-cpp.so
set(YAML_CPP_LIBRARIES /usr/local/lib/libyaml-cpp.so)
add_executable(main main.cpp)
target_link_libraries(main ${OpenCV_LIBS} ${YAML_CPP_LIBRARIES})
getline()函数从终端和文件中读数据
// 本教程编译环境是 ubuntu16.04 clion
#include
#include
#include
using namespace std;
int main()
{
string name;
string city;
cout << "Please enter your name: ";
// 这个函数是来完成读入一行数据
// getline()函数的功能是读入一行数据
// std::cin ; 以终端键盘输入的方式读入内容来写入文件
getline(cin, name);
cout << "Hello, " << name << endl;
// ifstream f; 以从文件中读取的方式读入内容来写入文件
ifstream f;
string s0;
f.open("/home/q/CLionProjects/cpp_tutorials/rgb.txt");
getline(f,s0);
cout << s0 << endl;
return 0;
}
部分内容整理来自网络如有侵权请联系小秋删除