rtsp_tensorrt/pipeline/common/yaml_config_parser.cpp

552 lines
20 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "yaml_config_parser.hpp"
#include "../common/logger.hpp"
#include <filesystem>
#include <iostream>
#include <opencv2/core.hpp>
#include <unordered_set>
namespace pipeline {
bool YamlConfigParser::parse(const std::string& config_file) {
try {
Logger::info("Parsing config file: " + config_file);
yaml_config_ = YAML::LoadFile(config_file);
// 解析各个配置部分
if (!parseInputConfig(yaml_config_["input"])) {
Logger::error("Failed to parse input config");
return false;
}
if (!parseModelConfig(yaml_config_["inference"])) {
Logger::error("Failed to parse model config");
return false;
}
if (!parseRenderConfig(yaml_config_["render"])) {
Logger::error("Failed to parse render config");
return false;
}
if (!parseOutputConfig(yaml_config_["output"])) {
Logger::error("Failed to parse output config");
return false;
}
if (!parseLogConfig(yaml_config_["log"])) {
Logger::error("Failed to parse log config");
return false;
}
Logger::info("Successfully parsed all configurations");
return true;
} catch (const YAML::Exception& e) {
Logger::error("YAML parsing error: " + std::string(e.what()));
return false;
} catch (const std::exception& e) {
Logger::error("Error in parse: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::validate() {
// 基本验证
if (config_.input.sources.empty()) {
Logger::error("No input sources configured");
return false;
}
// 验证输入源名称唯一性
std::unordered_set<std::string> source_names;
for (const auto& source : config_.input.sources) {
if (!source_names.insert(source.name).second) {
Logger::error("Duplicate input source name: " + source.name);
return false;
}
}
// 验证输出目标名称唯一性
std::unordered_set<std::string> target_names;
for (const auto& target : config_.output.targets) {
if (!target_names.insert(target.name).second) {
Logger::error("Duplicate output target name: " + target.name);
return false;
}
}
// 收集所有有效的输出目标名称
std::unordered_set<std::string> valid_output_names;
for (const auto& target : config_.output.targets) {
valid_output_names.insert(target.name);
}
// 验证输入源配置
for (auto& source : config_.input.sources) {
if (source.type.empty() || source.name.empty()) {
Logger::error("Input source missing type or name");
return false;
}
if (source.type == "rtsp" && source.url.empty()) {
Logger::error("RTSP source missing URL");
return false;
}
if (source.buffer_size <= 0) {
Logger::error("Invalid buffer size for source: " + source.name);
return false;
}
// 如果没有指定输出目标,使用所有可用的输出目标
if (source.outputs.empty() && !valid_output_names.empty()) {
Logger::info("No output targets specified for source '" + source.name + "', using all available targets");
source.outputs.insert(source.outputs.end(),
valid_output_names.begin(),
valid_output_names.end());
}
// 验证输出目标映射
else if (!source.outputs.empty()) {
for (const auto& output : source.outputs) {
if (valid_output_names.find(output) == valid_output_names.end()) {
Logger::error("Invalid output target '" + output + "' specified for input source '" + source.name + "'");
return false;
}
}
}
}
// 验证推理配置
if (config_.inference.engine_path.empty()) {
Logger::error("Model engine path not specified");
return false;
}
if (config_.inference.input_shape.empty()) {
Logger::error("Model input shape not specified");
return false;
}
if (config_.inference.threshold.conf < 0.0f || config_.inference.threshold.conf > 1.0f) {
Logger::error("Invalid confidence threshold (must be between 0.0 and 1.0)");
return false;
}
if (config_.inference.threshold.nms < 0.0f || config_.inference.threshold.nms > 1.0f) {
Logger::error("Invalid NMS threshold (must be between 0.0 and 1.0)");
return false;
}
// 验证渲染配置
// 验证窗口配置
if (config_.render.window.width <= 0 || config_.render.window.height <= 0) {
Logger::error("Invalid window dimensions");
return false;
}
if (config_.render.window.name.empty()) {
Logger::error("Window name not specified");
return false;
}
// 验证默认样式
if (config_.render.default_style.transparency < 0.0f ||
config_.render.default_style.transparency > 1.0f) {
Logger::error("Invalid default style transparency (must be between 0.0 and 1.0)");
return false;
}
if (config_.render.default_style.box_thickness <= 0 ||
config_.render.default_style.font_thickness <= 0) {
Logger::error("Invalid default style thickness values");
return false;
}
if (config_.render.default_style.font_scale <= 0.0) {
Logger::error("Invalid default style font scale");
return false;
}
// 验证类别样式
for (const auto& [class_name, style] : config_.render.class_styles) {
if (class_name.empty()) {
Logger::error("Empty class name in style configuration");
return false;
}
if (style.transparency < 0.0f || style.transparency > 1.0f) {
Logger::error("Invalid transparency for class " + class_name);
return false;
}
if (style.box_thickness <= 0 || style.font_thickness <= 0) {
Logger::error("Invalid thickness values for class " + class_name);
return false;
}
if (style.font_scale <= 0.0) {
Logger::error("Invalid font scale for class " + class_name);
return false;
}
}
// 验证性能指标配置
if (config_.render.metrics.update_interval_ms <= 0) {
Logger::error("Invalid metrics update interval");
return false;
}
// 验证输出配置
for (const auto& target : config_.output.targets) {
if (target.type.empty() || target.name.empty()) {
Logger::error("Output target missing type or name");
return false;
}
if (target.type == "video") {
if (target.path.empty()) {
Logger::error("Video output target missing path");
return false;
}
if (target.fps <= 0) {
Logger::error("Invalid video output fps");
return false;
}
if (target.bitrate <= 0) {
Logger::error("Invalid video output bitrate");
return false;
}
if (target.codec.empty()) {
Logger::error("Video output codec not specified");
return false;
}
}
}
// 验证日志配置
if (config_.log.level.empty()) {
Logger::error("Log level not specified");
return false;
}
if (config_.log.save_path.empty()) {
Logger::error("Log save path not specified");
return false;
}
return true;
}
bool YamlConfigParser::parseInputConfig(const YAML::Node& node) {
try {
// 解析输入源
if (node["sources"]) {
for (const auto& source : node["sources"]) {
InputSourceConfig src_config;
src_config.type = source["type"].as<std::string>();
src_config.name = source["name"].as<std::string>();
if (source["url"]) {
src_config.url = source["url"].as<std::string>();
}
if (source["buffer_size"]) {
src_config.buffer_size = source["buffer_size"].as<int>();
}
// 解析输出目标列表
if (source["output_targets"]) {
src_config.outputs = source["output_targets"].as<std::vector<std::string>>();
}
// 向后兼容如果没有output_targets字段检查旧的outputs字段
else if (source["outputs"]) {
src_config.outputs = source["outputs"].as<std::vector<std::string>>();
}
// 如果都没有指定将在validate阶段添加所有可用的输出目标
config_.input.sources.push_back(src_config);
}
}
// 解析批处理大小
if (node["max_batch_size"]) {
config_.input.max_batch_size = node["max_batch_size"].as<int>();
}
return true;
} catch (const YAML::Exception& e) {
Logger::error("Error parsing input config: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::parseModelConfig(const YAML::Node& node) {
try {
if (!node["model"]) {
Logger::error("Model configuration section not found");
return false;
}
const auto& model = node["model"];
// 检查必需的字段
if (!model["onnx_path"]) {
Logger::error("ONNX path not specified in model config");
return false;
}
if (!model["engine_path"]) {
Logger::error("Engine path not specified in model config");
return false;
}
if (!model["input_shape"]) {
Logger::error("Input shape not specified in model config");
return false;
}
// 读取配置
config_.inference.engine_path = model["engine_path"].as<std::string>();
config_.inference.input_shape = model["input_shape"].as<std::vector<int>>();
config_.inference.precision = model["precision"] ? model["precision"].as<std::string>() : "FP16";
// 读取可选的版本和标签配置
if (model["version"]) {
config_.inference.version = model["version"].as<std::string>();
}
if (model["labels"]) {
config_.inference.labels = model["labels"].as<std::vector<std::string>>();
}
// 读取阈值配置
if (node["threshold"]) {
config_.inference.threshold.conf = node["threshold"]["conf"] ?
node["threshold"]["conf"].as<float>() : 0.5f;
config_.inference.threshold.nms = node["threshold"]["nms"] ?
node["threshold"]["nms"].as<float>() : 0.45f;
}
// 读取GPU设备ID
config_.inference.gpu_id = node["gpu_id"] ? node["gpu_id"].as<int>() : 0;
// 打印加载的配置信息
Logger::info("Loaded model configuration:");
Logger::info(" Engine path: " + config_.inference.engine_path);
Logger::info(" Input shape: " + std::to_string(config_.inference.input_shape[0]) + "," +
std::to_string(config_.inference.input_shape[1]) + "," +
std::to_string(config_.inference.input_shape[2]));
Logger::info(" Precision: " + config_.inference.precision);
Logger::info(" GPU ID: " + std::to_string(config_.inference.gpu_id));
Logger::info(" Confidence threshold: " + std::to_string(config_.inference.threshold.conf));
Logger::info(" NMS threshold: " + std::to_string(config_.inference.threshold.nms));
if (!config_.inference.version.empty()) {
Logger::info(" Version: " + config_.inference.version);
}
if (!config_.inference.labels.empty()) {
std::string labels_str = " Labels: ";
for (const auto& label : config_.inference.labels) {
labels_str += label + ", ";
}
labels_str = labels_str.substr(0, labels_str.length() - 2); // 移除最后的", "
Logger::info(labels_str);
}
return true;
} catch (const YAML::Exception& e) {
Logger::error("Error parsing model config: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::parseRenderConfig(const YAML::Node& node) {
try {
// 解析渲染启用状态
if (node["enable"]) {
config_.render.enable = node["enable"].as<bool>();
}
// 解析窗口配置
if (node["window"]) {
const auto& window = node["window"];
if (window["name"]) {
config_.render.window.name = window["name"].as<std::string>();
}
if (window["width"]) {
config_.render.window.width = window["width"].as<int>();
}
if (window["height"]) {
config_.render.window.height = window["height"].as<int>();
}
if (window["fullscreen"]) {
config_.render.window.fullscreen = window["fullscreen"].as<bool>();
}
}
// 解析默认样式
if (node["default_style"]) {
const auto& style = node["default_style"];
if (style["box_color"]) {
auto color = style["box_color"].as<std::vector<int>>();
if (color.size() >= 3) {
config_.render.default_style.box_color = cv::Scalar(color[0], color[1], color[2]);
}
}
if (style["text_color"]) {
auto color = style["text_color"].as<std::vector<int>>();
if (color.size() >= 3) {
config_.render.default_style.text_color = cv::Scalar(color[0], color[1], color[2]);
}
}
if (style["transparency"]) {
config_.render.default_style.transparency = style["transparency"].as<float>();
}
if (style["box_thickness"]) {
config_.render.default_style.box_thickness = style["box_thickness"].as<int>();
}
if (style["font_scale"]) {
config_.render.default_style.font_scale = style["font_scale"].as<double>();
}
if (style["font_thickness"]) {
config_.render.default_style.font_thickness = style["font_thickness"].as<int>();
}
}
// 解析类别样式
if (node["class_styles"]) {
for (const auto& class_style : node["class_styles"]) {
std::string class_name = class_style.first.as<std::string>();
const auto& style = class_style.second;
RenderConfig::ClassStyle class_config;
if (style["box_color"]) {
auto color = style["box_color"].as<std::vector<int>>();
if (color.size() >= 3) {
class_config.box_color = cv::Scalar(color[0], color[1], color[2]);
}
}
if (style["text_color"]) {
auto color = style["text_color"].as<std::vector<int>>();
if (color.size() >= 3) {
class_config.text_color = cv::Scalar(color[0], color[1], color[2]);
}
}
if (style["transparency"]) {
class_config.transparency = style["transparency"].as<float>();
}
if (style["box_thickness"]) {
class_config.box_thickness = style["box_thickness"].as<int>();
}
if (style["font_scale"]) {
class_config.font_scale = style["font_scale"].as<double>();
}
if (style["font_thickness"]) {
class_config.font_thickness = style["font_thickness"].as<int>();
}
config_.render.class_styles[class_name] = class_config;
}
}
// 解析性能指标配置
if (node["metrics"]) {
const auto& metrics = node["metrics"];
if (metrics["show_fps"]) {
config_.render.metrics.show_fps = metrics["show_fps"].as<bool>();
}
if (metrics["show_inference_time"]) {
config_.render.metrics.show_inference_time = metrics["show_inference_time"].as<bool>();
}
if (metrics["show_gpu_usage"]) {
config_.render.metrics.show_gpu_usage = metrics["show_gpu_usage"].as<bool>();
}
if (metrics["update_interval_ms"]) {
config_.render.metrics.update_interval_ms = metrics["update_interval_ms"].as<int>();
}
}
return true;
} catch (const YAML::Exception& e) {
Logger::error("Error parsing render config: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::parseOutputConfig(const YAML::Node& node) {
try {
if (node["targets"]) {
for (const auto& target : node["targets"]) {
OutputTargetConfig target_config;
target_config.type = target["type"].as<std::string>();
target_config.name = target["name"].as<std::string>();
if (target["path"]) {
target_config.path = target["path"].as<std::string>();
}
if (target["fps"]) {
target_config.fps = target["fps"].as<int>();
}
if (target["codec"]) {
target_config.codec = target["codec"].as<std::string>();
}
if (target["bitrate"]) {
target_config.bitrate = target["bitrate"].as<int>();
}
config_.output.targets.push_back(target_config);
}
}
return true;
} catch (const YAML::Exception& e) {
return false;
}
}
bool YamlConfigParser::parseLogConfig(const YAML::Node& node) {
try {
// 检查必需的字段
if (!node["level"]) {
Logger::error("Log level not specified");
return false;
}
if (!node["save_path"]) {
Logger::error("Log save path not specified");
return false;
}
// 读取配置
std::string level = node["level"].as<std::string>();
// 验证日志级别是否有效
if (level.empty() || (level != "debug" && level != "info" && level != "warn" && level != "error")) {
Logger::error("Invalid log level: " + level);
return false;
}
config_.log.level = level;
config_.log.save_path = node["save_path"].as<std::string>();
return true;
} catch (const YAML::Exception& e) {
Logger::error("Error parsing log config: " + std::string(e.what()));
return false;
}
}
bool YamlConfigParser::parseRtspConfig(const YAML::Node& config, RtspReader::Config& rtsp_config) {
try {
auto rtsp_node = config["rtsp"];
if (!rtsp_node) {
return false;
}
// 设置默认值
rtsp_config = RtspReader::Config();
// 读取配置
if (rtsp_node["buffer_size"]) {
rtsp_config.buffer_size = rtsp_node["buffer_size"].as<int>();
}
if (rtsp_node["max_retry_count"]) {
rtsp_config.max_retry_count = rtsp_node["max_retry_count"].as<int>();
}
if (rtsp_node["retry_interval_ms"]) {
rtsp_config.retry_interval_ms = rtsp_node["retry_interval_ms"].as<int>();
}
if (rtsp_node["frame_timeout_ms"]) {
rtsp_config.frame_timeout_ms = rtsp_node["frame_timeout_ms"].as<int>();
}
if (rtsp_node["target_fps"]) {
rtsp_config.target_fps = rtsp_node["target_fps"].as<float>();
}
return true;
} catch (const YAML::Exception& e) {
Logger::error("Error parsing RTSP config: " + std::string(e.what()));
return false;
}
}
// 工厂函数实现
std::unique_ptr<ConfigParser> createConfigParser() {
return std::make_unique<YamlConfigParser>();
}
} // namespace pipeline