详细教程:c++ 如何操作yaml文件

创作背景

使用python来对yolov8的模型进行推理速度有些慢,准备做一个c++版本的POC。POC会使用opencv dnn或者openvino来进行推理,其中涉及到需要读取coco.yaml文件,但是发现C++本身并没有提供读取YAML文件的API,但是可以使用第三方库来实现。

其中比较流行的是yaml-cpp库,它是一个纯C++实现的YAML解析器,支持C++11标准。

安装yaml-cpp库

安装环境: Windows10 + CMake + VS 2022

从Git Hub下载源代码

Git Hub地址:

jbeder/yaml-cpp: A YAML parser and emitter in C++ (github.com)

Release 版本:

Releases · jbeder/yaml-cpp (github.com)

我下载的是最新版本:yaml-cpp-0.8.0。

使用CMake生成VS 2022解决方案

解压下载回来的源代码包到 `D:/cxx_3_parties/yaml-cpp-0.8.0`,使用CMake-GUI来生成项目对应的VS 2022解决方案。

其中 “Where is the source code” 为源代码的目录,“Where to build the binaries”为VS解决方案保存的目录。

修改“CMAKE_INSTALL_PREFIX”库安装的目录为“d:/CXXDeps/YAML_CPP”

修改“YAML_BUILD_SHARED_LIBS”为选中状态,其他保持默认值。

点击“Configure”进行配置,然后点击“Generate” 生成VS 2022解决方案。

生成成功之后,通过点击“Open Project”打开解决方案。

使用VS 2022构建并安装库

通过“生成 -> 批生成...”打开Batch生成窗口,选中ALL_BUILD和INSTALL的Debug和Release版本,点击“生成”或者“重新生成”同时构建和安装Debug和Release的x64的版本。

点击“生成”按钮,进行库构建和安装,构建完成之后,可以在“D:\CXXDeps\YAML_CPP”目录下看到生成的头文件目录(include), 库目录(lib),动态链接库目录(bin)。

使用案例

读取coco.yaml文件

// 使用yaml-cpp库提供的API读取YAML文件
void read_coco_yaml()
{
    std::cout << "read_coco_yaml --------------------" << std::endl;
    // 加载YAML文件
    YAML::Node config = YAML::LoadFile("coco.yaml");

    // 获取指定路径下的值
    std::string path = config["path"].as<std::string>();
    std::cout << "path: " << path << std::endl;
    std::map<int, std::string> names = config["names"].as<std::map<int, std::string>>();
    std::cout << "names: " << std::endl;
    for (const auto& node : names) {
        std::cout << node.first << ": " << node.second << std::endl;
    }
     
    // 或者直接遍历YAML节点
    for (const auto& node : config["names"]) {
        std::cout << node.first << ": " << node.second << std::endl;
    }
}

修改coco.yaml并另存为new_coco.yaml

// 使用yaml-cpp库提供的API读取和修改YAML文件
void modify_coco_yaml()
{
    std::cout << "modify_coco_yaml --------------------" << std::endl;
    // 加载YAML文件
    YAML::Node config = YAML::LoadFile("coco.yaml");

    // 获取指定路径下的值
    std::string path = config["path"].as<std::string>();
    std::cout << "path: " << path << std::endl;
    config["path"] = "./newdataset/coco";
    std::map<int, std::string> names = config["names"].as<std::map<int, std::string>>();
    std::cout << "names: " << std::endl;
    names[80] = "test";
    config["names"] = names;

    YAML::Emitter out;
    out << YAML::BeginMap;
    out << config;
    out << YAML::EndMap;

    std::ofstream outFile("new_coco.yaml");
    outFile << out.c_str();
    outFile.close();
}

创建新的yaml文件

// 使用yaml-cpp库提供的API创建YAML文件 
void  create_new_yaml_file()
{
    std::cout << "create_new_yaml_file --------------------" << std::endl;

    YAML::Emitter out;
    
    out << "test yaml!";

    /* A simple list. produce as:

        - eggs
        - bread
        - milk
    */
    out << YAML::BeginSeq;
    out << "eggs";
    out << "bread";
    out << "milk";
    out << YAML::EndSeq;
    
    /* A simple map. produce as:

        name: Ryan Braun
        position: LF

    */
    out << YAML::BeginMap;
    out << YAML::Key << "name";
    out << YAML::Value << "Ryan Braun";
    out << YAML::Key << "position";
    out << YAML::Value << "LF";
    out << YAML::EndMap;
     
    /* These elements can, of course, be nested. produce as:

        name1: Barack Obama
        children1:
            - Sasha
            - Malia
    */
    out << YAML::BeginMap;
    out << YAML::Key << "name1";
    out << YAML::Value << "Barack Obama";
    out << YAML::Key << "children1";
    out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq;
    out << YAML::EndMap;
    
    /* STL Containers. produce as:

        - [1, 4, 9, 16]
        -
        Daniel: 26
        Jesse: 24
    */
    std::vector <int> squares;
    squares.push_back(1);
    squares.push_back(4);
    squares.push_back(9);
    squares.push_back(16);

    std::map <std::string, int> ages;
    ages["Daniel"] = 26;
    ages["Jesse"] = 24;

    out << YAML::BeginSeq;
    out << YAML::Flow << squares;
    out << ages;
    out << YAML::EndSeq;


    std::cout << "yaml str: \n" << out.c_str() << std::endl;

    std::ofstream fileOut("yaml_test.yaml"); 
    fileOut << out.c_str();
    fileOut.close();
}

VSCode项目文件

 CMakeLists.txt

# 设置yaml-cpp所在的目录
set(YAML_CPP_DIR D:/CXXDeps/YAML_CPP)
set(CMAKE_BUILD_TYPE "Debug")
# 使用c++ iso 17(保持vs 2022解决方案使用的c++版本保持一致)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(cpp_yaml_demo main.cpp)
target_include_directories(cpp_yaml_demo PRIVATE ${YAML_CPP_DIR}/include)
target_link_libraries(cpp_yaml_demo ${YAML_CPP_DIR}/lib/yaml-cppd.lib)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/coco.yaml DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/) 
file(COPY ${YAML_CPP_DIR}/bin/yaml-cppd.dll DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/) 

main.cpp

#include <iostream>
#include <fstream>
// 包含yaml-cpp头文件
#include <yaml-cpp/yaml.h>

// 使用yaml-cpp库提供的API读取YAML文件
void read_coco_yaml()
{
    std::cout << "read_coco_yaml --------------------" << std::endl;
    // 加载YAML文件
    YAML::Node config = YAML::LoadFile("coco.yaml");

    // 获取指定路径下的值
    std::string path = config["path"].as<std::string>();
    std::cout << "path: " << path << std::endl;
    std::map<int, std::string> names = config["names"].as<std::map<int, std::string>>();
    std::cout << "names: " << std::endl;
    for (const auto& node : names) {
        std::cout << node.first << ": " << node.second << std::endl;
    }
     
    // 或者直接遍历YAML节点
    for (const auto& node : config["names"]) {
        std::cout << node.first << ": " << node.second << std::endl;
    }
}


// 使用yaml-cpp库提供的API读取和修改YAML文件
void modify_coco_yaml()
{
    std::cout << "modify_coco_yaml --------------------" << std::endl;
    // 加载YAML文件
    YAML::Node config = YAML::LoadFile("coco.yaml");

    // 获取指定路径下的值
    std::string path = config["path"].as<std::string>();
    std::cout << "path: " << path << std::endl;
    config["path"] = "./newdataset/coco";
    std::map<int, std::string> names = config["names"].as<std::map<int, std::string>>();
    std::cout << "names: " << std::endl;
    names[80] = "test";
    config["names"] = names;

    YAML::Emitter out;
    out << YAML::BeginMap;
    out << config;
    out << YAML::EndMap;

    std::ofstream outFile("new_coco.yaml");
    outFile << out.c_str();
    outFile.close();
}

// 使用yaml-cpp库提供的API创建YAML文件 
void  create_new_yaml_file()
{
    std::cout << "create_new_yaml_file --------------------" << std::endl;

    YAML::Emitter out;
    
    out << "test yaml!";

    /* A simple list. produce as:

        - eggs
        - bread
        - milk
    */
    out << YAML::BeginSeq;
    out << "eggs";
    out << "bread";
    out << "milk";
    out << YAML::EndSeq;
    
    /* A simple map. produce as:

        name: Ryan Braun
        position: LF

    */
    out << YAML::BeginMap;
    out << YAML::Key << "name";
    out << YAML::Value << "Ryan Braun";
    out << YAML::Key << "position";
    out << YAML::Value << "LF";
    out << YAML::EndMap;
     
    /* These elements can, of course, be nested. produce as:

        name1: Barack Obama
        children1:
            - Sasha
            - Malia
    */
    out << YAML::BeginMap;
    out << YAML::Key << "name1";
    out << YAML::Value << "Barack Obama";
    out << YAML::Key << "children1";
    out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq;
    out << YAML::EndMap;
    
    /* STL Containers. produce as:

        - [1, 4, 9, 16]
        -
        Daniel: 26
        Jesse: 24
    */
    std::vector <int> squares;
    squares.push_back(1);
    squares.push_back(4);
    squares.push_back(9);
    squares.push_back(16);

    std::map <std::string, int> ages;
    ages["Daniel"] = 26;
    ages["Jesse"] = 24;

    out << YAML::BeginSeq;
    out << YAML::Flow << squares;
    out << ages;
    out << YAML::EndSeq;


    std::cout << "yaml str: \n" << out.c_str() << std::endl;

    std::ofstream fileOut("yaml_test.yaml"); 
    fileOut << out.c_str();
    fileOut.close();
}

int main() 
{
    read_coco_yaml();
    modify_coco_yaml();
    create_new_yaml_file();
    return 0;
}

 coco.yaml

# Ultralytics YOLO 🚀, AGPL-3.0 license
# COCO 2017 dataset http://cocodataset.org by Microsoft
# Example usage: yolo train data=coco.yaml
# parent
# ├── ultralytics
# └── datasets
#     └── coco  ← downloads here (20.1 GB)


# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/coco  # dataset root dir
train: train2017.txt  # train images (relative to 'path') 118287 images
val: val2017.txt  # val images (relative to 'path') 5000 images
test: test-dev2017.txt  # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794

# Classes
names:
  0: person
  1: bicycle
  2: car
  3: motorcycle
  4: airplane
  5: bus
  6: train
  7: truck
  8: boat
  9: traffic light
  10: fire hydrant
  11: stop sign
  12: parking meter
  13: bench
  14: bird
  15: cat
  16: dog
  17: horse
  18: sheep
  19: cow
  20: elephant
  21: bear
  22: zebra
  23: giraffe
  24: backpack
  25: umbrella
  26: handbag
  27: tie
  28: suitcase
  29: frisbee
  30: skis
  31: snowboard
  32: sports ball
  33: kite
  34: baseball bat
  35: baseball glove
  36: skateboard
  37: surfboard
  38: tennis racket
  39: bottle
  40: wine glass
  41: cup
  42: fork
  43: knife
  44: spoon
  45: bowl
  46: banana
  47: apple
  48: sandwich
  49: orange
  50: broccoli
  51: carrot
  52: hot dog
  53: pizza
  54: donut
  55: cake
  56: chair
  57: couch
  58: potted plant
  59: bed
  60: dining table
  61: toilet
  62: tv
  63: laptop
  64: mouse
  65: remote
  66: keyboard
  67: cell phone
  68: microwave
  69: oven
  70: toaster
  71: sink
  72: refrigerator
  73: book
  74: clock
  75: vase
  76: scissors
  77: teddy bear
  78: hair drier
  79: toothbrush


# Download script/URL (optional)
download: |
  from ultralytics.utils.downloads import download
  from pathlib import Path

  # Download labels
  segments = True  # segment or box labels
  dir = Path(yaml['path'])  # dataset root dir
  url = 'https://github.com/ultralytics/yolov5/releases/download/v1.0/'
  urls = [url + ('coco2017labels-segments.zip' if segments else 'coco2017labels.zip')]  # labels
  download(urls, dir=dir.parent)
  # Download data
  urls = ['http://images.cocodataset.org/zips/train2017.zip',  # 19G, 118k images
          'http://images.cocodataset.org/zips/val2017.zip',  # 1G, 5k images
          'http://images.cocodataset.org/zips/test2017.zip']  # 7G, 41k images (optional)
  download(urls, dir=dir / 'images', threads=3)

参考资料

  1. How To Emit YAML · jbeder/yaml-cpp Wiki (github.com)
  2. Tutorial · jbeder/yaml-cpp Wiki (github.com)
  • 17
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老狼IT工作室

你的鼓励将是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值