Commit 6c828f54 by yhb

Merge branch 'Wangbing1' of git.patzn.com:root/Oil_Level_Recognition_System into Wangbing1

parent a965fd26
......@@ -33,7 +33,7 @@ channel4:
channel1:
general:
task_id: '1'
task_name: 曲线
task_name: 历史回放功能展示
area_count: 0
safe_low: 2.0mm
safe_high: 10.0mm
......@@ -41,7 +41,7 @@ channel1:
video_format: AVI
push_address: ''
video_path: ''
save_liquid_data_path: D:\restructure\liquid_level_line_detection_system\database\mission_result\1_曲线
save_liquid_data_path: d:\restructure\liquid_level_line_detection_system\database\mission_result\1_历史回放功能展示
areas:
area_1: 通道1_区域1
area_heights:
......
......@@ -10,19 +10,23 @@ address_list: 'rtsp://admin:cei345678@192.168.0.121:8000/stream1
batch_processing_enabled: false
channel1:
name: 通道1
address: rtsp://admin:cei345678@192.168.2.126:8000/stream1
address: ''
file_path: D:/record/通道1/camera_1_20251202_101042.avi
channel1_model_path: database/model/detection_model/bestmodel/best.dat
channel2:
name: 通道2
address: rtsp://admin:cei345678@192.168.2.27:8000/stream1
file_path: ''
channel2_model_path: database/model/detection_model/bestmodel/best.dat
channel3:
name: 通道3
address: rtsp://admin:cei345678@192.168.2.121:8000/stream1
file_path: ''
channel3_model_path: database/model/detection_model/bestmodel/best.dat
channel4:
name: 通道4
address: rtsp://admin:cei345678@192.168.0.127:8000/stream1
file_path: ''
channel4_model_path: database/model/detection_model/bestmodel/best.dat
classes:
- color: '#FF0000'
......
++ "b/database/mission_result/1_\345\216\206\345\217\262\345\233\236\346\224\276\345\212\237\350\203\275\345\261\225\347\244\272/\351\200\232\351\201\2231_\345\214\272\345\237\2371.csv"
++ "b/database/mission_result/1_\345\216\206\345\217\262\345\233\236\346\224\276\345\212\237\350\203\275\345\261\225\347\244\272/\351\200\232\351\201\2231_\345\214\272\345\237\2372.csv"
2025-12-02-11:20:31.608 0.0
2025-12-02-11:20:31.608 0.0
......@@ -2949,3 +2949,253 @@
2025-12-02-12:33:31.974 0.0
2025-12-02-12:33:32.178 0.0
2025-12-02-12:33:32.554 0.0
2025-12-02-13:13:29.373 0.0
2025-12-02-13:13:29.481 0.0
2025-12-02-13:13:29.785 0.0
2025-12-02-13:13:29.966 0.0
2025-12-02-13:13:30.129 0.0
2025-12-02-13:13:30.314 0.0
2025-12-02-13:13:30.533 0.0
2025-12-02-13:13:30.732 0.0
2025-12-02-13:13:30.935 0.0
2025-12-02-13:13:31.206 0.0
2025-12-02-13:13:31.387 0.0
2025-12-02-13:13:31.585 0.0
2025-12-02-13:13:31.808 0.0
2025-12-02-13:13:31.978 0.0
2025-12-02-13:13:32.165 0.0
2025-12-02-13:13:32.364 0.0
2025-12-02-13:13:32.578 0.0
2025-12-02-13:13:32.778 0.0
2025-12-02-13:13:32.992 0.0
2025-12-02-13:13:33.163 0.0
2025-12-02-13:13:33.378 0.0
2025-12-02-13:13:33.543 0.0
2025-12-02-13:13:33.766 0.0
2025-12-02-13:13:33.955 0.0
2025-12-02-13:13:34.177 0.0
2025-12-02-13:13:34.403 0.0
2025-12-02-13:13:34.586 0.0
2025-12-02-13:13:34.787 0.0
2025-12-02-13:13:34.993 0.0
2025-12-02-13:13:35.171 0.0
2025-12-02-13:13:35.405 0.0
2025-12-02-13:13:35.651 0.0
2025-12-02-13:13:35.853 0.0
2025-12-02-13:13:36.032 0.0
2025-12-02-13:13:36.206 0.0
2025-12-02-13:13:36.440 0.0
2025-12-02-13:13:36.619 0.0
2025-12-02-13:13:36.798 0.0
2025-12-02-13:13:37.030 0.0
2025-12-02-13:13:37.244 0.0
2025-12-02-13:13:37.416 0.0
2025-12-02-13:13:37.656 0.0
2025-12-02-13:13:37.853 0.0
2025-12-02-13:13:38.053 0.0
2025-12-02-13:13:38.230 0.0
2025-12-02-13:13:38.444 0.0
2025-12-02-13:13:38.678 0.0
2025-12-02-13:13:38.873 0.0
2025-12-02-13:13:39.091 0.0
2025-12-02-13:13:39.281 0.0
2025-12-02-13:13:39.480 0.0
2025-12-02-13:13:39.657 0.0
2025-12-02-13:13:39.903 0.0
2025-12-02-13:13:40.122 0.0
2025-12-02-13:13:40.266 0.0
2025-12-02-13:13:40.468 0.0
2025-12-02-13:13:40.665 0.0
2025-12-02-13:13:40.867 0.0
2025-12-02-13:13:41.110 0.0
2025-12-02-13:13:41.328 0.0
2025-12-02-13:13:41.512 0.0
2025-12-02-13:13:41.717 0.0
2025-12-02-13:13:41.880 0.0
2025-12-02-13:13:42.098 0.0
2025-12-02-13:13:42.299 0.0
2025-12-02-13:13:42.524 0.0
2025-12-02-13:13:42.707 0.0
2025-12-02-13:13:42.906 0.0
2025-12-02-13:13:43.113 0.0
2025-12-02-13:13:43.339 0.0
2025-12-02-13:13:43.543 0.0
2025-12-02-13:13:43.732 0.0
2025-12-02-13:13:43.951 0.0
2025-12-02-13:13:44.171 0.0
2025-12-02-13:13:44.366 0.0
2025-12-02-13:13:44.569 0.0
2025-12-02-13:13:44.730 0.0
2025-12-02-13:13:44.967 0.0
2025-12-02-13:13:45.163 0.0
2025-12-02-13:13:45.522 0.0
2025-12-02-13:13:45.772 0.0
2025-12-02-13:13:45.982 0.0
2025-12-02-13:13:46.217 0.0
2025-12-02-13:13:46.500 0.0
2025-12-02-13:13:46.769 0.0
2025-12-02-13:13:47.020 0.0
2025-12-02-13:13:47.290 0.0
2025-12-02-13:13:47.483 0.0
2025-12-02-13:13:47.716 0.0
2025-12-02-13:13:47.950 0.0
2025-12-02-13:13:48.176 0.0
2025-12-02-13:13:48.409 0.0
2025-12-02-13:13:48.738 0.0
2025-12-02-13:13:48.977 0.0
2025-12-02-13:13:49.194 0.0
2025-12-02-13:13:49.519 0.0
2025-12-02-13:13:49.720 0.0
2025-12-02-13:13:49.947 0.0
2025-12-02-13:13:50.115 0.0
2025-12-02-13:13:50.256 0.0
2025-12-02-13:13:50.482 0.0
2025-12-02-13:13:50.706 0.0
2025-12-02-13:13:50.916 0.0
2025-12-02-13:13:51.181 0.0
2025-12-02-13:13:51.478 0.0
2025-12-02-13:13:51.680 0.0
2025-12-02-13:13:51.823 0.0
2025-12-02-13:13:52.067 0.0
2025-12-02-13:13:52.318 0.0
2025-12-02-13:13:53.091 0.0
2025-12-02-13:13:53.482 0.0
2025-12-02-13:13:53.750 0.0
2025-12-02-13:13:54.020 0.0
2025-12-02-13:13:54.259 0.0
2025-12-02-13:13:54.499 0.0
2025-12-02-13:13:54.709 0.0
2025-12-02-13:13:54.932 0.0
2025-12-02-13:13:55.232 0.0
2025-12-02-13:13:55.461 0.0
2025-12-02-13:13:55.721 0.0
2025-12-02-13:13:56.105 0.0
2025-12-02-13:13:56.417 0.0
2025-12-02-13:13:56.930 0.0
2025-12-02-13:13:57.269 0.0
2025-12-02-13:13:57.622 0.0
2025-12-02-13:13:57.861 0.0
2025-12-02-13:13:58.123 0.0
2025-12-02-13:13:58.408 0.0
2025-12-02-13:13:58.756 0.0
2025-12-02-13:13:59.001 0.0
2025-12-02-13:13:59.213 0.0
2025-12-02-13:13:59.409 0.0
2025-12-02-13:13:59.636 0.0
2025-12-02-13:13:59.821 0.0
2025-12-02-13:14:00.055 0.0
2025-12-02-13:14:00.225 0.0
2025-12-02-13:14:00.479 0.0
2025-12-02-13:14:00.679 0.0
2025-12-02-13:14:00.878 0.0
2025-12-02-13:14:01.054 0.0
2025-12-02-13:14:01.274 0.0
2025-12-02-13:14:01.492 0.0
2025-12-02-13:14:01.735 0.0
2025-12-02-13:14:02.003 0.0
2025-12-02-13:14:02.206 0.0
2025-12-02-13:14:02.470 0.0
2025-12-02-13:14:02.732 0.0
2025-12-02-13:14:02.953 0.0
2025-12-02-13:14:03.135 0.0
2025-12-02-13:14:03.379 0.0
2025-12-02-13:14:03.596 0.0
2025-12-02-13:14:03.804 0.0
2025-12-02-13:14:04.029 0.0
2025-12-02-13:14:04.250 0.0
2025-12-02-13:14:04.516 0.0
2025-12-02-13:14:04.759 0.0
2025-12-02-13:14:05.008 0.0
2025-12-02-13:14:05.248 0.0
2025-12-02-13:14:05.496 0.0
2025-12-02-13:14:05.713 0.0
2025-12-02-13:14:05.918 0.0
2025-12-02-13:14:06.157 0.0
2025-12-02-13:14:06.422 0.0
2025-12-02-13:14:06.699 0.0
2025-12-02-13:14:07.009 0.0
2025-12-02-13:14:07.322 0.0
2025-12-02-13:14:07.666 0.0
2025-12-02-13:14:07.923 0.0
2025-12-02-13:14:08.182 0.0
2025-12-02-13:14:08.383 0.0
2025-12-02-13:14:08.629 0.0
2025-12-02-13:14:08.862 0.0
2025-12-02-13:14:09.089 0.0
2025-12-02-13:14:09.331 0.0
2025-12-02-13:14:09.587 0.0
2025-12-02-13:14:09.807 0.0
2025-12-02-13:14:10.043 0.0
2025-12-02-13:14:10.267 0.0
2025-12-02-13:14:10.561 0.0
2025-12-02-13:14:10.790 0.0
2025-12-02-13:14:11.020 0.0
2025-12-02-13:14:11.248 0.0
2025-12-02-13:14:11.456 0.0
2025-12-02-13:14:11.698 0.0
2025-12-02-13:14:11.903 0.0
2025-12-02-13:14:12.113 0.0
2025-12-02-13:14:12.291 0.0
2025-12-02-13:14:12.625 0.0
2025-12-02-13:14:12.843 0.0
2025-12-02-13:14:13.053 0.0
2025-12-02-13:14:13.273 0.0
2025-12-02-13:14:13.456 0.0
2025-12-02-13:14:13.677 0.0
2025-12-02-13:14:13.884 0.0
2025-12-02-13:14:14.096 0.0
2025-12-02-13:14:14.258 0.0
2025-12-02-13:14:14.518 0.0
2025-12-02-13:14:14.699 0.0
2025-12-02-13:14:14.997 0.0
2025-12-02-13:14:15.257 0.0
2025-12-02-13:14:15.485 0.0
2025-12-02-13:14:15.740 0.0
2025-12-02-13:14:16.007 0.0
2025-12-02-13:14:16.182 0.0
2025-12-02-13:14:16.479 0.0
2025-12-02-13:14:16.710 0.0
2025-12-02-13:14:16.948 0.0
2025-12-02-13:14:17.203 0.0
2025-12-02-13:14:17.582 0.0
2025-12-02-13:14:17.824 0.0
2025-12-02-13:14:18.056 0.0
2025-12-02-13:14:18.275 0.0
2025-12-02-13:14:18.513 0.0
2025-12-02-13:14:18.771 0.0
2025-12-02-13:14:19.026 0.0
2025-12-02-13:14:19.282 0.0
2025-12-02-13:14:19.548 0.0
2025-12-02-13:14:19.763 0.0
2025-12-02-13:14:20.006 0.0
2025-12-02-13:14:20.227 0.0
2025-12-02-13:14:20.474 0.0
2025-12-02-13:14:20.717 0.0
2025-12-02-13:14:20.989 0.0
2025-12-02-13:14:21.211 0.0
2025-12-02-13:14:21.444 0.0
2025-12-02-13:14:21.642 0.0
2025-12-02-13:14:21.860 0.0
2025-12-02-13:14:22.074 0.0
2025-12-02-13:14:22.280 0.0
2025-12-02-13:14:22.503 0.0
2025-12-02-13:14:22.710 0.0
2025-12-02-13:14:22.942 0.0
2025-12-02-13:14:23.162 0.0
2025-12-02-13:14:23.356 0.0
2025-12-02-13:14:23.603 0.0
2025-12-02-13:14:23.825 0.0
2025-12-02-13:14:24.042 0.0
2025-12-02-13:14:24.242 0.0
2025-12-02-13:14:24.506 0.0
2025-12-02-13:14:24.725 0.0
2025-12-02-13:14:24.934 0.0
2025-12-02-13:14:25.135 0.0
2025-12-02-13:14:25.347 0.0
2025-12-02-13:14:25.522 0.0
2025-12-02-13:14:25.768 0.0
2025-12-02-13:14:25.973 0.0
2025-12-02-13:14:26.151 0.0
2025-12-02-13:14:26.371 0.0
2025-12-02-13:14:26.596 0.0
2025-12-02-13:14:26.759 0.0
2025-12-02-11:20:31.608 0.0
2025-12-02-11:20:31.608 0.0
......@@ -2949,3 +2949,253 @@
2025-12-02-12:33:31.974 15.3
2025-12-02-12:33:32.178 15.6
2025-12-02-12:33:32.554 15.6
2025-12-02-13:13:29.373 0.0
2025-12-02-13:13:29.481 0.0
2025-12-02-13:13:29.785 0.0
2025-12-02-13:13:29.966 0.0
2025-12-02-13:13:30.129 0.0
2025-12-02-13:13:30.314 20.0
2025-12-02-13:13:30.533 20.0
2025-12-02-13:13:30.732 20.0
2025-12-02-13:13:30.935 20.0
2025-12-02-13:13:31.206 20.0
2025-12-02-13:13:31.387 20.0
2025-12-02-13:13:31.585 0.0
2025-12-02-13:13:31.808 0.0
2025-12-02-13:13:31.978 0.0
2025-12-02-13:13:32.165 0.0
2025-12-02-13:13:32.364 0.0
2025-12-02-13:13:32.578 20.0
2025-12-02-13:13:32.778 20.0
2025-12-02-13:13:32.992 20.0
2025-12-02-13:13:33.163 20.0
2025-12-02-13:13:33.378 20.0
2025-12-02-13:13:33.543 20.0
2025-12-02-13:13:33.766 0.0
2025-12-02-13:13:33.955 0.0
2025-12-02-13:13:34.177 20.0
2025-12-02-13:13:34.403 0.0
2025-12-02-13:13:34.586 0.0
2025-12-02-13:13:34.787 0.0
2025-12-02-13:13:34.993 0.0
2025-12-02-13:13:35.171 0.0
2025-12-02-13:13:35.405 0.0
2025-12-02-13:13:35.651 20.0
2025-12-02-13:13:35.853 20.0
2025-12-02-13:13:36.032 0.0
2025-12-02-13:13:36.206 0.0
2025-12-02-13:13:36.440 0.0
2025-12-02-13:13:36.619 0.0
2025-12-02-13:13:36.798 20.0
2025-12-02-13:13:37.030 0.0
2025-12-02-13:13:37.244 20.0
2025-12-02-13:13:37.416 20.0
2025-12-02-13:13:37.656 20.0
2025-12-02-13:13:37.853 20.0
2025-12-02-13:13:38.053 20.0
2025-12-02-13:13:38.230 0.0
2025-12-02-13:13:38.444 0.0
2025-12-02-13:13:38.678 0.0
2025-12-02-13:13:38.873 0.0
2025-12-02-13:13:39.091 0.0
2025-12-02-13:13:39.281 0.0
2025-12-02-13:13:39.480 0.0
2025-12-02-13:13:39.657 0.0
2025-12-02-13:13:39.903 20.0
2025-12-02-13:13:40.122 0.0
2025-12-02-13:13:40.266 0.0
2025-12-02-13:13:40.468 0.0
2025-12-02-13:13:40.665 0.0
2025-12-02-13:13:40.867 0.0
2025-12-02-13:13:41.110 0.0
2025-12-02-13:13:41.328 0.0
2025-12-02-13:13:41.512 0.0
2025-12-02-13:13:41.717 0.0
2025-12-02-13:13:41.880 0.0
2025-12-02-13:13:42.098 20.0
2025-12-02-13:13:42.299 0.0
2025-12-02-13:13:42.524 0.0
2025-12-02-13:13:42.707 0.0
2025-12-02-13:13:42.906 0.0
2025-12-02-13:13:43.113 0.0
2025-12-02-13:13:43.339 0.0
2025-12-02-13:13:43.543 0.0
2025-12-02-13:13:43.732 20.0
2025-12-02-13:13:43.951 20.0
2025-12-02-13:13:44.171 0.0
2025-12-02-13:13:44.366 0.0
2025-12-02-13:13:44.569 0.0
2025-12-02-13:13:44.730 0.0
2025-12-02-13:13:44.967 0.0
2025-12-02-13:13:45.163 0.0
2025-12-02-13:13:45.522 0.0
2025-12-02-13:13:45.772 0.0
2025-12-02-13:13:45.982 0.0
2025-12-02-13:13:46.217 0.0
2025-12-02-13:13:46.500 0.0
2025-12-02-13:13:46.769 0.0
2025-12-02-13:13:47.020 0.0
2025-12-02-13:13:47.290 0.0
2025-12-02-13:13:47.483 0.0
2025-12-02-13:13:47.716 0.0
2025-12-02-13:13:47.950 0.0
2025-12-02-13:13:48.176 0.0
2025-12-02-13:13:48.409 0.0
2025-12-02-13:13:48.738 20.0
2025-12-02-13:13:48.977 0.0
2025-12-02-13:13:49.194 0.0
2025-12-02-13:13:49.519 20.0
2025-12-02-13:13:49.720 20.0
2025-12-02-13:13:49.947 20.0
2025-12-02-13:13:50.115 20.0
2025-12-02-13:13:50.256 0.0
2025-12-02-13:13:50.482 0.0
2025-12-02-13:13:50.706 0.0
2025-12-02-13:13:50.916 0.0
2025-12-02-13:13:51.181 0.0
2025-12-02-13:13:51.478 0.0
2025-12-02-13:13:51.680 0.0
2025-12-02-13:13:51.823 20.0
2025-12-02-13:13:52.067 20.0
2025-12-02-13:13:52.318 0.0
2025-12-02-13:13:53.091 20.0
2025-12-02-13:13:53.482 20.0
2025-12-02-13:13:53.750 20.0
2025-12-02-13:13:54.020 20.0
2025-12-02-13:13:54.259 0.0
2025-12-02-13:13:54.499 0.0
2025-12-02-13:13:54.709 20.0
2025-12-02-13:13:54.932 20.0
2025-12-02-13:13:55.232 20.0
2025-12-02-13:13:55.461 20.0
2025-12-02-13:13:55.721 0.0
2025-12-02-13:13:56.105 20.0
2025-12-02-13:13:56.417 0.0
2025-12-02-13:13:56.930 0.0
2025-12-02-13:13:57.269 0.0
2025-12-02-13:13:57.622 20.0
2025-12-02-13:13:57.861 20.0
2025-12-02-13:13:58.123 0.0
2025-12-02-13:13:58.408 0.0
2025-12-02-13:13:58.756 0.0
2025-12-02-13:13:59.001 0.0
2025-12-02-13:13:59.213 0.0
2025-12-02-13:13:59.409 0.0
2025-12-02-13:13:59.636 0.0
2025-12-02-13:13:59.821 0.0
2025-12-02-13:14:00.055 0.0
2025-12-02-13:14:00.225 20.0
2025-12-02-13:14:00.479 20.0
2025-12-02-13:14:00.679 20.0
2025-12-02-13:14:00.878 0.0
2025-12-02-13:14:01.054 0.0
2025-12-02-13:14:01.274 0.0
2025-12-02-13:14:01.492 0.0
2025-12-02-13:14:01.735 20.0
2025-12-02-13:14:02.003 20.0
2025-12-02-13:14:02.206 20.0
2025-12-02-13:14:02.470 20.0
2025-12-02-13:14:02.732 20.0
2025-12-02-13:14:02.953 0.0
2025-12-02-13:14:03.135 0.0
2025-12-02-13:14:03.379 0.0
2025-12-02-13:14:03.596 0.0
2025-12-02-13:14:03.804 20.0
2025-12-02-13:14:04.029 20.0
2025-12-02-13:14:04.250 20.0
2025-12-02-13:14:04.516 20.0
2025-12-02-13:14:04.759 20.0
2025-12-02-13:14:05.008 20.0
2025-12-02-13:14:05.248 20.0
2025-12-02-13:14:05.496 20.0
2025-12-02-13:14:05.713 20.0
2025-12-02-13:14:05.918 20.0
2025-12-02-13:14:06.157 0.0
2025-12-02-13:14:06.422 0.0
2025-12-02-13:14:06.699 0.0
2025-12-02-13:14:07.009 20.0
2025-12-02-13:14:07.322 0.0
2025-12-02-13:14:07.666 20.0
2025-12-02-13:14:07.923 0.0
2025-12-02-13:14:08.182 0.0
2025-12-02-13:14:08.383 0.0
2025-12-02-13:14:08.629 0.0
2025-12-02-13:14:08.862 0.0
2025-12-02-13:14:09.089 20.0
2025-12-02-13:14:09.331 0.0
2025-12-02-13:14:09.587 0.0
2025-12-02-13:14:09.807 0.0
2025-12-02-13:14:10.043 20.0
2025-12-02-13:14:10.267 0.0
2025-12-02-13:14:10.561 20.0
2025-12-02-13:14:10.790 0.0
2025-12-02-13:14:11.020 0.0
2025-12-02-13:14:11.248 0.0
2025-12-02-13:14:11.456 0.0
2025-12-02-13:14:11.698 0.0
2025-12-02-13:14:11.903 0.0
2025-12-02-13:14:12.113 0.0
2025-12-02-13:14:12.291 0.0
2025-12-02-13:14:12.625 0.0
2025-12-02-13:14:12.843 0.0
2025-12-02-13:14:13.053 0.0
2025-12-02-13:14:13.273 0.0
2025-12-02-13:14:13.456 0.0
2025-12-02-13:14:13.677 0.0
2025-12-02-13:14:13.884 0.0
2025-12-02-13:14:14.096 0.0
2025-12-02-13:14:14.258 0.0
2025-12-02-13:14:14.518 0.0
2025-12-02-13:14:14.699 0.0
2025-12-02-13:14:14.997 0.0
2025-12-02-13:14:15.257 0.0
2025-12-02-13:14:15.485 0.0
2025-12-02-13:14:15.740 0.0
2025-12-02-13:14:16.007 20.0
2025-12-02-13:14:16.182 0.0
2025-12-02-13:14:16.479 20.0
2025-12-02-13:14:16.710 20.0
2025-12-02-13:14:16.948 20.0
2025-12-02-13:14:17.203 20.0
2025-12-02-13:14:17.582 0.0
2025-12-02-13:14:17.824 0.0
2025-12-02-13:14:18.056 0.0
2025-12-02-13:14:18.275 20.0
2025-12-02-13:14:18.513 20.0
2025-12-02-13:14:18.771 20.0
2025-12-02-13:14:19.026 20.0
2025-12-02-13:14:19.282 0.0
2025-12-02-13:14:19.548 0.0
2025-12-02-13:14:19.763 20.0
2025-12-02-13:14:20.006 0.0
2025-12-02-13:14:20.227 0.0
2025-12-02-13:14:20.474 20.0
2025-12-02-13:14:20.717 0.0
2025-12-02-13:14:20.989 20.0
2025-12-02-13:14:21.211 20.0
2025-12-02-13:14:21.444 20.0
2025-12-02-13:14:21.642 20.0
2025-12-02-13:14:21.860 20.0
2025-12-02-13:14:22.074 0.0
2025-12-02-13:14:22.280 0.0
2025-12-02-13:14:22.503 0.0
2025-12-02-13:14:22.710 0.0
2025-12-02-13:14:22.942 0.0
2025-12-02-13:14:23.162 0.0
2025-12-02-13:14:23.356 20.0
2025-12-02-13:14:23.603 20.0
2025-12-02-13:14:23.825 0.0
2025-12-02-13:14:24.042 0.0
2025-12-02-13:14:24.242 0.0
2025-12-02-13:14:24.506 0.0
2025-12-02-13:14:24.725 0.0
2025-12-02-13:14:24.934 0.0
2025-12-02-13:14:25.135 0.0
2025-12-02-13:14:25.347 0.0
2025-12-02-13:14:25.522 20.0
2025-12-02-13:14:25.768 20.0
2025-12-02-13:14:25.973 20.0
2025-12-02-13:14:26.151 0.0
2025-12-02-13:14:26.371 0.0
2025-12-02-13:14:26.596 0.0
2025-12-02-13:14:26.759 0.0
# -*- coding: utf-8 -*-
"""
液位检测引擎测试脚本
功能:
- 读取本地视频文件
- 使用检测引擎进行液位检测
- 输出检测结果(CSV格式)
使用方法:
python test_detection_engine.py --video <视频路径> --model <模型路径> [--annotation <标注文件路径>] [--output <输出文件路径>]
示例:
python test_detection_engine.py --video test_video.mp4 --model database/model/detection_model/model.pt --annotation database/config/annotation_result.yaml --output results.csv
"""
import argparse
import cv2
import yaml
import csv
import json
import os
import sys
from pathlib import Path
from typing import Dict, List, Optional
from datetime import datetime
# 添加项目根目录到路径
sys.path.insert(0, str(Path(__file__).parent))
from handlers.videopage.detection import LiquidDetectionEngine
def load_annotation_from_yaml(yaml_path: str, channel_key: Optional[str] = None) -> Optional[Dict]:
"""
从YAML文件加载标注数据
Args:
yaml_path: YAML文件路径
channel_key: 通道键名(如 'channel1'),如果为None则使用第一个通道
Returns:
标注数据字典,包含 boxes, fixed_bottoms, fixed_tops, actual_heights
"""
try:
with open(yaml_path, 'r', encoding='utf-8') as f:
try:
annotation_data = yaml.safe_load(f)
except yaml.constructor.ConstructorError:
# 如果safe_load失败,使用unsafe_load
f.seek(0)
annotation_data = yaml.unsafe_load(f)
# 如果没有指定channel_key,使用第一个通道
if channel_key is None:
if isinstance(annotation_data, dict):
channel_key = list(annotation_data.keys())[0]
print(f"[标注加载] 未指定通道,使用第一个通道: {channel_key}")
if channel_key not in annotation_data:
print(f"❌ [标注加载] 通道 '{channel_key}' 不存在于标注文件中")
return None
channel_data = annotation_data[channel_key]
# 提取标注数据
boxes = channel_data.get('boxes', [])
fixed_bottoms = channel_data.get('fixed_bottoms', [])
fixed_tops = channel_data.get('fixed_tops', [])
# 提取实际高度(从areas中提取或使用默认值)
actual_heights = []
areas = channel_data.get('areas', {})
if areas:
for area_key in sorted(areas.keys()):
area_data = areas[area_key]
height_str = area_data.get('height', '20mm')
# 解析高度字符串,如 "20mm" -> 20.0
try:
height_value = float(height_str.replace('mm', '').strip())
actual_heights.append(height_value)
except:
actual_heights.append(20.0)
# 如果从areas中没有提取到高度,使用默认值
if not actual_heights:
actual_heights = [20.0] * len(boxes)
print(f"[标注加载] 成功加载通道 '{channel_key}' 的标注数据:")
print(f" - 检测区域数量: {len(boxes)}")
print(f" - 容器底部坐标: {fixed_bottoms}")
print(f" - 容器顶部坐标: {fixed_tops}")
print(f" - 容器实际高度: {actual_heights}mm")
return {
'boxes': boxes,
'fixed_bottoms': fixed_bottoms,
'fixed_tops': fixed_tops,
'actual_heights': actual_heights
}
except Exception as e:
print(f"❌ [标注加载] 加载标注文件失败: {e}")
import traceback
traceback.print_exc()
return None
def save_results_to_csv(results: List[Dict], output_path: str):
"""
将检测结果保存为CSV文件
Args:
results: 检测结果列表,每个元素包含 frame_idx, timestamp, liquid_line_positions
output_path: 输出文件路径
"""
if not results:
print("⚠️ [结果保存] 没有检测结果可保存")
return
# 获取所有目标索引
all_target_indices = set()
for result in results:
if 'liquid_line_positions' in result:
all_target_indices.update(result['liquid_line_positions'].keys())
all_target_indices = sorted(all_target_indices)
# 写入CSV文件
with open(output_path, 'w', newline='', encoding='utf-8-sig') as f:
# 创建表头
headers = ['frame_idx', 'timestamp_ms']
for idx in all_target_indices:
headers.extend([
f'target_{idx}_y',
f'target_{idx}_height_mm',
f'target_{idx}_height_px',
f'target_{idx}_left',
f'target_{idx}_right'
])
headers.append('success')
writer = csv.DictWriter(f, fieldnames=headers)
writer.writeheader()
# 写入数据
for result in results:
row = {
'frame_idx': result.get('frame_idx', 0),
'timestamp_ms': result.get('timestamp_ms', 0),
'success': result.get('success', False)
}
liquid_positions = result.get('liquid_line_positions', {})
for idx in all_target_indices:
if idx in liquid_positions:
pos = liquid_positions[idx]
row[f'target_{idx}_y'] = pos.get('y', '')
row[f'target_{idx}_height_mm'] = pos.get('height_mm', '')
row[f'target_{idx}_height_px'] = pos.get('height_px', '')
row[f'target_{idx}_left'] = pos.get('left', '')
row[f'target_{idx}_right'] = pos.get('right', '')
else:
row[f'target_{idx}_y'] = ''
row[f'target_{idx}_height_mm'] = ''
row[f'target_{idx}_height_px'] = ''
row[f'target_{idx}_left'] = ''
row[f'target_{idx}_right'] = ''
writer.writerow(row)
print(f"✅ [结果保存] 检测结果已保存到: {output_path}")
print(f" - 总帧数: {len(results)}")
print(f" - 目标数量: {len(all_target_indices)}")
def save_results_to_json(results: List[Dict], output_path: str):
"""
将检测结果保存为JSON文件
Args:
results: 检测结果列表
output_path: 输出文件路径
"""
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(results, f, indent=2, ensure_ascii=False)
print(f"✅ [结果保存] 检测结果已保存到: {output_path} (JSON格式)")
def process_video(
video_path: str,
model_path: str,
annotation_config: Optional[Dict] = None,
output_path: Optional[str] = None,
max_frames: Optional[int] = None,
frame_skip: int = 1
):
"""
处理视频文件,执行液位检测
Args:
video_path: 视频文件路径
model_path: 模型文件路径
annotation_config: 标注配置字典(可选)
output_path: 输出文件路径(可选,默认自动生成)
max_frames: 最大处理帧数(可选,用于测试)
frame_skip: 跳帧数(每N帧处理一次,默认1表示处理所有帧)
"""
print("=" * 60)
print("液位检测引擎测试脚本")
print("=" * 60)
# 检查视频文件
if not os.path.exists(video_path):
print(f"❌ [错误] 视频文件不存在: {video_path}")
return
# 检查模型文件
if not os.path.exists(model_path):
print(f"❌ [错误] 模型文件不存在: {model_path}")
return
# 打开视频文件
print(f"\n[视频加载] 正在打开视频文件: {video_path}")
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
print(f"❌ [错误] 无法打开视频文件: {video_path}")
return
# 获取视频信息
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
print(f"[视频信息]")
print(f" - 总帧数: {total_frames}")
print(f" - 帧率: {fps:.2f} fps")
print(f" - 分辨率: {width}x{height}")
if max_frames:
total_frames = min(total_frames, max_frames)
print(f" - 限制处理帧数: {max_frames}")
if frame_skip > 1:
print(f" - 跳帧设置: 每 {frame_skip} 帧处理一次")
# 初始化检测引擎
print(f"\n[检测引擎] 正在初始化检测引擎...")
print(f" - 模型路径: {model_path}")
engine = LiquidDetectionEngine(
model_path=None, # 延迟加载
device='cuda', # 使用GPU
batch_size=4
)
if not engine.load_model(model_path):
print(f"❌ [错误] 模型加载失败")
cap.release()
return
# 配置标注数据
if annotation_config:
print(f"\n[标注配置] 正在配置标注数据...")
boxes = annotation_config.get('boxes', [])
fixed_bottoms = annotation_config.get('fixed_bottoms', [])
fixed_tops = annotation_config.get('fixed_tops', [])
actual_heights = annotation_config.get('actual_heights', [])
engine.configure(boxes, fixed_bottoms, fixed_tops, actual_heights)
print(f"✅ [标注配置] 标注数据配置完成")
else:
print(f"⚠️ [标注配置] 未提供标注数据,将使用默认配置")
# 如果没有标注数据,使用默认配置(需要用户手动设置)
print(f"⚠️ [标注配置] 请确保在代码中手动配置标注数据")
# 处理视频帧
print(f"\n[开始检测] 正在处理视频帧...")
results = []
frame_idx = 0
processed_count = 0
import time
start_time = time.time()
try:
while True:
ret, frame = cap.read()
if not ret:
break
# 跳帧处理
if frame_idx % frame_skip != 0:
frame_idx += 1
continue
# 限制最大帧数
if max_frames and processed_count >= max_frames:
break
# 计算时间戳(毫秒)
timestamp_ms = int((frame_idx / fps) * 1000) if fps > 0 else frame_idx * 33
# 执行检测
detection_result = engine.detect(frame)
# 保存结果
result_entry = {
'frame_idx': frame_idx,
'timestamp_ms': timestamp_ms,
'liquid_line_positions': detection_result.get('liquid_line_positions', {}),
'success': detection_result.get('success', False)
}
results.append(result_entry)
processed_count += 1
# 进度显示
if processed_count % 10 == 0 or processed_count == 1:
progress = (processed_count / total_frames) * 100 if total_frames > 0 else 0
elapsed = time.time() - start_time
fps_actual = processed_count / elapsed if elapsed > 0 else 0
print(f" [进度] {processed_count}/{total_frames} 帧 ({progress:.1f}%) | "
f"处理速度: {fps_actual:.2f} fps | "
f"已用时: {elapsed:.1f}s")
frame_idx += 1
except KeyboardInterrupt:
print(f"\n⚠️ [中断] 用户中断处理")
except Exception as e:
print(f"\n❌ [错误] 处理过程中出现异常: {e}")
import traceback
traceback.print_exc()
finally:
cap.release()
engine.cleanup()
# 计算统计信息
elapsed_time = time.time() - start_time
avg_fps = processed_count / elapsed_time if elapsed_time > 0 else 0
print(f"\n[检测完成]")
print(f" - 处理帧数: {processed_count}")
print(f" - 总用时: {elapsed_time:.2f}s")
print(f" - 平均速度: {avg_fps:.2f} fps")
# 保存结果
if results:
if output_path is None:
# 自动生成输出文件名
video_name = Path(video_path).stem
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_path = f"detection_results_{video_name}_{timestamp}.csv"
# 根据扩展名选择保存格式
if output_path.endswith('.json'):
save_results_to_json(results, output_path)
else:
save_results_to_csv(results, output_path)
# 打印结果摘要
print(f"\n[结果摘要]")
success_count = sum(1 for r in results if r.get('success', False))
print(f" - 成功检测帧数: {success_count}/{processed_count}")
# 打印每个目标的统计信息
if results and 'liquid_line_positions' in results[0]:
all_target_indices = sorted(results[0]['liquid_line_positions'].keys())
for idx in all_target_indices:
heights = [r['liquid_line_positions'][idx].get('height_mm', 0)
for r in results if idx in r.get('liquid_line_positions', {})]
if heights:
print(f" - 目标{idx}: 平均高度 {sum(heights)/len(heights):.2f}mm, "
f"最小 {min(heights):.2f}mm, 最大 {max(heights):.2f}mm")
else:
print(f"⚠️ [结果] 没有检测结果可保存")
def main():
"""主函数"""
parser = argparse.ArgumentParser(
description='液位检测引擎测试脚本',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例:
# 基本使用(需要手动配置标注数据)
python test_detection_engine.py --video test.mp4 --model model.pt
# 使用标注文件
python test_detection_engine.py --video test.mp4 --model model.pt --annotation annotation_result.yaml
# 指定通道和输出文件
python test_detection_engine.py --video test.mp4 --model model.pt --annotation annotation_result.yaml --channel channel1 --output results.csv
# 限制处理帧数(用于快速测试)
python test_detection_engine.py --video test.mp4 --model model.pt --annotation annotation_result.yaml --max-frames 100
"""
)
parser.add_argument('--video', '-v', required=True, help='视频文件路径')
parser.add_argument('--model', '-m', required=True, help='模型文件路径(.pt 或 .dat)')
parser.add_argument('--annotation', '-a', help='标注文件路径(YAML格式)')
parser.add_argument('--channel', '-c', help='通道键名(如 channel1),如果不指定则使用第一个通道')
parser.add_argument('--output', '-o', help='输出文件路径(CSV或JSON格式),如果不指定则自动生成')
parser.add_argument('--max-frames', type=int, help='最大处理帧数(用于测试)')
parser.add_argument('--frame-skip', type=int, default=1, help='跳帧数(每N帧处理一次,默认1)')
args = parser.parse_args()
# 加载标注数据
annotation_config = None
if args.annotation:
annotation_config = load_annotation_from_yaml(args.annotation, args.channel)
if annotation_config is None:
print("⚠️ [警告] 标注数据加载失败,将使用默认配置")
# 处理视频
process_video(
video_path=args.video,
model_path=args.model,
annotation_config=annotation_config,
output_path=args.output,
max_frames=args.max_frames,
frame_skip=args.frame_skip
)
if __name__ == '__main__':
main()
......@@ -745,39 +745,54 @@ class ChannelPanelHandler:
def _connectChannelThread(self, channel_id, channel_config):
"""在后台线程中打开通道"""
try:
# 解析RTSP地址(从address字段获取)
rtsp_url = channel_config.get('address', channel_config.get('rtsp', ''))
if not rtsp_url:
self._showConnectionError(channel_id, "通道地址为空")
return
# 解析RTSP URL获取连接信息
username, password, ip = self._parseRTSP(rtsp_url)
# 导入HKcapture
from handlers.videopage.HK_SDK.HKcapture import HKcapture
# 从配置读取帧率(确保所有帧率设置来自外部配置)
fps = self._capture_fps # 使用配置的捕获帧率
# 创建捕获对象
if username and password and ip:
# 海康威视摄像头(使用SDK)
cap = HKcapture(
source=ip,
username=username,
password=password,
port=8000,
channel=1,
fps=fps # 传入配置的帧率
)
# 🔥 优先检查文件路径(本地视频文件)
file_path = channel_config.get('file_path', '').strip()
if file_path:
# 检查文件是否存在
import os
if os.path.exists(file_path):
# 使用本地视频文件
cap = HKcapture(
source=file_path,
fps=fps
)
else:
self._showConnectionError(channel_id, f"视频文件不存在: {file_path}")
return
else:
# 其他RTSP摄像头(使用OpenCV)
cap = HKcapture(
source=rtsp_url,
fps=fps # 传入配置的帧率
)
# 使用RTSP地址
rtsp_url = channel_config.get('address', channel_config.get('rtsp', ''))
if not rtsp_url:
self._showConnectionError(channel_id, "通道地址和文件路径均为空")
return
# 解析RTSP URL获取连接信息
username, password, ip = self._parseRTSP(rtsp_url)
# 创建捕获对象
if username and password and ip:
# 海康威视摄像头(使用SDK)
cap = HKcapture(
source=ip,
username=username,
password=password,
port=8000,
channel=1,
fps=fps # 传入配置的帧率
)
else:
# 其他RTSP摄像头(使用OpenCV)
cap = HKcapture(
source=rtsp_url,
fps=fps # 传入配置的帧率
)
# 打开连接
if not cap.open():
......
......@@ -991,13 +991,39 @@ class GeneralSetPanelHandler:
# 绘制矩形框(黄色)
cv2.rectangle(annotated_frame, (left, top), (right, bottom), (0, 255, 255), 3)
# 绘制底部点的圆点(绿色)
# 绘制底部点的水平线条(绿色,1px宽,长度与检测框宽度一致)
print(f"[DEBUG _createAnnotationmission_resultPixmap] 底部点数量: {len(bottoms)}")
for i, pt in enumerate(bottoms):
cv2.circle(annotated_frame, pt, 8, (0, 255, 0), -1)
# 绘制顶部点的圆点(红色)
print(f"[DEBUG _createAnnotationmission_resultPixmap] 绘制底部点 {i}: {pt}")
# 获取对应框的宽度作为线条长度
if i < len(boxes):
_, _, size = boxes[i]
line_length = size # 线条长度等于框的宽度
else:
line_length = 30 # 默认长度(不应该发生)
half_length = line_length // 2
x, y = pt
start_point = (x - half_length, y)
end_point = (x + half_length, y)
print(f"[DEBUG _createAnnotationmission_resultPixmap] 底部线条: start={start_point}, end={end_point}, color=(0,255,0), thickness=1, length={line_length}")
cv2.line(annotated_frame, start_point, end_point, (0, 255, 0), 1)
# 绘制顶部点的水平线条(红色,1px宽,长度与检测框宽度一致)
print(f"[DEBUG _createAnnotationmission_resultPixmap] 顶部点数量: {len(tops)}")
for i, pt in enumerate(tops):
cv2.circle(annotated_frame, pt, 8, (0, 0, 255), -1)
print(f"[DEBUG _createAnnotationmission_resultPixmap] 绘制顶部点 {i}: {pt}")
# 获取对应框的宽度作为线条长度
if i < len(boxes):
_, _, size = boxes[i]
line_length = size # 线条长度等于框的宽度
else:
line_length = 30 # 默认长度(不应该发生)
half_length = line_length // 2
x, y = pt
start_point = (x - half_length, y)
end_point = (x + half_length, y)
print(f"[DEBUG _createAnnotationmission_resultPixmap] 顶部线条: start={start_point}, end={end_point}, color=(0,0,255), thickness=1, length={line_length}")
cv2.line(annotated_frame, start_point, end_point, (0, 0, 255), 1)
# 第二步:使用PIL绘制中文文本(包括底部/顶部标签、区域名称和高度)
try:
......
......@@ -1120,7 +1120,8 @@ class MissionPanelHandler:
channels[i] = {
'channel_id': i,
'name': channel_info.get('name', f'通道{i}'),
'address': channel_info.get('address', '')
'address': channel_info.get('address', ''),
'file_path': channel_info.get('file_path', '')
}
return {'channels': channels}
......@@ -1158,7 +1159,8 @@ class MissionPanelHandler:
config[channel_key] = {
'name': channel_info.get('name', f'通道{channel_id}'),
'address': address
'address': address,
'file_path': channel_info.get('file_path', '')
}
# 保存配置
......
......@@ -80,18 +80,41 @@ class VideoRecorder:
self.file_start_time = datetime.now()
self._create_new_writer(fourcc, fps, width, height)
# 用于计算实际帧率
frame_count = 0
start_time = time.time()
actual_fps = fps # 初始使用配置的fps
while self.is_recording:
ret, frame = self.cap.read()
if ret and frame is not None:
self.writer.write(frame)
frame_count += 1
# 每30帧重新计算一次实际帧率
if frame_count % 30 == 0:
elapsed_time = time.time() - start_time
if elapsed_time > 0:
calculated_fps = frame_count / elapsed_time
# 使用移动平均来平滑帧率变化
actual_fps = (actual_fps * 0.8 + calculated_fps * 0.2)
# 如果实际帧率与写入帧率差异较大,重新创建writer
if abs(actual_fps - fps) > 2: # 差异超过2fps
logging.info(f"相机{self.camera_id} 检测到帧率变化: {fps:.1f} -> {actual_fps:.1f}")
self.writer.release()
fps = max(1, int(actual_fps)) # 确保fps至少为1
self._create_new_writer(fourcc, fps, width, height)
else:
time.sleep(0.1) # 等待新帧
time.sleep(0.01) # 短暂等待,减少CPU占用
# 检查是否需要切换新文件(5分钟)
if datetime.now() - self.file_start_time >= timedelta(minutes=5):
self.writer.release()
self.file_start_time = datetime.now()
self._create_new_writer(fourcc, fps, width, height)
frame_count = 0 # 重置帧计数
start_time = time.time()
if self.writer:
self.writer.release()
......
......@@ -1188,9 +1188,15 @@ class AnnotationWidget(QtWidgets.QWidget):
def _drawAnnotations(self, img):
"""绘制标注内容"""
print(f"[DEBUG _drawAnnotations] 方法被调用,annotation_engine={self.annotation_engine}")
if self.annotation_engine is None:
print(f"[DEBUG _drawAnnotations] annotation_engine为None,返回")
return
print(f"[DEBUG _drawAnnotations] boxes数量: {len(self.annotation_engine.boxes) if hasattr(self.annotation_engine, 'boxes') else 0}")
print(f"[DEBUG _drawAnnotations] bottom_points数量: {len(self.annotation_engine.bottom_points) if hasattr(self.annotation_engine, 'bottom_points') else 0}")
print(f"[DEBUG _drawAnnotations] top_points数量: {len(self.annotation_engine.top_points) if hasattr(self.annotation_engine, 'top_points') else 0}")
# 第一步:使用OpenCV绘制所有的框和点
# 绘制已完成的框
for i, (cx, cy, size) in enumerate(self.annotation_engine.boxes):
......@@ -1205,13 +1211,39 @@ class AnnotationWidget(QtWidgets.QWidget):
# 绘制检测框(黄色)
cv2.rectangle(img, (left, top), (right, bottom), (0, 255, 255), 3)
# 绘制底部点(绿色)- 只绘制圆点,文字用PIL绘制
# 绘制底部点(绿色)- 绘制1px水平线条,长度与检测框宽度一致
print(f"[DEBUG _drawAnnotations] 底部点数量: {len(self.annotation_engine.bottom_points)}")
for i, pt in enumerate(self.annotation_engine.bottom_points):
cv2.circle(img, pt, 8, (0, 255, 0), -1)
# 绘制顶部点(红色)- 只绘制圆点,文字用PIL绘制
print(f"[DEBUG _drawAnnotations] 绘制底部点 {i}: {pt}")
# 获取对应框的宽度作为线条长度
if i < len(self.annotation_engine.boxes):
_, _, size = self.annotation_engine.boxes[i]
line_length = size # 线条长度等于框的宽度
else:
line_length = 30 # 默认长度(不应该发生)
half_length = line_length // 2
x, y = pt
start_point = (x - half_length, y)
end_point = (x + half_length, y)
print(f"[DEBUG _drawAnnotations] 底部线条: start={start_point}, end={end_point}, color=(0,255,0), thickness=1, length={line_length}")
cv2.line(img, start_point, end_point, (0, 255, 0), 1)
# 绘制顶部点(红色)- 绘制1px水平线条,长度与检测框宽度一致
print(f"[DEBUG _drawAnnotations] 顶部点数量: {len(self.annotation_engine.top_points)}")
for i, pt in enumerate(self.annotation_engine.top_points):
cv2.circle(img, pt, 8, (0, 0, 255), -1)
print(f"[DEBUG _drawAnnotations] 绘制顶部点 {i}: {pt}")
# 获取对应框的宽度作为线条长度
if i < len(self.annotation_engine.boxes):
_, _, size = self.annotation_engine.boxes[i]
line_length = size # 线条长度等于框的宽度
else:
line_length = 30 # 默认长度(不应该发生)
half_length = line_length // 2
x, y = pt
start_point = (x - half_length, y)
end_point = (x + half_length, y)
print(f"[DEBUG _drawAnnotations] 顶部线条: start={start_point}, end={end_point}, color=(0,0,255), thickness=1, length={line_length}")
cv2.line(img, start_point, end_point, (0, 0, 255), 1)
# 如果正在画框,显示临时框
if self.drawing_box:
......
......@@ -357,7 +357,7 @@ class MissionPanel(QtWidgets.QWidget):
channels_grid = QtWidgets.QGridLayout()
channels_grid.setContentsMargins(0, 0, 0, 0)
channels_grid.setHorizontalSpacing(0) # 水平间距设为0
channels_grid.setVerticalSpacing(2)
channels_grid.setVerticalSpacing(5)
# 设置地址标签列和地址输入框列之间的间距为0
channels_grid.setColumnMinimumWidth(2, 0) # 地址标签列最小宽度
......@@ -365,6 +365,7 @@ class MissionPanel(QtWidgets.QWidget):
# 创建4个通道的输入框
self.channel_name_edits = {} # 通道名称输入框
self.channel_addr_edits = {} # 地址输入框
self.channel_file_path_edits = {} # 文件路径输入框
for i in range(1, 5):
# 通道标签
......@@ -443,16 +444,53 @@ class MissionPanel(QtWidgets.QWidget):
self.channel_debug_btns = {}
self.channel_debug_btns[i] = debug_btn
# === 添加文件路径输入行 ===
# 文件路径标签
file_path_label = QtWidgets.QLabel("文件:")
FontManager.applyToWidget(file_path_label)
file_path_label.setContentsMargins(0, 0, 0, 0)
file_path_label.setStyleSheet("margin-right: 0px; padding-right: 0px;")
# 文件路径输入框
file_path_edit = QtWidgets.QLineEdit()
file_path_edit.setPlaceholderText("选择本地视频文件路径")
file_path_edit.setMinimumWidth(200)
file_path_edit.setFixedHeight(30)
FontManager.applyToWidget(file_path_edit)
file_path_edit.setContentsMargins(0, 0, 0, 0)
file_path_edit.setStyleSheet("""
QLineEdit {
margin-left: 0px;
padding-left: 2px;
padding-right: 2px;
padding-top: 0px;
padding-bottom: 0px;
text-align: left;
border: 1px solid #CCCCCC;
}
""")
# 浏览按钮
browse_btn = createTextButton("浏览", parent=self, slot=lambda checked, ch=i: self._onBrowseVideoFile(ch))
# 添加到布局
row = i - 1
channels_grid.addWidget(label, row, 0)
channels_grid.addWidget(name_edit, row, 1)
channels_grid.addWidget(addr_label, row, 2)
channels_grid.addWidget(addr_edit, row, 3)
channels_grid.addWidget(debug_btn, row, 4)
# 第一行:通道标签、名称、地址标签、地址输入、调试按钮
row1 = (i - 1) * 2
channels_grid.addWidget(label, row1, 0)
channels_grid.addWidget(name_edit, row1, 1)
channels_grid.addWidget(addr_label, row1, 2)
channels_grid.addWidget(addr_edit, row1, 3)
channels_grid.addWidget(debug_btn, row1, 4)
# 第二行:空、空、文件标签、文件路径输入、浏览按钮
row2 = row1 + 1
channels_grid.addWidget(file_path_label, row2, 2)
channels_grid.addWidget(file_path_edit, row2, 3)
channels_grid.addWidget(browse_btn, row2, 4)
self.channel_name_edits[i] = name_edit
self.channel_addr_edits[i] = addr_edit
self.channel_file_path_edits[i] = file_path_edit
# 设置列拉伸因子:让地址输入框占据剩余空间
channels_grid.setColumnStretch(0, 0) # 通道标签列不拉伸
......@@ -1465,12 +1503,14 @@ class MissionPanel(QtWidgets.QWidget):
for i in range(1, 5):
name = self.channel_name_edits[i].text().strip()
addr = self.channel_addr_edits[i].text().strip()
if addr: # 只有当地址非空时才保存该通道
file_path = self.channel_file_path_edits[i].text().strip()
# 如果地址或文件路径非空,则保存该通道
if addr or file_path:
channels[i] = {
'channel_id': i,
'name': name or f'通道{i}',
'address': addr
'address': addr,
'file_path': file_path
}
# 发送通道确认信号
......@@ -1479,6 +1519,32 @@ class MissionPanel(QtWidgets.QWidget):
# 切换回列表界面
self.showTableView()
def _onBrowseVideoFile(self, channel_id):
"""浏览选择本地视频文件"""
try:
# 定义支持的视频文件格式
video_formats = "视频文件 (*.mp4 *.avi *.mov *.mkv *.flv *.wmv *.m4v *.mpg *.mpeg);;所有文件 (*.*)"
# 打开文件选择对话框
file_path, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
f"选择通道{channel_id}的视频文件",
"", # 默认目录为空,使用系统默认
video_formats
)
# 如果用户选择了文件,则设置到输入框
if file_path:
self.channel_file_path_edits[channel_id].setText(file_path)
except Exception as e:
import traceback
traceback.print_exc()
DialogManager.show_warning(
self,
"文件选择失败",
f"选择视频文件时发生错误:\n{str(e)}"
)
def _onChannelCancel(self):
"""通道管理取消按钮点击"""
# 发送通道取消信号
......@@ -1565,6 +1631,13 @@ class MissionPanel(QtWidgets.QWidget):
edit.home(False),
edit.update()
))
# 加载文件路径
file_path = channel.get('file_path', '')
if file_path:
self.channel_file_path_edits[i].setText(file_path)
else:
self.channel_file_path_edits[i].clear()
def _resetDebugButton(self, channel_id):
"""重置调试按钮状态"""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment