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
柳青君
Oil_Level_Recognition_System
Commits
e491a327
Commit
e491a327
authored
Nov 26, 2025
by
Yuhaibo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1
parent
872a1442
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
111 additions
and
344 deletions
+111
-344
CLEANUP_PROGRESS.md
handlers/CLEANUP_PROGRESS.md
+12
-7
__main__.py
handlers/__main__.py
+3
-43
app.py
handlers/app.py
+4
-21
annotation_handler.py
handlers/datasetpage/annotation_handler.py
+5
-21
datacollection_channel_handler.py
handlers/datasetpage/datacollection_channel_handler.py
+1
-16
datapreprocess_handler.py
handlers/datasetpage/datapreprocess_handler.py
+0
-0
cleanup_test_code.py
handlers/modelpage/cleanup_test_code.py
+0
-59
model_page_handler.py
handlers/modelpage/model_page_handler.py
+9
-37
model_set_handler.py
handlers/modelpage/model_set_handler.py
+0
-71
model_signal_handler.py
handlers/modelpage/model_signal_handler.py
+4
-10
model_test_handler.py
handlers/modelpage/model_test_handler.py
+3
-49
model_training_handler.py
handlers/modelpage/model_training_handler.py
+0
-0
display_thread.py
handlers/videopage/thread_manager/threads/display_thread.py
+10
-0
storage_thread.py
handlers/videopage/thread_manager/threads/storage_thread.py
+60
-10
No files found.
handlers/CLEANUP_PROGRESS.md
View file @
e491a327
...
...
@@ -116,10 +116,14 @@
### 部分清理
17.
🔄
**handlers/videopage/missionpanel_handler.py**
- 已清理前880行,删除约50处print语句(文件共2004行,需继续清理)
23.
🔄
**handlers/modelpage/model_test_handler.py**
- 已清理约20处print语句(文件共2090行,剩余约280处,需继续清理)
### 新增完成清理
18.
✅
**widgets/datasetpage/crop_preview_panel.py**
- 删除约47处print语句和2处DEBUG注释
19.
✅
**widgets/datasetpage/datacollection_panel.py**
- 删除约20处print语句和1处DEBUG注释
20.
✅
**handlers/modelpage/model_page_handler.py**
- 删除7处print语句和2处DEBUG注释
21.
✅
**handlers/modelpage/model_set_handler.py**
- 删除47处print语句和2处DEBUG注释
22.
✅
**handlers/modelpage/model_signal_handler.py**
- 删除6处print语句
## 清理进度说明
...
...
@@ -150,13 +154,13 @@
-
⏳ widgets/datasetpage/test_
*
.py
### 剩余工作量估算
-
已清理: 约
384处调试语句 (18个文件完全清理 + 1
个文件部分清理)
-
剩余: 约
3057处调试语句
-
预计需要: 继续手动清理约4
5
个文件
-
已清理: 约
464处调试语句 (21个文件完全清理 + 2
个文件部分清理)
-
剩余: 约
2672处调试语句
-
预计需要: 继续手动清理约4
1
个文件
### 本次清理总结 (2025-11-26 2
0:46
)
-
完成文件数:
18个完全清理 + 1
个部分清理
-
删除调试语句: 约
38
4处(包含print语句和DEBUG注释)
### 本次清理总结 (2025-11-26 2
1:02
)
-
完成文件数:
21个完全清理 + 2
个部分清理
-
删除调试语句: 约
46
4处(包含print语句和DEBUG注释)
-
主要清理内容:
-
核心应用入口和窗口管理 (app.py)
-
视图布局切换管理 (view_handler.py)
...
...
@@ -166,8 +170,9 @@
-
完整线程管理系统 (thread_manager.py, curve_thread.py, global_detection_thread.py, storage_thread.py, display_thread.py)
-
完整UI组件系统 (missionpanel.py, general_set.py, curvepanel.py, historyvideopanel.py)
-
数据集页面组件 (crop_preview_panel.py, datacollection_panel.py)
-
模型页面Handler系统 (model_page_handler.py, model_set_handler.py, model_signal_handler.py)
-
部分任务面板Handler (missionpanel_handler.py)
---
*最后更新: 2025-11-26 2
0:46
*
*最后更新: 2025-11-26 2
1:00
*
handlers/__main__.py
View file @
e491a327
...
...
@@ -77,30 +77,16 @@ def setup_runtime_directories():
if
not
os
.
path
.
exists
(
dir_path
):
try
:
os
.
makedirs
(
dir_path
,
exist_ok
=
True
)
print
(
f
"✓ 创建运行时目录: {dir_path}"
)
except
Exception
as
e
:
print
(
f
"⚠ 无法创建目录 {dir_path}: {e}"
)
# 打印配置文件读取位置说明
print
(
f
"
\n
📂 配置文件读取位置: {os.path.join(sys._MEIPASS, 'database', 'config')}"
)
print
(
f
"📂 运行时数据保存位置: {exe_dir}"
)
pass
def
main
():
"""主入口函数"""
try
:
# 在打包环境中
输出详细的启动信息
# 在打包环境中
创建运行时目录结构
if
getattr
(
sys
,
'frozen'
,
False
):
pass
print
(
f
"脚本目录: {current_dir}"
)
print
(
f
"Python 版本: {sys.version}"
)
print
(
"="
*
80
)
print
()
# 创建运行时目录结构
print
(
"正在初始化运行时环境..."
)
setup_runtime_directories
()
print
()
_main
()
except
Exception
as
e
:
...
...
@@ -129,8 +115,6 @@ sys.path:
{chr(10).join(f' - {p}' for p in sys.path)}
{'=' * 80}
"""
print
(
error_log
)
# 保存错误日志到文件
log_path
=
None
try
:
...
...
@@ -138,9 +122,8 @@ sys.path:
log_path
=
os
.
path
.
join
(
os
.
getcwd
(),
log_filename
)
with
open
(
log_path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
error_log
)
print
(
f
"
\n
错误日志已保存到: {log_path}"
)
except
Exception
as
log_err
:
p
rint
(
f
"
\n
警告: 无法保存日志文件 - {log_err}"
)
p
ass
# 在打包环境中使用更可靠的暂停方法
if
getattr
(
sys
,
'frozen'
,
False
):
...
...
@@ -175,9 +158,6 @@ sys.path:
def
_main
():
"""实际主入口函数"""
# 在打包环境中输出详细的初始化信息
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
"[1/6] 解析命令行参数..."
)
# 创建参数解析器
parser
=
argparse
.
ArgumentParser
(
...
...
@@ -224,31 +204,21 @@ def _main():
args
=
parser
.
parse_args
()
if
args
.
version
:
print
(
'帕特智能油液位检测 v1.0'
)
return
# 从args中提取配置
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
"[2/6] 提取配置参数..."
)
config_from_args
=
args
.
__dict__
filename
=
config_from_args
.
pop
(
'filename'
)
config_file_or_yaml
=
config_from_args
.
pop
(
'config'
)
version
=
config_from_args
.
pop
(
'version'
)
# 获取配置(三层级联)
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
f
"[3/6] 加载配置文件: {config_file_or_yaml}"
)
print
(
f
" 配置文件存在: {os.path.exists(config_file_or_yaml)}"
)
log_file_path
=
setup_logging
(
args
.
logger_level
)
logging
.
getLogger
(
__name__
)
.
debug
(
"Logger level set to
%
s"
,
args
.
logger_level
)
config
=
get_config
(
config_file_or_yaml
,
config_from_args
)
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
" 配置加载成功"
)
# 创建Qt应用
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
"[4/6] 创建 Qt 应用..."
)
app
=
QtWidgets
.
QApplication
(
sys
.
argv
)
app
.
setApplicationName
(
'Detection'
)
app
.
setOrganizationName
(
'Detection'
)
...
...
@@ -256,21 +226,11 @@ def _main():
# 应用全局字体配置
FontManager
.
applyToApplication
(
app
)
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
" Qt 应用创建成功"
)
# 创建主窗口
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
"[5/6] 创建主窗口..."
)
win
=
MainWindow
(
config
=
config
,
filename
=
filename
,
)
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
" 主窗口创建成功"
)
if
getattr
(
sys
,
'frozen'
,
False
):
print
(
"[6/6] 显示窗口并启动事件循环..."
)
win
.
show
()
# 启动事件循环
...
...
handlers/app.py
View file @
e491a327
...
...
@@ -190,7 +190,7 @@ except ImportError:
# ============================================================================
# 事件过滤器
:用于在debug模式下拦截交互
# 事件过滤器
# ============================================================================
class
MissionRequiredEventFilter
(
QObject
):
...
...
@@ -569,7 +569,6 @@ class MainWindow(
# 初始化数据采集通道资源
self
.
_initDataCollectionChannelResources
()
# 初始化测试调试资源(TestHandler)
if
hasattr
(
self
,
'_initTestResources'
):
self
.
_initTestResources
()
...
...
@@ -599,7 +598,6 @@ class MainWindow(
# 连接信号槽
self
.
_connectSignals
()
# 安装事件过滤器(debug模式下拦截交互)
self
.
_installEventFilters
()
# 恢复窗口状态
...
...
@@ -725,7 +723,6 @@ class MainWindow(
(
670
,
495
)
# 右下
]
# 检查是否为debug模式
from
database.config
import
is_debug_mode
is_debug
=
is_debug_mode
(
self
.
_config
)
...
...
@@ -733,7 +730,6 @@ class MainWindow(
channel_id
=
f
'channel{i+1}'
channel_name
=
self
.
getChannelDisplayName
(
channel_id
,
i
+
1
)
# 只有通道1在debug模式下显示debug文本
debug_mode
=
is_debug
and
(
i
==
0
)
channelPanel
=
ChannelPanel
(
channel_name
,
parent
=
self
.
default_channel_container
,
debug_mode
=
debug_mode
)
...
...
@@ -742,12 +738,7 @@ class MainWindow(
if
hasattr
(
channelPanel
,
'setChannelName'
):
channelPanel
.
setChannelName
(
channel_name
)
# 如果是通道1且为debug模式,设置current_mission显示(从内存变量读取)
if
debug_mode
and
hasattr
(
channelPanel
,
'setCurrentMission'
):
# 从内存变量读取current_mission(不依赖配置文件)
current_mission
=
self
.
current_mission
if
hasattr
(
self
,
'current_mission'
)
else
None
channelPanel
.
setCurrentMission
(
current_mission
)
# 🔥 为每个通道面板的任务标签设置变量名(channel1mission, channel2mission, channel3mission, channel4mission)
mission_var_name
=
f
'channel{i+1}mission'
setattr
(
self
,
mission_var_name
,
channelPanel
.
taskLabel
)
...
...
@@ -975,7 +966,6 @@ class MainWindow(
# 所有任务表格的信号连接都在 MissionPanelHandler.connectMissionPanel 中处理
self
.
connectMissionPanel
(
self
.
missionTable
)
# ========== 测试调试按钮信号(TestHandler)==========
self
.
_connectTestSignals
(
self
.
missionTable
)
# ========== 通道管理按钮信号 ==========
...
...
@@ -1115,7 +1105,6 @@ class MainWindow(
任务面板本身不受限制,始终可以交互。
"""
try
:
# 检查是否是debug模式
from
database.config
import
is_debug_mode
is_debug
=
is_debug_mode
(
self
.
_config
)
...
...
@@ -1213,18 +1202,12 @@ class MainWindow(
def
main
():
"""独立运行入口,用于UI预览和调试"""
import
sys
# 创建应用
app
=
QtWidgets
.
QApplication
(
sys
.
argv
)
app
.
setApplicationName
(
'Detection'
)
app
.
setOrganizationName
(
'Detection'
)
# 🔥 暂时禁用全局字体配置,测试是否解决重复显示问题
# FontManager.applyToApplication(app)
# 设置应用样式(可选)
# app.setStyle('Fusion')
# 创建主窗口
win
=
MainWindow
(
config
=
{})
win
.
show
()
...
...
handlers/datasetpage/annotation_handler.py
View file @
e491a327
...
...
@@ -83,7 +83,6 @@ class AnnotationHandler(QtCore.QObject):
bool: 是否成功
"""
if
not
dir_path
or
not
osp
.
exists
(
dir_path
):
print
(
f
"目录不存在: {dir_path}"
)
return
False
# 停止之前的监控
...
...
@@ -116,18 +115,15 @@ class AnnotationHandler(QtCore.QObject):
# 添加目录到监控列表
if
self
.
current_dir
not
in
self
.
file_watcher
.
directories
():
self
.
file_watcher
.
addPath
(
self
.
current_dir
)
print
(
f
"[AnnotationHandler] 开始监控目录: {self.current_dir}"
)
# 启动定时刷新
if
not
self
.
refresh_timer
.
isActive
():
self
.
refresh_timer
.
start
(
self
.
refresh_interval
)
print
(
f
"[AnnotationHandler] 启动定时刷新 (间隔: {self.refresh_interval}ms)"
)
self
.
monitoring_enabled
=
True
return
True
except
Exception
as
e
:
print
(
f
"[AnnotationHandler] 启动监控失败: {e}"
)
return
False
def
stopMonitoring
(
self
):
...
...
@@ -147,14 +143,12 @@ class AnnotationHandler(QtCore.QObject):
self
.
refresh_timer
.
stop
()
self
.
monitoring_enabled
=
False
print
(
f
"[AnnotationHandler] 停止监控"
)
except
Exception
as
e
:
p
rint
(
f
"[AnnotationHandler] 停止监控失败: {e}"
)
p
ass
def
_onDirectoryChanged
(
self
,
path
):
"""目录内容变化回调"""
print
(
f
"[AnnotationHandler] 检测到目录变化: {path}"
)
# 重新扫描文件
old_files
=
set
(
self
.
image_files
)
...
...
@@ -164,13 +158,11 @@ class AnnotationHandler(QtCore.QObject):
# 检测新增文件
added_files
=
new_files
-
old_files
for
file_path
in
added_files
:
print
(
f
"[AnnotationHandler] 新增文件: {osp.basename(file_path)}"
)
self
.
fileAdded
.
emit
(
file_path
)
# 检测删除文件
removed_files
=
old_files
-
new_files
for
file_path
in
removed_files
:
print
(
f
"[AnnotationHandler] 删除文件: {osp.basename(file_path)}"
)
if
file_path
in
self
.
file_info_dict
:
del
self
.
file_info_dict
[
file_path
]
self
.
fileRemoved
.
emit
(
file_path
)
...
...
@@ -183,7 +175,6 @@ class AnnotationHandler(QtCore.QObject):
def
_onFileChanged
(
self
,
path
):
"""文件变化回调"""
print
(
f
"[AnnotationHandler] 检测到文件变化: {osp.basename(path)}"
)
# 刷新该文件的信息
if
path
in
self
.
file_info_dict
:
...
...
@@ -212,7 +203,6 @@ class AnnotationHandler(QtCore.QObject):
if
json_exists_now
!=
json_existed_before
:
# JSON文件状态发生变化
print
(
f
"[AnnotationHandler] JSON状态变化: {osp.basename(image_path)} - {'新增' if json_exists_now else '删除'}"
)
self
.
refreshFileInfo
(
image_path
)
has_changes
=
True
elif
json_exists_now
:
...
...
@@ -222,7 +212,6 @@ class AnnotationHandler(QtCore.QObject):
# 重新获取JSON信息来检查
json_info
=
self
.
getJsonInfo
(
json_path
)
if
json_info
[
'shapes_count'
]
!=
old_info
[
'shapes_count'
]:
print
(
f
"[AnnotationHandler] JSON内容变化: {osp.basename(image_path)}"
)
self
.
refreshFileInfo
(
image_path
)
has_changes
=
True
except
Exception
as
e
:
...
...
@@ -235,7 +224,7 @@ class AnnotationHandler(QtCore.QObject):
self
.
fileListUpdated
.
emit
(
self
.
getAllFileInfoList
())
except
Exception
as
e
:
p
rint
(
f
"[AnnotationHandler] 定时刷新出错: {e}"
)
p
ass
def
setRefreshInterval
(
self
,
interval_ms
):
"""
...
...
@@ -249,7 +238,6 @@ class AnnotationHandler(QtCore.QObject):
if
self
.
refresh_timer
.
isActive
():
self
.
refresh_timer
.
stop
()
self
.
refresh_timer
.
start
(
self
.
refresh_interval
)
print
(
f
"[AnnotationHandler] 刷新间隔已更新: {interval_ms}ms"
)
def
scanImageFiles
(
self
):
"""
...
...
@@ -272,12 +260,10 @@ class AnnotationHandler(QtCore.QObject):
# 排序
self
.
image_files
.
sort
()
print
(
f
"扫描到 {len(self.image_files)} 个图片文件"
)
return
True
except
Exception
as
e
:
print
(
f
"扫描文件夹失败: {e}"
)
return
False
def
loadFileInfoList
(
self
):
...
...
@@ -332,7 +318,7 @@ class AnnotationHandler(QtCore.QObject):
else
:
info
[
'file_size_str'
]
=
f
"{file_size / (1024 * 1024):.1f} MB"
except
Exception
as
e
:
p
rint
(
f
"获取文件大小失败: {e}"
)
p
ass
# 获取分辨率
try
:
...
...
@@ -349,7 +335,7 @@ class AnnotationHandler(QtCore.QObject):
QtCore
.
Qt
.
SmoothTransformation
)
except
Exception
as
e
:
p
rint
(
f
"获取图片信息失败: {e}"
)
p
ass
# 如果有JSON文件,获取JSON信息
if
info
[
'has_json'
]:
...
...
@@ -390,7 +376,7 @@ class AnnotationHandler(QtCore.QObject):
info
[
'modified_time'
]
=
datetime
.
fromtimestamp
(
mtime
)
.
strftime
(
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
except
Exception
as
e
:
p
rint
(
f
"读取JSON文件失败: {e}"
)
p
ass
return
info
...
...
@@ -534,11 +520,9 @@ class AnnotationHandler(QtCore.QObject):
with
open
(
output_path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
json
.
dump
(
export_data
,
f
,
ensure_ascii
=
False
,
indent
=
2
)
print
(
f
"统计信息已导出到: {output_path}"
)
return
True
except
Exception
as
e
:
print
(
f
"导出统计信息失败: {e}"
)
return
False
...
...
handlers/datasetpage/datacollection_channel_handler.py
View file @
e491a327
...
...
@@ -175,7 +175,6 @@ class DataCollectionChannelHandler:
def
_connectDataCollectionChannelThread
(
self
,
channel_source
):
"""在后台线程中连接数据采集通道(使用与实时监测管理相同的方式)"""
try
:
print
(
f
"[DEBUG] 开始连接通道: {channel_source}"
)
success
=
False
error_detail
=
""
...
...
@@ -188,9 +187,7 @@ class DataCollectionChannelHandler:
error_detail
=
f
"无法连接到配置的通道 {channel_source}
\n
请检查:
\n
1. 相机是否已开机并连接到网络
\n
2. IP地址和端口是否正确"
else
:
# 如果没有配置,尝试直接连接USB通道
print
(
f
"[DEBUG] 尝试连接USB通道: {channel_source}"
)
success
=
self
.
_connectUSBChannel
(
channel_source
)
print
(
f
"[DEBUG] USB通道连接结果: {success}"
)
if
not
success
:
error_detail
=
f
"无法连接到USB通道 {channel_source}
\n
请检查:
\n
1. USB相机是否已连接
\n
2. 相机驱动是否已安装
\n
3. 相机是否被其他程序占用"
else
:
...
...
@@ -200,8 +197,6 @@ class DataCollectionChannelHandler:
error_detail
=
f
"无法连接到RTSP地址
\n
请检查:
\n
1. 网络连接是否正常
\n
2. RTSP地址格式是否正确
\n
3. 相机是否支持RTSP协议
\n\n
地址:{channel_source}"
if
not
success
:
print
(
f
"[DEBUG] 连接失败,显示错误对话框"
)
print
(
f
"[DEBUG] 错误详情: {error_detail}"
)
self
.
_showDataCollectionChannelError
(
"相机连接失败"
,
error_detail
if
error_detail
else
"无法打开通道设备,请检查通道是否连接正常或配置是否正确"
...
...
@@ -756,32 +751,22 @@ class DataCollectionChannelHandler:
def
_showDataCollectionChannelError
(
self
,
title
,
message
):
"""显示数据采集通道错误(线程安全)"""
print
(
f
"[DEBUG] _showDataCollectionChannelError 被调用"
)
print
(
f
"[DEBUG] 标题: {title}"
)
print
(
f
"[DEBUG] 消息: {message}"
)
# 使用信号发射错误信息(线程安全)
print
(
f
"[DEBUG] 准备发射错误信号"
)
self
.
_dc_error_signal
.
error
.
emit
(
title
,
message
)
print
(
f
"[DEBUG] 错误信号已发射"
)
def
_showDataCollectionChannelErrorUI
(
self
,
title
,
message
):
"""在主线程中显示数据采集通道错误"""
try
:
print
(
f
"[DEBUG] _showDataCollectionChannelErrorUI 被调用,准备显示对话框"
)
if
DialogManager
:
DialogManager
.
show_critical
(
self
,
title
,
message
)
else
:
QtWidgets
.
QMessageBox
.
critical
(
self
,
title
,
message
)
print
(
f
"[DEBUG] 错误对话框已显示"
)
if
hasattr
(
self
,
'statusBar'
):
self
.
statusBar
()
.
showMessage
(
f
"错误: {message}"
)
except
Exception
as
e
:
print
(
f
"[DEBUG] 显示错误对话框时发生异常: {e}"
)
import
traceback
traceback
.
print_exc
()
pass
def
getDataCollectionChannelStatus
(
self
):
"""
...
...
handlers/datasetpage/datapreprocess_handler.py
View file @
e491a327
This diff is collapsed.
Click to expand it.
handlers/modelpage/cleanup_test_code.py
View file @
e491a327
...
...
@@ -53,7 +53,6 @@ def backup_file(filepath):
timestamp
=
datetime
.
now
()
.
strftime
(
"
%
Y
%
m
%
d_
%
H
%
M
%
S"
)
backup_path
=
f
"{filepath}.backup_{timestamp}"
shutil
.
copy2
(
filepath
,
backup_path
)
print
(
f
"✅ 已备份原文件到: {backup_path}"
)
return
backup_path
def
find_method_range
(
lines
,
method_name
):
...
...
@@ -92,16 +91,12 @@ def find_method_range(lines, method_name):
def
cleanup_test_code
(
filepath
):
"""清理测试代码"""
print
(
"
\n
"
+
"="
*
60
)
print
(
"开始清理测试代码"
)
print
(
"="
*
60
)
# 读取文件
with
open
(
filepath
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
lines
=
f
.
readlines
()
original_line_count
=
len
(
lines
)
print
(
f
"
\n
原文件行数: {original_line_count}"
)
# 记录删除的方法
deleted_methods
=
[]
...
...
@@ -113,9 +108,6 @@ def cleanup_test_code(filepath):
if
result
:
start
,
end
=
result
method_lines
=
end
-
start
print
(
f
"
\n
找到方法: {method_name}"
)
print
(
f
" 位置: 第 {start + 1} 行到第 {end} 行"
)
print
(
f
" 行数: {method_lines} 行"
)
# 删除方法
del
lines
[
start
:
end
]
...
...
@@ -126,9 +118,6 @@ def cleanup_test_code(filepath):
'lines'
:
method_lines
})
deleted_lines
+=
method_lines
print
(
f
" ✅ 已删除"
)
else
:
print
(
f
"
\n
⚠️ 未找到方法: {method_name}"
)
# 写回文件
with
open
(
filepath
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
...
...
@@ -136,20 +125,6 @@ def cleanup_test_code(filepath):
new_line_count
=
len
(
lines
)
# 生成报告
print
(
"
\n
"
+
"="
*
60
)
print
(
"清理完成"
)
print
(
"="
*
60
)
print
(
f
"
\n
原文件行数: {original_line_count}"
)
print
(
f
"新文件行数: {new_line_count}"
)
print
(
f
"删除行数: {deleted_lines}"
)
print
(
f
"删除方法数: {len(deleted_methods)}"
)
# 详细报告
print
(
"
\n
删除的方法:"
)
for
method
in
reversed
(
deleted_methods
):
print
(
f
" - {method['name']}: {method['lines']} 行 (第 {method['start']}-{method['end']} 行)"
)
# 生成报告文件
report_path
=
str
(
filepath
)
.
replace
(
'.py'
,
'_cleanup_report.txt'
)
with
open
(
report_path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
...
...
@@ -167,25 +142,18 @@ def cleanup_test_code(filepath):
f
.
write
(
f
" - {method['name']}: {method['lines']} 行 (第 {method['start']}-{method['end']} 行)
\n
"
)
f
.
write
(
"
\n
"
+
"="
*
60
+
"
\n
"
)
print
(
f
"
\n
✅ 清理报告已保存到: {report_path}"
)
return
deleted_methods
def
verify_file
(
filepath
):
"""验证文件语法"""
print
(
"
\n
"
+
"="
*
60
)
print
(
"验证文件语法"
)
print
(
"="
*
60
)
try
:
with
open
(
filepath
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
code
=
f
.
read
()
compile
(
code
,
filepath
,
'exec'
)
print
(
"✅ 文件语法正确"
)
return
True
except
SyntaxError
as
e
:
print
(
f
"❌ 语法错误: {e}"
)
return
False
def
main
():
...
...
@@ -194,25 +162,11 @@ def main():
filepath
=
script_dir
/
'model_training_handler.py'
if
not
filepath
.
exists
():
print
(
f
"❌ 文件不存在: {filepath}"
)
return
False
print
(
"="
*
60
)
print
(
"模型训练处理器代码清理工具"
)
print
(
"="
*
60
)
print
(
f
"
\n
目标文件: {filepath}"
)
print
(
f
"
\n
将删除以下方法:"
)
for
method
in
METHODS_TO_DELETE
:
print
(
f
" - {method}"
)
print
(
f
"
\n
将保留以下方法:"
)
for
method
in
METHODS_TO_KEEP
:
print
(
f
" - {method}"
)
# 确认
response
=
input
(
"
\n
是否继续?(y/n): "
)
if
response
.
lower
()
!=
'y'
:
print
(
"已取消"
)
return
False
# 备份
...
...
@@ -224,26 +178,13 @@ def main():
# 验证
if
verify_file
(
filepath
):
print
(
"
\n
🎉 清理成功!"
)
print
(
f
"
\n
下一步:"
)
print
(
f
" 1. 运行集成测试: python test_integration.py"
)
print
(
f
" 2. 测试应用程序功能"
)
print
(
f
" 3. 如有问题,可从备份恢复: {backup_path}"
)
return
True
else
:
print
(
"
\n
❌ 清理后文件有语法错误,正在恢复..."
)
shutil
.
copy2
(
backup_path
,
filepath
)
print
(
f
"✅ 已从备份恢复"
)
return
False
except
Exception
as
e
:
print
(
f
"
\n
❌ 清理失败: {e}"
)
import
traceback
traceback
.
print_exc
()
print
(
"
\n
正在从备份恢复..."
)
shutil
.
copy2
(
backup_path
,
filepath
)
print
(
f
"✅ 已从备份恢复"
)
return
False
if
__name__
==
"__main__"
:
...
...
handlers/modelpage/model_page_handler.py
View file @
e491a327
...
...
@@ -79,17 +79,11 @@ class ModelPageHandler:
self
.
_model_operations
=
ModelOperations
(
handler
=
handlers
[
'model_set_handler'
])
def
create_model_page
(
self
):
"""
创建模型管理页面(已弃用)
注意:此方法已不再使用,推荐直接使用 app.py 中的 _createModelPage() 方法。
保留此方法仅用于向后兼容。
Returns:
QtWidgets.QWidget: 模型页面
"""
print
(
"[WARNING] create_model_page() 方法已弃用,请使用 app.py 中的 _createModelPage()"
)
"""创建模型页面(已弃用,保留以兼容旧代码)"""
pass
def
_createModelPage
(
self
):
"""创建模型页面的实际实现"""
# 导入页面组件(从 widgets.modelpage)
try
:
from
...widgets.modelpage.modelset_page
import
ModelSetPage
...
...
@@ -99,8 +93,7 @@ class ModelPageHandler:
from
widgets.modelpage.modelset_page
import
ModelSetPage
from
widgets.modelpage.training_page
import
TrainingPage
except
ImportError
as
e
:
print
(
f
"[ERROR] 无法导入必要的页面组件: {e}"
)
return
QtWidgets
.
QWidget
()
return
None
# 导入训练处理器
try
:
...
...
@@ -112,7 +105,6 @@ class ModelPageHandler:
from
handlers.modelpage.model_training_handler
import
ModelTrainingHandler
except
ImportError
:
ModelTrainingHandler
=
None
print
(
"[WARNING] 无法导入ModelTrainingHandler,训练功能将不可用"
)
# 创建主页面容器
page
=
QtWidgets
.
QWidget
()
...
...
@@ -130,8 +122,7 @@ class ModelPageHandler:
# 创建训练处理器
if
ModelTrainingHandler
:
self
.
_parent
.
training_handler
=
ModelTrainingHandler
()
self
.
_parent
.
training_handler
.
_set_main_window
(
self
.
_parent
)
print
(
"[OK] 训练处理器初始化成功"
)
self
.
_parent
.
training_handler
.
connectSignals
()
else
:
self
.
_parent
.
training_handler
=
None
...
...
@@ -139,10 +130,6 @@ class ModelPageHandler:
self
.
_parent
.
trainingPage
=
TrainingPage
(
parent
=
self
.
_parent
)
self
.
_parent
.
modelStackWidget
.
addWidget
(
self
.
_parent
.
trainingPage
)
# 连接训练处理器
if
self
.
_parent
.
training_handler
:
self
.
_parent
.
training_handler
.
connectToTrainingPanel
(
self
.
_parent
.
trainingPage
)
# 默认显示第一个页面(模型集管理)
self
.
_parent
.
modelStackWidget
.
setCurrentIndex
(
0
)
...
...
@@ -167,12 +154,7 @@ class ModelPageHandler:
self
.
_handlers
[
'model_signal_handler'
]
.
setupModelPageConnections
()
def
add_test_models_to_list
(
self
):
"""
添加测试模型到模型列表(已弃用)
注意:此方法已不再使用,模型应通过"模型集管理"页面手动添加。
"""
print
(
"[WARNING] add_test_models_to_list() 方法已弃用"
)
"""添加测试模型到列表(已弃用)"""
pass
# ==================== 信号处理方法 ====================
...
...
@@ -189,21 +171,11 @@ class ModelPageHandler:
QtWidgets
.
QMessageBox
.
warning
(
self
.
_parent
,
"错误"
,
f
"运行模型测试失败: {e}"
)
def
on_browse_test_file
(
self
):
"""
浏览测试文件(已弃用)
注意:模型测试功能已移除,此方法不再使用。
"""
print
(
"[WARNING] on_browse_test_file() 方法已弃用"
)
"""浏览测试文件(已弃用)"""
pass
def
on_browse_save_liquid_data_path
(
self
):
"""
浏览保存路径(已弃用)
注意:此方法已不再使用。
"""
print
(
"[WARNING] on_browse_save_liquid_data_path() 方法已弃用"
)
"""浏览保存路径(已弃用)"""
pass
def
on_add_model_set
(
self
):
...
...
handlers/modelpage/model_set_handler.py
View file @
e491a327
...
...
@@ -417,44 +417,22 @@ class ModelSetHandler:
def
loadModelsFromConfig
(
self
):
"""从配置文件和模型目录加载所有模型"""
try
:
print
(
"🚀 [模型加载] 开始加载模型列表..."
)
# 1. 加载配置文件
print
(
" [模型加载] 步骤1: 加载配置文件"
)
config
=
self
.
_loadConfigFile
()
if
not
config
:
print
(
"❌ [模型加载] 配置文件加载失败,停止加载"
)
return
print
(
"✅ [模型加载] 配置文件加载成功"
)
# 2. 跳过配置文件中的通道模型(只显示train_model目录下的模型)
print
(
" [模型加载] 步骤2: 跳过配置文件中的通道模型"
)
channel_models
=
[]
# 不加载通道模型
print
(
f
"✅ [模型加载] 跳过通道模型,专注于train_model目录"
)
# 3. 扫描模型目录
print
(
" [模型加载] 步骤3: 扫描模型目录"
)
scanned_models
=
self
.
_scanModelDirectory
()
print
(
f
"✅ [模型加载] 从目录扫描到 {len(scanned_models)} 个模型"
)
# 4. 直接使用扫描到的模型(不合并通道模型)
print
(
" [模型加载] 步骤4: 使用扫描到的模型"
)
all_models
=
scanned_models
# 直接使用扫描模型
# 设置第一个模型为默认模型(如果有模型的话)
if
len
(
all_models
)
>
0
:
all_models
[
0
][
'is_default'
]
=
True
print
(
f
"✅ [模型加载] 设置默认模型: {all_models[0]['name']}"
)
print
(
f
"✅ [模型加载] 最终显示 {len(all_models)} 个模型"
)
# 5. 更新UI
print
(
" [模型加载] 步骤5: 更新UI显示"
)
self
.
_updateModelList
(
all_models
)
print
(
"✅ [模型加载] 模型列表加载完成"
)
except
Exception
as
e
:
print
(
f
"❌ [模型加载] 加载过程中发生异常: {e}"
)
import
traceback
traceback
.
print_exc
()
...
...
@@ -543,33 +521,18 @@ class ModelSetHandler:
current_dir
=
Path
(
__file__
)
.
parent
.
parent
.
parent
model_dir
=
current_dir
/
"database"
/
"model"
/
"train_model"
print
(
f
" [模型扫描] 项目根目录: {current_dir}"
)
print
(
f
" [模型扫描] 模型目录路径: {model_dir}"
)
print
(
f
" [模型扫描] 模型目录是否存在: {model_dir.exists()}"
)
if
not
model_dir
.
exists
():
print
(
"❌ [模型扫描] 模型目录不存在,返回空列表"
)
return
models
# 列出目录中的所有项目
all_items
=
list
(
model_dir
.
iterdir
())
print
(
f
" [模型扫描] 目录中的所有项目: {[item.name for item in all_items]}"
)
# 遍历所有子目录,并按目录名排序
sorted_subdirs
=
sorted
(
model_dir
.
iterdir
(),
key
=
lambda
x
:
x
.
name
if
x
.
is_dir
()
else
''
)
print
(
f
" [模型扫描] 排序后的子目录: {[subdir.name for subdir in sorted_subdirs if subdir.is_dir()]}"
)
for
subdir
in
sorted_subdirs
:
if
subdir
.
is_dir
():
print
(
f
" [模型扫描] 正在扫描子目录: {subdir.name} ({subdir})"
)
# 列出子目录中的所有文件
subdir_files
=
list
(
subdir
.
iterdir
())
print
(
f
" [模型扫描] 子目录 {subdir.name} 中的文件: {[f.name for f in subdir_files]}"
)
# 查找 .dat 文件(优先)
dat_files
=
list
(
subdir
.
glob
(
"*.dat"
))
print
(
f
" [模型扫描] 找到的 .dat 文件: {[f.name for f in dat_files]}"
)
for
model_file
in
sorted
(
dat_files
):
model_info
=
{
...
...
@@ -580,11 +543,8 @@ class ModelSetHandler:
'format'
:
'dat'
}
models
.
append
(
model_info
)
print
(
f
"✅ [模型扫描] 添加 .dat 模型: {model_info}"
)
# 然后查找 .pt 文件
pt_files
=
list
(
subdir
.
glob
(
"*.pt"
))
print
(
f
" [模型扫描] 找到的 .pt 文件: {[f.name for f in pt_files]}"
)
for
model_file
in
sorted
(
pt_files
):
model_info
=
{
...
...
@@ -595,16 +555,11 @@ class ModelSetHandler:
'format'
:
'pt'
}
models
.
append
(
model_info
)
print
(
f
"✅ [模型扫描] 添加 .pt 模型: {model_info}"
)
else
:
print
(
f
"⚠️ [模型扫描] 跳过非目录项: {subdir.name}"
)
except
Exception
as
e
:
print
(
f
"❌ [模型扫描] 扫描过程中发生异常: {e}"
)
import
traceback
traceback
.
print_exc
()
print
(
f
" [模型扫描] 扫描完成,共找到 {len(models)} 个模型"
)
return
models
def
_mergeModelInfo
(
self
,
channel_models
,
scanned_models
):
...
...
@@ -612,19 +567,12 @@ class ModelSetHandler:
all_models
=
[]
seen_paths
=
set
()
print
(
f
" [模型合并] 开始合并模型信息"
)
print
(
f
" [模型合并] 通道模型数量: {len(channel_models)}"
)
print
(
f
" [模型合并] 扫描模型数量: {len(scanned_models)}"
)
# 优先添加配置文件中的通道模型
for
model
in
channel_models
:
path
=
model
[
'path'
]
if
path
not
in
seen_paths
:
all_models
.
append
(
model
)
seen_paths
.
add
(
path
)
print
(
f
"✅ [模型合并] 添加通道模型: {model['name']} ({path})"
)
else
:
print
(
f
"⚠️ [模型合并] 跳过重复通道模型: {model['name']} ({path})"
)
# 再添加扫描到的模型(跳过已存在的)
for
model
in
scanned_models
:
...
...
@@ -632,37 +580,26 @@ class ModelSetHandler:
if
path
not
in
seen_paths
:
all_models
.
append
(
model
)
seen_paths
.
add
(
path
)
print
(
f
"✅ [模型合并] 添加扫描模型: {model['name']} ({path})"
)
else
:
print
(
f
"⚠️ [模型合并] 跳过重复扫描模型: {model['name']} ({path})"
)
# 确保有一个默认模型
has_default
=
any
(
model
.
get
(
'is_default'
,
False
)
for
model
in
all_models
)
if
not
has_default
and
len
(
all_models
)
>
0
:
all_models
[
0
][
'is_default'
]
=
True
print
(
f
"✅ [模型合并] 设置默认模型: {all_models[0]['name']}"
)
print
(
f
" [模型合并] 合并完成,最终模型数量: {len(all_models)}"
)
return
all_models
def
_updateModelList
(
self
,
all_models
):
"""更新UI中的模型列表"""
try
:
print
(
f
" [UI更新] 开始更新模型列表,模型数量: {len(all_models)}"
)
if
not
hasattr
(
self
,
'modelSetPage'
)
or
not
self
.
modelSetPage
:
print
(
"❌ [UI更新] modelSetPage 不存在,无法更新UI"
)
return
print
(
f
"✅ [UI更新] 找到 modelSetPage,准备更新"
)
# 清空现有模型参数
self
.
modelSetPage
.
_model_params
=
{}
# 添加所有模型到UI
for
i
,
model
in
enumerate
(
all_models
):
model_name
=
model
[
'name'
]
print
(
f
" [UI更新] 处理模型 {i+1}/{len(all_models)}: {model_name}"
)
# 创建模型参数
model_params
=
self
.
_createModelParams
(
model
,
{})
...
...
@@ -671,19 +608,11 @@ class ModelSetHandler:
# 设置默认模型
if
model
.
get
(
'is_default'
,
False
):
self
.
modelSetPage
.
_current_default_model
=
model_name
print
(
f
"✅ [UI更新] 设置默认模型: {model_name}"
)
# 刷新UI显示
if
hasattr
(
self
.
modelSetPage
,
'refreshModelList'
):
print
(
f
" [UI更新] 调用 refreshModelList 刷新UI"
)
self
.
modelSetPage
.
refreshModelList
()
else
:
print
(
f
"⚠️ [UI更新] modelSetPage 没有 refreshModelList 方法"
)
print
(
f
"✅ [UI更新] 模型列表更新完成"
)
except
Exception
as
e
:
print
(
f
"❌ [UI更新] 更新UI时发生异常: {e}"
)
import
traceback
traceback
.
print_exc
()
...
...
handlers/modelpage/model_signal_handler.py
View file @
e491a327
...
...
@@ -79,13 +79,10 @@ class ModelSignalHandler:
# self.modelSetPage.setDefaultRequested.connect(
# self.model_set_handler.setAsDefaultModel
# )
print
(
"[OK] ModelSetPage 业务逻辑信号已连接到 model_set_handler"
)
else
:
print
(
"[警告] model_set_handler 未初始化,业务逻辑信号未连接"
)
if
hasattr
(
self
.
modelSetPage
,
'modelSetClicked'
):
self
.
modelSetPage
.
modelSetClicked
.
connect
(
self
.
_onModelSetPageModelSelected
)
except
Exception
as
e
:
print
(
f
"[ModelSignalHandler] 建立连接时出错: {e}"
)
import
traceback
traceback
.
print_exc
()
...
...
@@ -96,7 +93,6 @@ class ModelSignalHandler:
Args:
model_name: 选中的模型名称
"""
print
(
f
" [ModelSignalHandler] ModelSetPage 选中模型: {model_name}"
)
# 这里可以添加额外的处理逻辑,比如更新状态栏
if
hasattr
(
self
,
'statusBar'
):
self
.
statusBar
()
.
showMessage
(
f
"当前选中模型: {model_name}"
)
...
...
@@ -108,7 +104,7 @@ class ModelSignalHandler:
Args:
model_name: 新添加的模型名称
"""
p
rint
(
f
" [ModelSignalHandler] 新模型已添加: {model_name}"
)
p
ass
def
_onModelDeleted
(
self
,
model_name
):
"""
...
...
@@ -117,6 +113,4 @@ class ModelSignalHandler:
Args:
model_name: 删除的模型名称
"""
print
(
f
" [ModelSignalHandler] 模型已删除: {model_name}"
)
pass
handlers/modelpage/model_test_handler.py
View file @
e491a327
...
...
@@ -95,11 +95,6 @@ class ModelTestThread(QThread):
is_video
=
self
.
test_params
[
'is_video'
]
handler
=
self
.
test_params
[
'handler'
]
print
(
f
"[测试线程] 开始执行模型测试..."
)
print
(
f
"[测试线程] 模型: {model_path}"
)
print
(
f
"[测试线程] 测试文件: {test_file_path}"
)
print
(
f
"[测试线程] 类型: {'视频' if is_video else '图片'}"
)
if
is_video
:
# 视频文件检测
self
.
progress_updated
.
emit
(
20
,
"正在加载视频文件..."
)
...
...
@@ -113,8 +108,6 @@ class ModelTestThread(QThread):
self
.
error_occurred
.
emit
(
"文件读取失败"
,
f
"无法读取测试文件: {test_file_path}"
)
return
print
(
f
"[测试线程] 测试帧加载成功,尺寸: {test_frame.shape}"
)
self
.
progress_updated
.
emit
(
30
,
"正在执行液位检测..."
)
self
.
_performImageDetection
(
handler
,
model_path
,
test_frame
,
annotation_file
)
...
...
@@ -122,7 +115,6 @@ class ModelTestThread(QThread):
self
.
test_finished
.
emit
(
True
,
"测试完成"
)
except
Exception
as
e
:
print
(
f
"[测试线程] 测试失败: {e}"
)
import
traceback
traceback
.
print_exc
()
self
.
error_occurred
.
emit
(
type
(
e
)
.
__name__
,
str
(
e
))
...
...
@@ -132,21 +124,17 @@ class ModelTestThread(QThread):
try
:
# 导入检测引擎
self
.
progress_updated
.
emit
(
40
,
"正在导入检测引擎..."
)
print
(
f
"[测试线程] 正在导入检测引擎..."
)
try
:
from
handlers.videopage.detection
import
LiquidDetectionEngine
print
(
f
"[测试线程] 检测引擎导入成功"
)
except
ImportError
:
try
:
from
...handlers.videopage.detection
import
LiquidDetectionEngine
print
(
f
"[测试线程] 检测引擎导入成功(相对导入)"
)
except
ImportError
as
e
:
raise
ImportError
(
f
"无法导入LiquidDetectionEngine: {e}"
)
# 读取标注数据
self
.
progress_updated
.
emit
(
45
,
"正在读取标注数据..."
)
print
(
f
"[测试线程] 开始读取标注文件: {annotation_file}"
)
with
open
(
annotation_file
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
try
:
...
...
@@ -158,52 +146,38 @@ class ModelTestThread(QThread):
else
:
raise
print
(
f
"[测试线程] 标注数据加载成功"
)
# 创建检测引擎
self
.
progress_updated
.
emit
(
50
,
"正在创建检测引擎..."
)
print
(
f
"[测试线程] 正在创建检测引擎..."
)
detection_engine
=
LiquidDetectionEngine
(
model_path
=
model_path
)
self
.
progress_updated
.
emit
(
60
,
"正在加载模型权重..."
)
print
(
f
"[测试线程] 正在加载模型权重..."
)
if
not
detection_engine
.
load_model
(
model_path
):
raise
RuntimeError
(
f
"模型加载失败: {model_path}"
)
print
(
f
"[测试线程] 模型权重加载成功"
)
# 配置标注数据
self
.
progress_updated
.
emit
(
70
,
"正在配置检测参数..."
)
detection_engine
.
set_annotation_data
(
annotation_data
)
# 执行检测
self
.
progress_updated
.
emit
(
80
,
"正在执行液位检测..."
)
print
(
f
"[测试线程] 开始执行液位检测..."
)
detection_result
=
detection_engine
.
detect_liquid_level
(
test_frame
)
if
detection_result
is
None
:
raise
RuntimeError
(
"检测结果为空"
)
print
(
f
"[测试线程] 液位检测完成"
)
self
.
_detection_result
=
detection_result
# 保存图片测试结果
self
.
progress_updated
.
emit
(
90
,
"正在保存测试结果..."
)
print
(
f
"[测试线程] 保存图片测试结果..."
)
self
.
_saveImageTestResults
(
model_path
,
test_frame
,
detection_result
,
annotation_file
)
except
Exception
as
e
:
print
(
f
"[测试线程] 图片检测失败: {e}"
)
raise
def
_performVideoDetection
(
self
,
handler
,
model_path
,
video_path
,
annotation_file
):
"""执行视频检测"""
try
:
print
(
f
"[测试线程] 开始视频逐帧检测..."
)
# 视频检测需要在主线程中执行(涉及UI更新)
# 所以这里只是标记,实际检测由主线程的原有方法处理
# 发送进度信号
...
...
@@ -211,16 +185,14 @@ class ModelTestThread(QThread):
# 注意:视频检测由于涉及实时播放器等UI组件
# 暂时保持在主线程执行,这里只做标记
p
rint
(
f
"[测试线程] 视频检测将在主线程中执行"
)
p
ass
except
Exception
as
e
:
print
(
f
"[测试线程] 视频检测失败: {e}"
)
raise
def
stop
(
self
):
"""停止线程"""
self
.
is_running
=
False
print
(
f
"[测试线程] 收到停止信号"
)
def
get_detection_result
(
self
):
"""获取检测结果"""
...
...
@@ -287,14 +259,8 @@ class ModelTestHandler:
def
_handleStopTest
(
self
):
"""停止测试并释放资源"""
print
(
"
\n
"
+
"="
*
60
)
print
(
"[模型测试] 用户请求停止测试"
)
print
(
"="
*
60
)
try
:
# 设置停止标志
self
.
_detection_stopped
=
True
print
(
"[模型测试] 已设置停止标志"
)
# 恢复按钮状态
self
.
training_panel
.
setTestButtonState
(
False
)
...
...
@@ -310,21 +276,14 @@ class ModelTestHandler:
"""
self
.
training_panel
.
display_panel
.
setHtml
(
stop_html
)
print
(
"[模型测试] 测试已停止,资源已释放"
)
except
Exception
as
e
:
print
(
f
"[模型测试] 停止测试时出错: {e}"
)
import
traceback
traceback
.
print_exc
()
def
_handleStartTestExecution
(
self
):
"""执行开始测试操作 - 液位检测测试功能"""
try
:
print
(
"
\n
"
+
"="
*
60
)
print
(
"[模型测试] 开始模型测试流程"
)
print
(
"="
*
60
)
# 切换按钮状态为"停止测试"
# 切换按钮状态为“停止测试”
self
.
training_panel
.
setTestButtonState
(
True
)
# 获取选择的测试模型和测试文件
...
...
@@ -334,11 +293,6 @@ class ModelTestHandler:
test_file_path_raw
=
self
.
training_panel
.
test_file_input
.
currentData
()
or
""
test_file_display
=
self
.
training_panel
.
test_file_input
.
currentText
()
print
(
f
"[模型测试] 选择的模型: {test_model_display}"
)
print
(
f
"[模型测试] 原始模型路径: {test_model_path_raw}"
)
print
(
f
"[模型测试] 测试文件: {test_file_display}"
)
print
(
f
"[模型测试] 原始文件路径: {test_file_path_raw}"
)
# 关键修复:路径规范化处理,确保相对路径转换为绝对路径
project_root
=
get_project_root
()
...
...
@@ -346,7 +300,7 @@ class ModelTestHandler:
if
test_model_path_raw
and
not
os
.
path
.
isabs
(
test_model_path_raw
):
# 相对路径,转换为绝对路径
test_model_path
=
os
.
path
.
join
(
project_root
,
test_model_path_raw
)
p
rint
(
f
"[模型测试] 相对路径转换: {test_model_path_raw} -> {test_model_path}"
)
p
ass
else
:
test_model_path
=
test_model_path_raw
...
...
handlers/modelpage/model_training_handler.py
View file @
e491a327
This diff is collapsed.
Click to expand it.
handlers/videopage/thread_manager/threads/display_thread.py
View file @
e491a327
...
...
@@ -43,6 +43,10 @@ class DisplayThread:
# 保存上次的液位线数据(用于历史数据回退)
last_liquid_positions
=
{}
# 调试计数器(用于追踪检测启动后的帧数)
debug_frame_count
=
0
last_detection_enabled
=
False
while
context
.
display_flag
:
try
:
frame_start_time
=
time
.
time
()
...
...
@@ -59,7 +63,13 @@ class DisplayThread:
display_frame
=
frame
# 检测状态变化时重置调试计数器
if
context
.
detection_enabled
and
not
last_detection_enabled
:
debug_frame_count
=
0
last_detection_enabled
=
context
.
detection_enabled
# 如果检测已启动,叠加液位线
if
context
.
detection_enabled
:
debug_frame_count
+=
1
# 从 detection_mission_results 队列读取液位线数据(非阻塞)
liquid_positions
=
{}
...
...
handlers/videopage/thread_manager/threads/storage_thread.py
View file @
e491a327
...
...
@@ -63,55 +63,96 @@ class StorageThread:
if
not
save_liquid_data_path
or
save_liquid_data_path
==
"0000"
:
return
# print(f" [存储线程-{channel_id}] 初始化")
# print(f" - 通道名称: {channel_name}")
# print(f" - 检测区域数: {len(area_names)}")
# print(f" - 曲线存储路径: {save_liquid_data_path}")
# 创建曲线存储目录
os
.
makedirs
(
save_liquid_data_path
,
exist_ok
=
True
)
# ========== 视频保存功能(占坑,暂不实现) ==========
# TODO: 未来实现检测结果视频的保存
# timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# video_path = context.storage_path if context.storage_path else save_liquid_data_path
# display_video_path = os.path.join(video_path, f"display_{timestamp}.mp4")
# 创建CSV文件写入器(每个检测区域一个文件)
csv_files
=
{}
csv_writers
=
{}
for
area_idx
,
area_name
in
area_names
.
items
():
# 文件名:区域名称.csv(区域名称已包含通道信息,不需要重复)
#
文件名:区域名称.csv(区域名称已包含通道信息,不需要重复)
csv_filename
=
f
"{area_name}.csv"
csv_filepath
=
os
.
path
.
join
(
save_liquid_data_path
,
csv_filename
)
# 打开CSV文件(追加模式,增加缓冲区)
#
打开CSV文件(追加模式,增加缓冲区)
csv_file
=
open
(
csv_filepath
,
'a'
,
encoding
=
'utf-8'
,
buffering
=
8192
)
# 8KB缓冲
csv_files
[
area_idx
]
=
csv_file
csv_writers
[
area_idx
]
=
csv_file
# 存储线程不受 save_data_rate 限制,全速消费队列,避免数据丢失
#
存储线程不受 save_data_rate 限制,全速消费队列,避免数据丢失
# save_data_rate 仅用于配置文件记录,实际存储线程会保存所有检测结果
# print(f" [存储线程-{channel_id}] 启动成功")
# print(f" - 注意:存储线程全速运行,保存所有检测结果(不受save_data_rate限制)")
data_count
=
0
last_log_time
=
time
.
time
()
last_flush_time
=
time
.
time
()
# 记录上次刷新时间
flush_interval
=
0.5
# 批量刷新间隔(秒),每0.5秒刷新一次
last_flush_time
=
time
.
time
()
#
记录上次刷新时间
flush_interval
=
0.5
#
批量刷新间隔(秒),每0.5秒刷新一次
while
context
.
storage_flag
:
try
:
# 1. 保存检测结果到CSV(从存储数据队列读取)
try
:
# 从独立的 storage_data 队列读取,避免与曲线线程竞争
#
从独立的 storage_data 队列读取,避免与曲线线程竞争
detection_mission_result
=
context
.
storage_data
.
get
(
timeout
=
0.1
)
# # 调试信息:存储线程接收数据
# print(f"\n [存储线程-{channel_id}] 接收到检测结果:")
# print(f" - detection_mission_result类型: {type(detection_mission_result)}")
# if detection_mission_result:
# print(f" - 包含的键: {detection_mission_result.keys()}")
# 解析液位高度数据
if
detection_mission_result
and
'liquid_line_positions'
in
detection_mission_result
:
liquid_positions
=
detection_mission_result
[
'liquid_line_positions'
]
current_time
=
datetime
.
now
()
.
strftime
(
"
%
Y-
%
m-
%
d-
%
H:
%
M:
%
S.
%
f"
)[:
-
3
]
# # 调试信息:液位位置数据
# print(f" [存储线程-{channel_id}] 液位位置数据:")
# for area_idx, position_data in liquid_positions.items():
# print(f" 目标{area_idx}:")
# print(f" - position_data键: {position_data.keys()}")
# print(f" - 包含'height_cm'? {'height_cm' in position_data}")
# print(f" - 包含'height_mm'? {'height_mm' in position_data}")
# if 'height_cm' in position_data:
# print(f" - height_cm值: {position_data['height_cm']}")
# if 'height_mm' in position_data:
# print(f" - height_mm值: {position_data['height_mm']}")
# 为每个检测区域写入数据
for
area_idx
,
position_data
in
liquid_positions
.
items
():
if
area_idx
in
csv_writers
:
# 统一使用mm单位,直接读取height_mm
#
统一使用mm单位,直接读取height_mm
height_mm
=
position_data
.
get
(
'height_mm'
,
0.0
)
# # 调试信息:读取到的高度值
# print(f" [存储线程-{channel_id}] 目标{area_idx} 读取高度:")
# print(f" - height_mm: {height_mm:.2f}mm")
# 存储mm值(保留1位小数,精度0.1mm)
height_decimal
=
round
(
height_mm
,
1
)
# print(f" - 最终写入CSV: {height_decimal}mm")
# 写入格式:时间戳 高度值(mm, 保留1位小数)
csv_writers
[
area_idx
]
.
write
(
f
"{current_time} {height_decimal:.1f}
\n
"
)
# 不再立即刷新,改为批量刷新
#
不再立即刷新,改为批量刷新
data_count
+=
1
# 定时批量刷新到磁盘(每0.5秒一次)
# 定时批量刷新到磁盘(每0.5秒一次)
current_time_check
=
time
.
time
()
if
current_time_check
-
last_flush_time
>=
flush_interval
:
...
...
@@ -119,13 +160,16 @@ class StorageThread:
csv_file
.
flush
()
last_flush_time
=
current_time_check
# 每5秒打印一次统计
if
time
.
time
()
-
last_log_time
>
5.0
:
# print(f" [存储线程-{channel_id}] 已保存 {data_count} 条数据,队列大小: {context.storage_data.qsize()}")
last_log_time
=
time
.
time
()
except
queue
.
Empty
:
# 队列为空,继续等待
pass
except
Exception
as
e
:
# print(f" [存储线程-{channel_id}] CSV写入错误: {e}")
import
traceback
traceback
.
print_exc
()
...
...
@@ -136,15 +180,21 @@ class StorageThread:
# 队列的 get(timeout=0.1) 已经提供了适当的等待
except
Exception
as
e
:
# print(f" [存储线程-{channel_id}] 错误: {e}")
time
.
sleep
(
0.1
)
# 清理资源
# print(f" [存储线程-{channel_id}] 正在停止...")
# 关闭CSV文件
for
csv_file
in
csv_files
.
values
():
csv_file
.
close
()
# TODO: 未来需要释放视频写入器
# TODO: 未来需要释放视频写入器
# if display_writer:
# display_writer.release()
# print(f" [存储线程-{channel_id}] 已停止")
@staticmethod
def
_load_channel_config
(
channel_id
:
str
):
...
...
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