#include "renderer.hpp" #include "../common/logger.hpp" #include namespace pipeline { bool Renderer::init(const renderer::RendererConfig& config) { if (initialized_) { Logger::warning("Renderer already initialized"); return true; } config_ = config; initialized_ = true; last_metrics_update_ = std::chrono::steady_clock::now(); // 如果不是测试模式,创建显示窗口 if (!config_.test_mode) { cv::namedWindow(config_.window_name, cv::WINDOW_NORMAL); cv::resizeWindow(config_.window_name, config_.window_width, config_.window_height); if (config_.fullscreen) { cv::setWindowProperty(config_.window_name, cv::WND_PROP_FULLSCREEN, cv::WINDOW_FULLSCREEN); } } Logger::info("Renderer initialized successfully"); return true; } bool Renderer::render(const cv::Mat& frame, const std::vector& results, const PerformanceMetrics& metrics) { if (!initialized_) { Logger::error("Renderer not initialized"); return false; } if (frame.empty()) { Logger::error("Input frame is empty"); return false; } try { // 创建帧的副本用于绘制 cv::Mat display_frame = frame.clone(); // 绘制检测结果 drawDetections(display_frame, results); // 绘制性能指标 if (config_.metrics.show_fps || config_.metrics.show_inference_time || config_.metrics.show_gpu_usage) { drawMetrics(display_frame, metrics); } // 显示或保存结果 if (!config_.test_mode) { cv::imshow(config_.window_name, display_frame); cv::waitKey(1); } last_frame_ = display_frame; // 保存最后渲染的帧 return true; } catch (const cv::Exception& e) { Logger::error("OpenCV error in render: " + std::string(e.what())); return false; } catch (const std::exception& e) { Logger::error("Error in render: " + std::string(e.what())); return false; } } void Renderer::drawDetections(cv::Mat& frame, const std::vector& results) { for (const auto& det : results) { // 获取类别样式 const auto& style = config_.class_styles.count(det.label) > 0 ? config_.class_styles.at(det.label) : config_.default_style; // 绘制边界框 cv::rectangle(frame, det.bbox, style.box_color, style.box_thickness); // 准备标签文本 std::stringstream ss; ss << det.label << " " << std::fixed << std::setprecision(2) << det.confidence; std::string label_text = ss.str(); // 绘制标签背景 cv::Point text_pos(det.bbox.x, det.bbox.y - 5); cv::Size text_size = cv::getTextSize(label_text, cv::FONT_HERSHEY_SIMPLEX, style.font_scale, style.font_thickness, nullptr); cv::rectangle(frame, cv::Point(text_pos.x, text_pos.y - text_size.height), cv::Point(text_pos.x + text_size.width, text_pos.y + 5), style.box_color, -1); // 绘制标签文本 drawText(frame, label_text, text_pos, style); } } void Renderer::drawMetrics(cv::Mat& frame, const PerformanceMetrics& metrics) { const auto& style = config_.default_style; int y_offset = 30; if (config_.metrics.show_fps) { std::stringstream ss; ss << "FPS: " << std::fixed << std::setprecision(1) << metrics.fps; drawText(frame, ss.str(), cv::Point(10, y_offset), style); y_offset += 30; } if (config_.metrics.show_inference_time) { std::stringstream ss; ss << "Inference: " << std::fixed << std::setprecision(1) << metrics.inference_time_ms << "ms"; drawText(frame, ss.str(), cv::Point(10, y_offset), style); y_offset += 30; } if (config_.metrics.show_gpu_usage) { std::stringstream ss; ss << "GPU: " << std::fixed << std::setprecision(1) << metrics.gpu_usage_percent << "%"; drawText(frame, ss.str(), cv::Point(10, y_offset), style); } } void Renderer::drawText(cv::Mat& frame, const std::string& text, const cv::Point& pos, const renderer::RendererConfig::ClassStyle& style) { cv::putText(frame, text, pos, cv::FONT_HERSHEY_SIMPLEX, style.font_scale, style.text_color, style.font_thickness); } void Renderer::cleanup() { if (initialized_ && !config_.test_mode) { cv::destroyWindow(config_.window_name); } initialized_ = false; } } // namespace pipeline