Procházet zdrojové kódy

HDMI输出全屏显示, 标题使用配置的app_name

- DisplayOutput: 支持全屏(WINDOW_FULLSCREEN), 窗口1920x1080铺满显示器
- 标题改为读取 config.json 的 app_name(钢包工位视频监测系统)
- config: 新增 hdmi_fullscreen 开关
dev před 1 týdnem
rodič
revize
29d817e910
4 změnil soubory, kde provedl 40 přidání a 12 odebrání
  1. 1 0
      config/config.json
  2. 30 8
      src/display_output.cpp
  3. 4 2
      src/display_output.h
  4. 5 2
      src/main.cpp

+ 1 - 0
config/config.json

@@ -72,6 +72,7 @@
     ],
     "hdmi_output": true,
     "hdmi_grid_cols": 0,
+    "hdmi_fullscreen": true,
     "relay": {
         "alarm_max_sec": 30,
         "aliases": {

+ 30 - 8
src/display_output.cpp

@@ -7,10 +7,12 @@ DisplayOutput::~DisplayOutput() {
     stop();
 }
 
-bool DisplayOutput::start(bool enable, int grid_cols, const string& title) {
+bool DisplayOutput::start(bool enable, int grid_cols, const string& title,
+                          bool fullscreen) {
     enable_ = enable;
     grid_cols_ = grid_cols;
     title_ = title;
+    fullscreen_ = fullscreen;
     if (!enable_) return false;
     if (running_.load()) return true;
 
@@ -43,7 +45,21 @@ void DisplayOutput::setFrame(int channel, const cv::Mat& frame,
 void DisplayOutput::loop() {
     int fps_counter = 0;
     auto last_t = chrono::steady_clock::now();
-    char fps_buf[32];
+    char fps_buf[32] = {0};
+    bool window_ready = false;
+
+    // 窗口分辨率: 全屏时跟随实际屏幕分辨率
+    int wnd_w = kWndW, wnd_h = kWndH;
+    if (fullscreen_.load()) {
+        cv::namedWindow(title_, cv::WINDOW_NORMAL);
+        // 探测当前屏幕分辨率
+        cv::Mat probe = cv::Mat::zeros(1, 1, CV_8UC3);
+        cv::imshow(title_, probe);
+        cv::waitKey(1);
+        // 无直接API读分辨率, 用全屏属性让X自动拉伸, 但画布用1920x1080保证清晰
+        cv::setWindowProperty(title_, cv::WND_PROP_FULLSCREEN, cv::WINDOW_FULLSCREEN);
+        window_ready = true;
+    }
 
     while (running_.load()) {
         auto t0 = chrono::steady_clock::now();
@@ -56,8 +72,8 @@ void DisplayOutput::loop() {
 
         if (snap.empty()) {
             // 无画面: 显示黑色占位
-            cv::Mat black(kWndH, kWndW, CV_8UC3, cv::Scalar(10, 10, 10));
-            cv::putText(black, "ZoneAlarm - waiting for frames...",
+            cv::Mat black(wnd_h, wnd_w, CV_8UC3, cv::Scalar(10, 10, 10));
+            cv::putText(black, title_ + " - waiting for frames...",
                         cv::Point(50, 50), cv::FONT_HERSHEY_SIMPLEX, 1.0,
                         cv::Scalar(255, 255, 255), 2);
             cv::imshow(title_, black);
@@ -70,9 +86,9 @@ void DisplayOutput::loop() {
             }
             int rows = (n + cols - 1) / cols;
 
-            int cell_w = kWndW / cols;
-            int cell_h = kWndH / rows;
-            cv::Mat canvas(kWndH, kWndW, CV_8UC3, cv::Scalar(20, 20, 20));
+            int cell_w = wnd_w / cols;
+            int cell_h = wnd_h / rows;
+            cv::Mat canvas(wnd_h, wnd_w, CV_8UC3, cv::Scalar(20, 20, 20));
 
             int idx = 0;
             for (auto& [ch, p] : snap) {
@@ -113,7 +129,7 @@ void DisplayOutput::loop() {
                 last_t = t1;
             }
             if (fps_buf[0]) {
-                cv::putText(canvas, fps_buf, cv::Point(kWndW - 100, 30),
+                cv::putText(canvas, fps_buf, cv::Point(wnd_w - 100, 30),
                             cv::FONT_HERSHEY_SIMPLEX, 0.7,
                             cv::Scalar(0, 255, 0), 2);
             }
@@ -121,6 +137,12 @@ void DisplayOutput::loop() {
             cv::imshow(title_, canvas);
         }
 
+        if (!window_ready) {
+            cv::namedWindow(title_, cv::WINDOW_NORMAL);
+            cv::setWindowProperty(title_, cv::WND_PROP_FULLSCREEN, cv::WINDOW_FULLSCREEN);
+            window_ready = true;
+        }
+
         cv::waitKey(1);
 
         // 目标 15 FPS 刷新

+ 4 - 2
src/display_output.h

@@ -14,8 +14,9 @@ public:
     DisplayOutput() = default;
     ~DisplayOutput();
 
-    // 初始化: enable=启用输出, grid_cols=网格列数(0=自动)
-    bool start(bool enable, int grid_cols = 0, const std::string& title = "ZoneAlarm");
+    // 初始化: enable=启用输出, grid_cols=网格列数(0=自动), fullscreen=全屏显示
+    bool start(bool enable, int grid_cols = 0, const std::string& title = "ZoneAlarm",
+               bool fullscreen = true);
     void stop();
 
     void setFrame(int channel, const cv::Mat& frame, const std::string& label);
@@ -27,6 +28,7 @@ private:
 
     std::atomic<bool> running_{false};
     std::atomic<bool> enable_{false};
+    std::atomic<bool> fullscreen_{false};
     std::thread worker_;
     std::string title_ = "ZoneAlarm";
     int grid_cols_ = 0;

+ 5 - 2
src/main.cpp

@@ -299,10 +299,13 @@ int main(int argc, char* argv[]) {
     int alarm_retention_days = cfg.value("alarm_retention_days", 30);
 
     // ========== 本机画面输出(HDMI显示器) ==========
+    string app_name = cfg.value("app_name", "钢包工位视频监测系统");
     bool hdmi_output = cfg.value("hdmi_output", true);
     int hdmi_grid_cols = cfg.value("hdmi_grid_cols", 0);
+    bool hdmi_fullscreen = cfg.value("hdmi_fullscreen", true);
     cout << "[Display] HDMI画面输出: " << (hdmi_output ? "启用" : "禁用")
-         << " 网格列=" << hdmi_grid_cols << endl;
+         << " 网格列=" << hdmi_grid_cols
+         << " 全屏=" << (hdmi_fullscreen ? "是" : "否") << endl;
 
     // ========== 姿态识别(跌倒检测) ==========
     string pose_model_path = cfg.value("pose_model_path",
@@ -1459,7 +1462,7 @@ int main(int argc, char* argv[]) {
     });
 
     web.start();
-    displayOutput.start(hdmi_output, hdmi_grid_cols, "ZoneAlarm - 钢包工位视频监测");
+    displayOutput.start(hdmi_output, hdmi_grid_cols, app_name, hdmi_fullscreen);
     cout << "[Main] Ctrl+C 退出" << endl;
 
     // 自动激活第一个工位(如果有配置)