yamlcpp遍历_OpenCV|C++从文件或终端读写yaml或txt文件

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;

}

部分内容整理来自网络如有侵权请联系小秋删除

你可能感兴趣的:(yamlcpp遍历)