Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
O
Oil_Level_Recognition_System
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Oil_Level_Recognition_System
Commits
6c828f54
Commit
6c828f54
authored
Dec 02, 2025
by
yhb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Merge branch 'Wangbing1' of git.patzn.com:root/Oil_Level_Recognition_System into Wangbing1
parent
a965fd26
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
1145 additions
and
36 deletions
+1145
-36
channel_config.yaml
database/config/channel_config.yaml
+2
-2
default_config.yaml
database/config/default_config.yaml
+5
-1
通道1_区域1.csv
database/mission_result/1_历史回放功能展示/通道1_区域1.csv
+1
-0
通道1_区域2.csv
database/mission_result/1_历史回放功能展示/通道1_区域2.csv
+1
-0
通道1_区域1.csv
database/mission_result/1_曲线/通道1_区域1.csv
+251
-1
通道1_区域2.csv
database/mission_result/1_曲线/通道1_区域2.csv
+251
-1
test_detection_engine.py
debug/test_detection_engine.py
+432
-0
channelpanel_handler.py
handlers/videopage/channelpanel_handler.py
+23
-8
general_set_handler.py
handlers/videopage/general_set_handler.py
+31
-5
missionpanel_handler.py
handlers/videopage/missionpanel_handler.py
+4
-2
record.py
utils/record.py
+24
-1
general_set.py
widgets/videopage/general_set.py
+37
-5
missionpanel.py
widgets/videopage/missionpanel.py
+83
-10
No files found.
database/config/channel_config.yaml
View file @
6c828f54
...
...
@@ -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
:
...
...
database/config/default_config.yaml
View file @
6c828f54
...
...
@@ -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'
...
...
database/mission_result/1_历史回放功能展示/通道1_区域1.csv
0 → 100644
View file @
6c828f54
++ "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"
database/mission_result/1_历史回放功能展示/通道1_区域2.csv
0 → 100644
View file @
6c828f54
++ "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"
database/mission_result/1_曲线/通道1_区域1.csv
View file @
6c828f54
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
database/mission_result/1_曲线/通道1_区域2.csv
View file @
6c828f54
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
debug/test_detection_engine.py
0 → 100644
View file @
6c828f54
# -*- 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
()
handlers/videopage/channelpanel_handler.py
View file @
6c828f54
...
...
@@ -745,22 +745,37 @@ class ChannelPanelHandler:
def
_connectChannelThread
(
self
,
channel_id
,
channel_config
):
"""在后台线程中打开通道"""
try
:
# 解析RTSP地址(从address字段获取)
# 导入HKcapture
from
handlers.videopage.HK_SDK.HKcapture
import
HKcapture
# 从配置读取帧率(确保所有帧率设置来自外部配置)
fps
=
self
.
_capture_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地址
rtsp_url
=
channel_config
.
get
(
'address'
,
channel_config
.
get
(
'rtsp'
,
''
))
if
not
rtsp_url
:
self
.
_showConnectionError
(
channel_id
,
"通道地址
为空"
)
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)
...
...
handlers/videopage/general_set_handler.py
View file @
6c828f54
...
...
@@ -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
:
...
...
handlers/videopage/missionpanel_handler.py
View file @
6c828f54
...
...
@@ -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'
,
''
)
}
# 保存配置
...
...
utils/record.py
View file @
6c828f54
...
...
@@ -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
()
...
...
widgets/videopage/general_set.py
View file @
6c828f54
...
...
@@ -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
:
...
...
widgets/videopage/missionpanel.py
View file @
6c828f54
...
...
@@ -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
):
"""通道管理取消按钮点击"""
# 发送通道取消信号
...
...
@@ -1566,6 +1632,13 @@ class MissionPanel(QtWidgets.QWidget):
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
):
"""重置调试按钮状态"""
if
channel_id
not
in
self
.
channel_debug_btns
:
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment