Commit e491a327 by Yuhaibo

1

parent 872a1442
...@@ -116,10 +116,14 @@ ...@@ -116,10 +116,14 @@
### 部分清理 ### 部分清理
17. 🔄 **handlers/videopage/missionpanel_handler.py** - 已清理前880行,删除约50处print语句(文件共2004行,需继续清理) 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注释 18.**widgets/datasetpage/crop_preview_panel.py** - 删除约47处print语句和2处DEBUG注释
19.**widgets/datasetpage/datacollection_panel.py** - 删除约20处print语句和1处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 @@ ...@@ -150,13 +154,13 @@
- ⏳ widgets/datasetpage/test_*.py - ⏳ widgets/datasetpage/test_*.py
### 剩余工作量估算 ### 剩余工作量估算
- 已清理: 约384处调试语句 (18个文件完全清理 + 1个文件部分清理) - 已清理: 约464处调试语句 (21个文件完全清理 + 2个文件部分清理)
- 剩余: 约3057处调试语句 - 剩余: 约2672处调试语句
- 预计需要: 继续手动清理约45个文件 - 预计需要: 继续手动清理约41个文件
### 本次清理总结 (2025-11-26 20:46) ### 本次清理总结 (2025-11-26 21:02)
- 完成文件数: 18个完全清理 + 1个部分清理 - 完成文件数: 21个完全清理 + 2个部分清理
- 删除调试语句: 约384处(包含print语句和DEBUG注释) - 删除调试语句: 约464处(包含print语句和DEBUG注释)
- 主要清理内容: - 主要清理内容:
- 核心应用入口和窗口管理 (app.py) - 核心应用入口和窗口管理 (app.py)
- 视图布局切换管理 (view_handler.py) - 视图布局切换管理 (view_handler.py)
...@@ -166,8 +170,9 @@ ...@@ -166,8 +170,9 @@
- 完整线程管理系统 (thread_manager.py, curve_thread.py, global_detection_thread.py, storage_thread.py, display_thread.py) - 完整线程管理系统 (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) - 完整UI组件系统 (missionpanel.py, general_set.py, curvepanel.py, historyvideopanel.py)
- 数据集页面组件 (crop_preview_panel.py, datacollection_panel.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) - 部分任务面板Handler (missionpanel_handler.py)
--- ---
*最后更新: 2025-11-26 20:46* *最后更新: 2025-11-26 21:00*
...@@ -77,30 +77,16 @@ def setup_runtime_directories(): ...@@ -77,30 +77,16 @@ def setup_runtime_directories():
if not os.path.exists(dir_path): if not os.path.exists(dir_path):
try: try:
os.makedirs(dir_path, exist_ok=True) os.makedirs(dir_path, exist_ok=True)
print(f"✓ 创建运行时目录: {dir_path}")
except Exception as e: except Exception as e:
print(f"⚠ 无法创建目录 {dir_path}: {e}") pass
# 打印配置文件读取位置说明
print(f"\n📂 配置文件读取位置: {os.path.join(sys._MEIPASS, 'database', 'config')}")
print(f"📂 运行时数据保存位置: {exe_dir}")
def main(): def main():
"""主入口函数""" """主入口函数"""
try: try:
# 在打包环境中输出详细的启动信息 # 在打包环境中创建运行时目录结构
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
pass
print(f"脚本目录: {current_dir}")
print(f"Python 版本: {sys.version}")
print("=" * 80)
print()
# 创建运行时目录结构
print("正在初始化运行时环境...")
setup_runtime_directories() setup_runtime_directories()
print()
_main() _main()
except Exception as e: except Exception as e:
...@@ -129,8 +115,6 @@ sys.path: ...@@ -129,8 +115,6 @@ sys.path:
{chr(10).join(f' - {p}' for p in sys.path)} {chr(10).join(f' - {p}' for p in sys.path)}
{'=' * 80} {'=' * 80}
""" """
print(error_log)
# 保存错误日志到文件 # 保存错误日志到文件
log_path = None log_path = None
try: try:
...@@ -138,9 +122,8 @@ sys.path: ...@@ -138,9 +122,8 @@ sys.path:
log_path = os.path.join(os.getcwd(), log_filename) log_path = os.path.join(os.getcwd(), log_filename)
with open(log_path, 'w', encoding='utf-8') as f: with open(log_path, 'w', encoding='utf-8') as f:
f.write(error_log) f.write(error_log)
print(f"\n错误日志已保存到: {log_path}")
except Exception as log_err: except Exception as log_err:
print(f"\n警告: 无法保存日志文件 - {log_err}") pass
# 在打包环境中使用更可靠的暂停方法 # 在打包环境中使用更可靠的暂停方法
if getattr(sys, 'frozen', False): if getattr(sys, 'frozen', False):
...@@ -175,9 +158,6 @@ sys.path: ...@@ -175,9 +158,6 @@ sys.path:
def _main(): def _main():
"""实际主入口函数""" """实际主入口函数"""
# 在打包环境中输出详细的初始化信息
if getattr(sys, 'frozen', False):
print("[1/6] 解析命令行参数...")
# 创建参数解析器 # 创建参数解析器
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
...@@ -224,31 +204,21 @@ def _main(): ...@@ -224,31 +204,21 @@ def _main():
args = parser.parse_args() args = parser.parse_args()
if args.version: if args.version:
print('帕特智能油液位检测 v1.0')
return return
# 从args中提取配置 # 从args中提取配置
if getattr(sys, 'frozen', False):
print("[2/6] 提取配置参数...")
config_from_args = args.__dict__ config_from_args = args.__dict__
filename = config_from_args.pop('filename') filename = config_from_args.pop('filename')
config_file_or_yaml = config_from_args.pop('config') config_file_or_yaml = config_from_args.pop('config')
version = config_from_args.pop('version') 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) log_file_path = setup_logging(args.logger_level)
logging.getLogger(__name__).debug("Logger level set to %s", 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) config = get_config(config_file_or_yaml, config_from_args)
if getattr(sys, 'frozen', False):
print(" 配置加载成功")
# 创建Qt应用 # 创建Qt应用
if getattr(sys, 'frozen', False):
print("[4/6] 创建 Qt 应用...")
app = QtWidgets.QApplication(sys.argv) app = QtWidgets.QApplication(sys.argv)
app.setApplicationName('Detection') app.setApplicationName('Detection')
app.setOrganizationName('Detection') app.setOrganizationName('Detection')
...@@ -256,21 +226,11 @@ def _main(): ...@@ -256,21 +226,11 @@ def _main():
# 应用全局字体配置 # 应用全局字体配置
FontManager.applyToApplication(app) FontManager.applyToApplication(app)
if getattr(sys, 'frozen', False):
print(" Qt 应用创建成功")
# 创建主窗口 # 创建主窗口
if getattr(sys, 'frozen', False):
print("[5/6] 创建主窗口...")
win = MainWindow( win = MainWindow(
config=config, config=config,
filename=filename, filename=filename,
) )
if getattr(sys, 'frozen', False):
print(" 主窗口创建成功")
if getattr(sys, 'frozen', False):
print("[6/6] 显示窗口并启动事件循环...")
win.show() win.show()
# 启动事件循环 # 启动事件循环
......
...@@ -190,7 +190,7 @@ except ImportError: ...@@ -190,7 +190,7 @@ except ImportError:
# ============================================================================ # ============================================================================
# 事件过滤器:用于在debug模式下拦截交互 # 事件过滤器
# ============================================================================ # ============================================================================
class MissionRequiredEventFilter(QObject): class MissionRequiredEventFilter(QObject):
...@@ -569,7 +569,6 @@ class MainWindow( ...@@ -569,7 +569,6 @@ class MainWindow(
# 初始化数据采集通道资源 # 初始化数据采集通道资源
self._initDataCollectionChannelResources() self._initDataCollectionChannelResources()
# 初始化测试调试资源(TestHandler)
if hasattr(self, '_initTestResources'): if hasattr(self, '_initTestResources'):
self._initTestResources() self._initTestResources()
...@@ -599,7 +598,6 @@ class MainWindow( ...@@ -599,7 +598,6 @@ class MainWindow(
# 连接信号槽 # 连接信号槽
self._connectSignals() self._connectSignals()
# 安装事件过滤器(debug模式下拦截交互)
self._installEventFilters() self._installEventFilters()
# 恢复窗口状态 # 恢复窗口状态
...@@ -725,7 +723,6 @@ class MainWindow( ...@@ -725,7 +723,6 @@ class MainWindow(
(670, 495) # 右下 (670, 495) # 右下
] ]
# 检查是否为debug模式
from database.config import is_debug_mode from database.config import is_debug_mode
is_debug = is_debug_mode(self._config) is_debug = is_debug_mode(self._config)
...@@ -733,7 +730,6 @@ class MainWindow( ...@@ -733,7 +730,6 @@ class MainWindow(
channel_id = f'channel{i+1}' channel_id = f'channel{i+1}'
channel_name = self.getChannelDisplayName(channel_id, i+1) channel_name = self.getChannelDisplayName(channel_id, i+1)
# 只有通道1在debug模式下显示debug文本
debug_mode = is_debug and (i == 0) debug_mode = is_debug and (i == 0)
channelPanel = ChannelPanel(channel_name, parent=self.default_channel_container, debug_mode=debug_mode) channelPanel = ChannelPanel(channel_name, parent=self.default_channel_container, debug_mode=debug_mode)
...@@ -742,11 +738,6 @@ class MainWindow( ...@@ -742,11 +738,6 @@ class MainWindow(
if hasattr(channelPanel, 'setChannelName'): if hasattr(channelPanel, 'setChannelName'):
channelPanel.setChannelName(channel_name) 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) # 🔥 为每个通道面板的任务标签设置变量名(channel1mission, channel2mission, channel3mission, channel4mission)
mission_var_name = f'channel{i+1}mission' mission_var_name = f'channel{i+1}mission'
...@@ -975,7 +966,6 @@ class MainWindow( ...@@ -975,7 +966,6 @@ class MainWindow(
# 所有任务表格的信号连接都在 MissionPanelHandler.connectMissionPanel 中处理 # 所有任务表格的信号连接都在 MissionPanelHandler.connectMissionPanel 中处理
self.connectMissionPanel(self.missionTable) self.connectMissionPanel(self.missionTable)
# ========== 测试调试按钮信号(TestHandler)==========
self._connectTestSignals(self.missionTable) self._connectTestSignals(self.missionTable)
# ========== 通道管理按钮信号 ========== # ========== 通道管理按钮信号 ==========
...@@ -1115,7 +1105,6 @@ class MainWindow( ...@@ -1115,7 +1105,6 @@ class MainWindow(
任务面板本身不受限制,始终可以交互。 任务面板本身不受限制,始终可以交互。
""" """
try: try:
# 检查是否是debug模式
from database.config import is_debug_mode from database.config import is_debug_mode
is_debug = is_debug_mode(self._config) is_debug = is_debug_mode(self._config)
...@@ -1219,12 +1208,6 @@ def main(): ...@@ -1219,12 +1208,6 @@ def main():
app.setApplicationName('Detection') app.setApplicationName('Detection')
app.setOrganizationName('Detection') app.setOrganizationName('Detection')
# 🔥 暂时禁用全局字体配置,测试是否解决重复显示问题
# FontManager.applyToApplication(app)
# 设置应用样式(可选)
# app.setStyle('Fusion')
# 创建主窗口 # 创建主窗口
win = MainWindow(config={}) win = MainWindow(config={})
win.show() win.show()
......
...@@ -83,7 +83,6 @@ class AnnotationHandler(QtCore.QObject): ...@@ -83,7 +83,6 @@ class AnnotationHandler(QtCore.QObject):
bool: 是否成功 bool: 是否成功
""" """
if not dir_path or not osp.exists(dir_path): if not dir_path or not osp.exists(dir_path):
print(f"目录不存在: {dir_path}")
return False return False
# 停止之前的监控 # 停止之前的监控
...@@ -116,18 +115,15 @@ class AnnotationHandler(QtCore.QObject): ...@@ -116,18 +115,15 @@ class AnnotationHandler(QtCore.QObject):
# 添加目录到监控列表 # 添加目录到监控列表
if self.current_dir not in self.file_watcher.directories(): if self.current_dir not in self.file_watcher.directories():
self.file_watcher.addPath(self.current_dir) self.file_watcher.addPath(self.current_dir)
print(f"[AnnotationHandler] 开始监控目录: {self.current_dir}")
# 启动定时刷新 # 启动定时刷新
if not self.refresh_timer.isActive(): if not self.refresh_timer.isActive():
self.refresh_timer.start(self.refresh_interval) self.refresh_timer.start(self.refresh_interval)
print(f"[AnnotationHandler] 启动定时刷新 (间隔: {self.refresh_interval}ms)")
self.monitoring_enabled = True self.monitoring_enabled = True
return True return True
except Exception as e: except Exception as e:
print(f"[AnnotationHandler] 启动监控失败: {e}")
return False return False
def stopMonitoring(self): def stopMonitoring(self):
...@@ -147,14 +143,12 @@ class AnnotationHandler(QtCore.QObject): ...@@ -147,14 +143,12 @@ class AnnotationHandler(QtCore.QObject):
self.refresh_timer.stop() self.refresh_timer.stop()
self.monitoring_enabled = False self.monitoring_enabled = False
print(f"[AnnotationHandler] 停止监控")
except Exception as e: except Exception as e:
print(f"[AnnotationHandler] 停止监控失败: {e}") pass
def _onDirectoryChanged(self, path): def _onDirectoryChanged(self, path):
"""目录内容变化回调""" """目录内容变化回调"""
print(f"[AnnotationHandler] 检测到目录变化: {path}")
# 重新扫描文件 # 重新扫描文件
old_files = set(self.image_files) old_files = set(self.image_files)
...@@ -164,13 +158,11 @@ class AnnotationHandler(QtCore.QObject): ...@@ -164,13 +158,11 @@ class AnnotationHandler(QtCore.QObject):
# 检测新增文件 # 检测新增文件
added_files = new_files - old_files added_files = new_files - old_files
for file_path in added_files: for file_path in added_files:
print(f"[AnnotationHandler] 新增文件: {osp.basename(file_path)}")
self.fileAdded.emit(file_path) self.fileAdded.emit(file_path)
# 检测删除文件 # 检测删除文件
removed_files = old_files - new_files removed_files = old_files - new_files
for file_path in removed_files: for file_path in removed_files:
print(f"[AnnotationHandler] 删除文件: {osp.basename(file_path)}")
if file_path in self.file_info_dict: if file_path in self.file_info_dict:
del self.file_info_dict[file_path] del self.file_info_dict[file_path]
self.fileRemoved.emit(file_path) self.fileRemoved.emit(file_path)
...@@ -183,7 +175,6 @@ class AnnotationHandler(QtCore.QObject): ...@@ -183,7 +175,6 @@ class AnnotationHandler(QtCore.QObject):
def _onFileChanged(self, path): def _onFileChanged(self, path):
"""文件变化回调""" """文件变化回调"""
print(f"[AnnotationHandler] 检测到文件变化: {osp.basename(path)}")
# 刷新该文件的信息 # 刷新该文件的信息
if path in self.file_info_dict: if path in self.file_info_dict:
...@@ -212,7 +203,6 @@ class AnnotationHandler(QtCore.QObject): ...@@ -212,7 +203,6 @@ class AnnotationHandler(QtCore.QObject):
if json_exists_now != json_existed_before: if json_exists_now != json_existed_before:
# JSON文件状态发生变化 # JSON文件状态发生变化
print(f"[AnnotationHandler] JSON状态变化: {osp.basename(image_path)} - {'新增' if json_exists_now else '删除'}")
self.refreshFileInfo(image_path) self.refreshFileInfo(image_path)
has_changes = True has_changes = True
elif json_exists_now: elif json_exists_now:
...@@ -222,7 +212,6 @@ class AnnotationHandler(QtCore.QObject): ...@@ -222,7 +212,6 @@ class AnnotationHandler(QtCore.QObject):
# 重新获取JSON信息来检查 # 重新获取JSON信息来检查
json_info = self.getJsonInfo(json_path) json_info = self.getJsonInfo(json_path)
if json_info['shapes_count'] != old_info['shapes_count']: if json_info['shapes_count'] != old_info['shapes_count']:
print(f"[AnnotationHandler] JSON内容变化: {osp.basename(image_path)}")
self.refreshFileInfo(image_path) self.refreshFileInfo(image_path)
has_changes = True has_changes = True
except Exception as e: except Exception as e:
...@@ -235,7 +224,7 @@ class AnnotationHandler(QtCore.QObject): ...@@ -235,7 +224,7 @@ class AnnotationHandler(QtCore.QObject):
self.fileListUpdated.emit(self.getAllFileInfoList()) self.fileListUpdated.emit(self.getAllFileInfoList())
except Exception as e: except Exception as e:
print(f"[AnnotationHandler] 定时刷新出错: {e}") pass
def setRefreshInterval(self, interval_ms): def setRefreshInterval(self, interval_ms):
""" """
...@@ -249,7 +238,6 @@ class AnnotationHandler(QtCore.QObject): ...@@ -249,7 +238,6 @@ class AnnotationHandler(QtCore.QObject):
if self.refresh_timer.isActive(): if self.refresh_timer.isActive():
self.refresh_timer.stop() self.refresh_timer.stop()
self.refresh_timer.start(self.refresh_interval) self.refresh_timer.start(self.refresh_interval)
print(f"[AnnotationHandler] 刷新间隔已更新: {interval_ms}ms")
def scanImageFiles(self): def scanImageFiles(self):
""" """
...@@ -272,12 +260,10 @@ class AnnotationHandler(QtCore.QObject): ...@@ -272,12 +260,10 @@ class AnnotationHandler(QtCore.QObject):
# 排序 # 排序
self.image_files.sort() self.image_files.sort()
print(f"扫描到 {len(self.image_files)} 个图片文件")
return True return True
except Exception as e: except Exception as e:
print(f"扫描文件夹失败: {e}")
return False return False
def loadFileInfoList(self): def loadFileInfoList(self):
...@@ -332,7 +318,7 @@ class AnnotationHandler(QtCore.QObject): ...@@ -332,7 +318,7 @@ class AnnotationHandler(QtCore.QObject):
else: else:
info['file_size_str'] = f"{file_size / (1024 * 1024):.1f} MB" info['file_size_str'] = f"{file_size / (1024 * 1024):.1f} MB"
except Exception as e: except Exception as e:
print(f"获取文件大小失败: {e}") pass
# 获取分辨率 # 获取分辨率
try: try:
...@@ -349,7 +335,7 @@ class AnnotationHandler(QtCore.QObject): ...@@ -349,7 +335,7 @@ class AnnotationHandler(QtCore.QObject):
QtCore.Qt.SmoothTransformation QtCore.Qt.SmoothTransformation
) )
except Exception as e: except Exception as e:
print(f"获取图片信息失败: {e}") pass
# 如果有JSON文件,获取JSON信息 # 如果有JSON文件,获取JSON信息
if info['has_json']: if info['has_json']:
...@@ -390,7 +376,7 @@ class AnnotationHandler(QtCore.QObject): ...@@ -390,7 +376,7 @@ class AnnotationHandler(QtCore.QObject):
info['modified_time'] = datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S') info['modified_time'] = datetime.fromtimestamp(mtime).strftime('%Y-%m-%d %H:%M:%S')
except Exception as e: except Exception as e:
print(f"读取JSON文件失败: {e}") pass
return info return info
...@@ -534,11 +520,9 @@ class AnnotationHandler(QtCore.QObject): ...@@ -534,11 +520,9 @@ class AnnotationHandler(QtCore.QObject):
with open(output_path, 'w', encoding='utf-8') as f: with open(output_path, 'w', encoding='utf-8') as f:
json.dump(export_data, f, ensure_ascii=False, indent=2) json.dump(export_data, f, ensure_ascii=False, indent=2)
print(f"统计信息已导出到: {output_path}")
return True return True
except Exception as e: except Exception as e:
print(f"导出统计信息失败: {e}")
return False return False
......
...@@ -175,7 +175,6 @@ class DataCollectionChannelHandler: ...@@ -175,7 +175,6 @@ class DataCollectionChannelHandler:
def _connectDataCollectionChannelThread(self, channel_source): def _connectDataCollectionChannelThread(self, channel_source):
"""在后台线程中连接数据采集通道(使用与实时监测管理相同的方式)""" """在后台线程中连接数据采集通道(使用与实时监测管理相同的方式)"""
try: try:
print(f"[DEBUG] 开始连接通道: {channel_source}")
success = False success = False
error_detail = "" error_detail = ""
...@@ -188,9 +187,7 @@ class DataCollectionChannelHandler: ...@@ -188,9 +187,7 @@ class DataCollectionChannelHandler:
error_detail = f"无法连接到配置的通道 {channel_source}\n请检查:\n1. 相机是否已开机并连接到网络\n2. IP地址和端口是否正确" error_detail = f"无法连接到配置的通道 {channel_source}\n请检查:\n1. 相机是否已开机并连接到网络\n2. IP地址和端口是否正确"
else: else:
# 如果没有配置,尝试直接连接USB通道 # 如果没有配置,尝试直接连接USB通道
print(f"[DEBUG] 尝试连接USB通道: {channel_source}")
success = self._connectUSBChannel(channel_source) success = self._connectUSBChannel(channel_source)
print(f"[DEBUG] USB通道连接结果: {success}")
if not success: if not success:
error_detail = f"无法连接到USB通道 {channel_source}\n请检查:\n1. USB相机是否已连接\n2. 相机驱动是否已安装\n3. 相机是否被其他程序占用" error_detail = f"无法连接到USB通道 {channel_source}\n请检查:\n1. USB相机是否已连接\n2. 相机驱动是否已安装\n3. 相机是否被其他程序占用"
else: else:
...@@ -200,8 +197,6 @@ class DataCollectionChannelHandler: ...@@ -200,8 +197,6 @@ class DataCollectionChannelHandler:
error_detail = f"无法连接到RTSP地址\n请检查:\n1. 网络连接是否正常\n2. RTSP地址格式是否正确\n3. 相机是否支持RTSP协议\n\n地址:{channel_source}" error_detail = f"无法连接到RTSP地址\n请检查:\n1. 网络连接是否正常\n2. RTSP地址格式是否正确\n3. 相机是否支持RTSP协议\n\n地址:{channel_source}"
if not success: if not success:
print(f"[DEBUG] 连接失败,显示错误对话框")
print(f"[DEBUG] 错误详情: {error_detail}")
self._showDataCollectionChannelError( self._showDataCollectionChannelError(
"相机连接失败", "相机连接失败",
error_detail if error_detail else "无法打开通道设备,请检查通道是否连接正常或配置是否正确" error_detail if error_detail else "无法打开通道设备,请检查通道是否连接正常或配置是否正确"
...@@ -756,32 +751,22 @@ class DataCollectionChannelHandler: ...@@ -756,32 +751,22 @@ class DataCollectionChannelHandler:
def _showDataCollectionChannelError(self, title, message): 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) self._dc_error_signal.error.emit(title, message)
print(f"[DEBUG] 错误信号已发射")
def _showDataCollectionChannelErrorUI(self, title, message): def _showDataCollectionChannelErrorUI(self, title, message):
"""在主线程中显示数据采集通道错误""" """在主线程中显示数据采集通道错误"""
try: try:
print(f"[DEBUG] _showDataCollectionChannelErrorUI 被调用,准备显示对话框")
if DialogManager: if DialogManager:
DialogManager.show_critical(self, title, message) DialogManager.show_critical(self, title, message)
else: else:
QtWidgets.QMessageBox.critical(self, title, message) QtWidgets.QMessageBox.critical(self, title, message)
print(f"[DEBUG] 错误对话框已显示")
if hasattr(self, 'statusBar'): if hasattr(self, 'statusBar'):
self.statusBar().showMessage(f"错误: {message}") self.statusBar().showMessage(f"错误: {message}")
except Exception as e: except Exception as e:
print(f"[DEBUG] 显示错误对话框时发生异常: {e}") pass
import traceback
traceback.print_exc()
def getDataCollectionChannelStatus(self): def getDataCollectionChannelStatus(self):
""" """
......
...@@ -175,7 +175,6 @@ class DrawableLabel(QtWidgets.QLabel): ...@@ -175,7 +175,6 @@ class DrawableLabel(QtWidgets.QLabel):
self._rectangles.pop(index) self._rectangles.pop(index)
self._redrawAllRectangles() self._redrawAllRectangles()
self.rectangleDeleted.emit(index) self.rectangleDeleted.emit(index)
print(f"[DrawableLabel] 删除区域 {index + 1}")
def _getRectangleAtPosition(self, pos): def _getRectangleAtPosition(self, pos):
""" """
...@@ -884,26 +883,22 @@ class VideoControlBar(QtWidgets.QWidget): ...@@ -884,26 +883,22 @@ class VideoControlBar(QtWidgets.QWidget):
if obj == self.start_marker: if obj == self.start_marker:
# 当前对象是绿色标记,提升它并允许它处理事件 # 当前对象是绿色标记,提升它并允许它处理事件
self.start_marker.raise_() self.start_marker.raise_()
print(f"[VideoControlBar] 绿色标记处理点击 (像素距离: {dist_to_start_pixel:.1f})")
return super(VideoControlBar, self).eventFilter(obj, event) return super(VideoControlBar, self).eventFilter(obj, event)
else: else:
# 当前对象是红色标记,但应该由绿色标记处理 # 当前对象是红色标记,但应该由绿色标记处理
# 阻止红色标记处理该事件 # 阻止红色标记处理该事件
self.start_marker.raise_() self.start_marker.raise_()
print(f"[VideoControlBar] 阻止红色标记响应,应由绿色标记处理 (绿色距离: {dist_to_start_pixel:.1f})")
return True # 阻止事件继续传播到红色标记 return True # 阻止事件继续传播到红色标记
else: else:
# 更接近结束标记的handle,应该由红色标记处理 # 更接近结束标记的handle,应该由红色标记处理
if obj == self.end_marker: if obj == self.end_marker:
# 当前对象是红色标记,提升它并允许它处理事件 # 当前对象是红色标记,提升它并允许它处理事件
self.end_marker.raise_() self.end_marker.raise_()
print(f"[VideoControlBar] 红色标记处理点击 (像素距离: {dist_to_end_pixel:.1f})")
return super(VideoControlBar, self).eventFilter(obj, event) return super(VideoControlBar, self).eventFilter(obj, event)
else: else:
# 当前对象是绿色标记,但应该由红色标记处理 # 当前对象是绿色标记,但应该由红色标记处理
# 阻止绿色标记处理该事件 # 阻止绿色标记处理该事件
self.end_marker.raise_() self.end_marker.raise_()
print(f"[VideoControlBar] 阻止绿色标记响应,应由红色标记处理 (红色距离: {dist_to_end_pixel:.1f})")
return True # 阻止事件继续传播到绿色标记 return True # 阻止事件继续传播到绿色标记
# 继续正常的事件处理 # 继续正常的事件处理
...@@ -948,8 +943,6 @@ class VideoControlBar(QtWidgets.QWidget): ...@@ -948,8 +943,6 @@ class VideoControlBar(QtWidgets.QWidget):
self.start_marker.raise_() # 提升绿色标记 self.start_marker.raise_() # 提升绿色标记
self.end_marker.raise_() # 提升红色标记 self.end_marker.raise_() # 提升红色标记
print(f"[VideoControlBar] 时间段标记已显示: 绿点在帧{self._start_frame}, 红点在帧{self._end_frame}")
self._updateTimeRangeDisplay() self._updateTimeRangeDisplay()
self._updateTimeRangeHighlight() self._updateTimeRangeHighlight()
...@@ -974,7 +967,6 @@ class VideoControlBar(QtWidgets.QWidget): ...@@ -974,7 +967,6 @@ class VideoControlBar(QtWidgets.QWidget):
def _onStartMarkerChanged(self, value): def _onStartMarkerChanged(self, value):
"""起始标记变化""" """起始标记变化"""
print(f"[VideoControlBar] 绿色标记值变化: {value}")
# 确保起始帧不超过结束帧 # 确保起始帧不超过结束帧
if value > self._end_frame: if value > self._end_frame:
...@@ -992,7 +984,6 @@ class VideoControlBar(QtWidgets.QWidget): ...@@ -992,7 +984,6 @@ class VideoControlBar(QtWidgets.QWidget):
def _onEndMarkerChanged(self, value): def _onEndMarkerChanged(self, value):
"""结束标记变化""" """结束标记变化"""
print(f"[VideoControlBar] 红色标记值变化: {value}")
# 确保结束帧不小于起始帧 # 确保结束帧不小于起始帧
if value < self._start_frame: if value < self._start_frame:
...@@ -1059,10 +1050,8 @@ class VideoControlBar(QtWidgets.QWidget): ...@@ -1059,10 +1050,8 @@ class VideoControlBar(QtWidgets.QWidget):
# 这样确保正在拖动的标记始终可见且可操作 # 这样确保正在拖动的标记始终可见且可操作
if marker_type == 'start': if marker_type == 'start':
self.start_marker.raise_() self.start_marker.raise_()
print(f"[VideoControlBar] 拖动绿色标记 (当前位置: 帧{self._start_frame})")
else: else:
self.end_marker.raise_() self.end_marker.raise_()
print(f"[VideoControlBar] 拖动红色标记 (当前位置: 帧{self._end_frame})")
# 更新高亮显示 # 更新高亮显示
self._updateTimeRangeHighlight() self._updateTimeRangeHighlight()
...@@ -1220,12 +1209,9 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1220,12 +1209,9 @@ class DataPreprocessHandler(QtCore.QObject):
def _showWarning(self, title, message): def _showWarning(self, title, message):
"""显示警告对话框""" """显示警告对话框"""
print(f"[DEBUG] _showWarning 被调用, DialogManager={'存在' if DialogManager else '不存在'}")
if DialogManager: if DialogManager:
print(f"[DEBUG] 使用 DialogManager.show_warning")
DialogManager.show_warning(self._panel, title, message) DialogManager.show_warning(self._panel, title, message)
else: else:
print(f"[DEBUG] 使用原生 QMessageBox.warning")
QtWidgets.QMessageBox.warning(self._panel, title, message) QtWidgets.QMessageBox.warning(self._panel, title, message)
def _showInformation(self, title, message): def _showInformation(self, title, message):
...@@ -1367,9 +1353,7 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1367,9 +1353,7 @@ class DataPreprocessHandler(QtCore.QObject):
new_widget.control_bar.timeRangeChanged.connect(self._onTimeRangeChanged) new_widget.control_bar.timeRangeChanged.connect(self._onTimeRangeChanged)
except Exception as e: except Exception as e:
print(f"[ERROR] 替换视频预览组件失败: {e}") pass
import traceback
traceback.print_exc()
def _initCropPreviewHandler(self): def _initCropPreviewHandler(self):
"""初始化裁剪预览处理器(延迟初始化,避免首次卡顿)""" """初始化裁剪预览处理器(延迟初始化,避免首次卡顿)"""
...@@ -1383,12 +1367,7 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1383,12 +1367,7 @@ class DataPreprocessHandler(QtCore.QObject):
# 连接信号:裁剪完成时刷新显示 # 连接信号:裁剪完成时刷新显示
self.cropFinished.connect(self._onCropFinishedForPreview) self.cropFinished.connect(self._onCropFinishedForPreview)
print("[DataPreprocessHandler] 裁剪预览处理器信号已连接(延迟初始化)")
except Exception as e: except Exception as e:
print(f"[DataPreprocessHandler] 初始化裁剪预览处理器失败: {e}")
import traceback
traceback.print_exc()
self._crop_preview_handler = None self._crop_preview_handler = None
def _ensureCropPreviewHandler(self): def _ensureCropPreviewHandler(self):
...@@ -1406,21 +1385,14 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1406,21 +1385,14 @@ class DataPreprocessHandler(QtCore.QObject):
if crop_preview_panel is not None: if crop_preview_panel is not None:
# 创建裁剪预览处理器 # 创建裁剪预览处理器
print("[DataPreprocessHandler] 首次创建裁剪预览处理器...")
self._crop_preview_handler = CropPreviewHandler(crop_preview_panel) self._crop_preview_handler = CropPreviewHandler(crop_preview_panel)
print("[DataPreprocessHandler] 裁剪预览处理器创建成功")
return True return True
else: else:
print("[DataPreprocessHandler] 裁剪预览面板不可用")
return False return False
else: else:
print("[DataPreprocessHandler] 面板不支持裁剪预览功能")
return False return False
except Exception as e: except Exception as e:
print(f"[DataPreprocessHandler] 创建裁剪预览处理器失败: {e}")
import traceback
traceback.print_exc()
self._crop_preview_handler = None self._crop_preview_handler = None
return False return False
...@@ -1428,7 +1400,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1428,7 +1400,6 @@ class DataPreprocessHandler(QtCore.QObject):
"""从文件加载视频与裁剪图片的映射关系""" """从文件加载视频与裁剪图片的映射关系"""
try: try:
if not osp.exists(self._mapping_file): if not osp.exists(self._mapping_file):
print(f"[DataPreprocessHandler] 映射文件不存在,跳过加载")
return return
import json import json
...@@ -1442,15 +1413,9 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1442,15 +1413,9 @@ class DataPreprocessHandler(QtCore.QObject):
if osp.exists(video_path): if osp.exists(video_path):
self._video_crop_mapping[video_path] = info self._video_crop_mapping[video_path] = info
loaded_count += 1 loaded_count += 1
else:
print(f"[DataPreprocessHandler] 视频文件不存在,跳过: {video_path}")
print(f"[DataPreprocessHandler] 成功加载 {loaded_count} 个视频裁剪映射")
except Exception as e: except Exception as e:
print(f"[DataPreprocessHandler] 加载映射文件失败: {e}") pass
import traceback
traceback.print_exc()
def _saveMappingToFile(self): def _saveMappingToFile(self):
"""保存视频与裁剪图片的映射关系到文件""" """保存视频与裁剪图片的映射关系到文件"""
...@@ -1465,12 +1430,8 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1465,12 +1430,8 @@ class DataPreprocessHandler(QtCore.QObject):
with open(self._mapping_file, 'w', encoding='utf-8') as f: with open(self._mapping_file, 'w', encoding='utf-8') as f:
json.dump(self._video_crop_mapping, f, ensure_ascii=False, indent=2) json.dump(self._video_crop_mapping, f, ensure_ascii=False, indent=2)
print(f"[DataPreprocessHandler] 已保存 {len(self._video_crop_mapping)} 个视频裁剪映射到文件")
except Exception as e: except Exception as e:
print(f"[DataPreprocessHandler] 保存映射文件失败: {e}") pass
import traceback
traceback.print_exc()
def updateVideoGridStyles(self): def updateVideoGridStyles(self):
"""更新视频网格中所有视频的样式,标记已裁剪的视频""" """更新视频网格中所有视频的样式,标记已裁剪的视频"""
...@@ -1527,7 +1488,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1527,7 +1488,6 @@ class DataPreprocessHandler(QtCore.QObject):
item.setBackground(QtGui.QColor(255, 255, 255)) # 白色背景 item.setBackground(QtGui.QColor(255, 255, 255)) # 白色背景
item.setForeground(QtGui.QColor(0, 0, 0)) # 黑色文字 item.setForeground(QtGui.QColor(0, 0, 0)) # 黑色文字
removed_mappings.append(video_path) removed_mappings.append(video_path)
print(f"[DataPreprocessHandler] 视频 {osp.basename(video_path)} 的裁剪图片已被删除,移除绿色标识")
else: else:
# 未裁剪,恢复默认样式 # 未裁剪,恢复默认样式
item.setBackground(QtGui.QColor(255, 255, 255)) # 白色背景 item.setBackground(QtGui.QColor(255, 255, 255)) # 白色背景
...@@ -1539,9 +1499,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1539,9 +1499,6 @@ class DataPreprocessHandler(QtCore.QObject):
del self._video_crop_mapping[video_path] del self._video_crop_mapping[video_path]
# 保存更新后的映射关系 # 保存更新后的映射关系
self._saveMappingToFile() self._saveMappingToFile()
print(f"[DataPreprocessHandler] 已移除 {len(removed_mappings)} 个无效映射")
print(f"[DataPreprocessHandler] 已更新视频网格样式,标记 {cropped_count} 个已裁剪视频")
def _checkCroppedImagesExist(self, crop_info): def _checkCroppedImagesExist(self, crop_info):
""" """
...@@ -1574,14 +1531,12 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1574,14 +1531,12 @@ class DataPreprocessHandler(QtCore.QObject):
# 找到至少一张图片,说明裁剪图片存在 # 找到至少一张图片,说明裁剪图片存在
return True return True
except Exception as e: except Exception as e:
print(f"[DataPreprocessHandler] 检查文件夹失败: {region_path}, 错误: {e}")
continue continue
# 所有区域文件夹都不存在或都没有图片 # 所有区域文件夹都不存在或都没有图片
return False return False
except Exception as e: except Exception as e:
print(f"[DataPreprocessHandler] 检查裁剪图片存在性失败: {e}")
return False return False
def _loadCroppedImagesForVideo(self, video_path): def _loadCroppedImagesForVideo(self, video_path):
...@@ -1589,7 +1544,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1589,7 +1544,6 @@ class DataPreprocessHandler(QtCore.QObject):
try: try:
# 检查该视频是否有裁剪记录 # 检查该视频是否有裁剪记录
if video_path not in self._video_crop_mapping: if video_path not in self._video_crop_mapping:
print(f"[DataPreprocessHandler] 视频 {osp.basename(video_path)} 没有裁剪记录")
# 清空预览面板 # 清空预览面板
if self._ensureCropPreviewHandler(): if self._ensureCropPreviewHandler():
self._crop_preview_handler.clearDisplay() self._crop_preview_handler.clearDisplay()
...@@ -1600,9 +1554,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1600,9 +1554,6 @@ class DataPreprocessHandler(QtCore.QObject):
save_path = crop_info['save_path'] save_path = crop_info['save_path']
region_paths = crop_info['region_paths'] region_paths = crop_info['region_paths']
print(f"[DataPreprocessHandler] 加载视频裁剪图片: {osp.basename(video_path)}")
print(f"[DataPreprocessHandler] 区域数量: {len(region_paths)}")
# 使用裁剪预览处理器加载并显示图片 # 使用裁剪预览处理器加载并显示图片
if self._ensureCropPreviewHandler(): if self._ensureCropPreviewHandler():
# 获取视频名称(不含扩展名) # 获取视频名称(不含扩展名)
...@@ -1613,14 +1564,9 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1613,14 +1564,9 @@ class DataPreprocessHandler(QtCore.QObject):
save_path, save_path,
video_name=video_name video_name=video_name
) )
print(f"[DataPreprocessHandler] 已加载视频 {video_name} 的裁剪预览")
else:
print("[DataPreprocessHandler] 裁剪预览处理器不可用")
except Exception as e: except Exception as e:
print(f"[DataPreprocessHandler] 加载裁剪图片失败: {e}") pass
import traceback
traceback.print_exc()
def _onCropStartedForPreview(self, config): def _onCropStartedForPreview(self, config):
"""裁剪任务开始 - 启动预览监控""" """裁剪任务开始 - 启动预览监控"""
...@@ -1635,10 +1581,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1635,10 +1581,6 @@ class DataPreprocessHandler(QtCore.QObject):
# 从视频路径中提取视频名称(不含扩展名) # 从视频路径中提取视频名称(不含扩展名)
video_name = osp.splitext(osp.basename(video_path))[0] video_name = osp.splitext(osp.basename(video_path))[0]
print(f"[DataPreprocessHandler] 启动裁剪预览监控: {save_liquid_data_path}")
print(f"[DataPreprocessHandler] 当前视频: {video_name}")
print(f"[DataPreprocessHandler] 清空上一个视频的预览")
# 启动新的监控(自动清空旧显示,只监控当前视频的区域文件夹) # 启动新的监控(自动清空旧显示,只监控当前视频的区域文件夹)
self._crop_preview_handler.startMonitoring( self._crop_preview_handler.startMonitoring(
save_liquid_data_path, save_liquid_data_path,
...@@ -1649,9 +1591,9 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1649,9 +1591,9 @@ class DataPreprocessHandler(QtCore.QObject):
def _onCropFinishedForPreview(self, save_liquid_data_path): def _onCropFinishedForPreview(self, save_liquid_data_path):
"""裁剪任务完成 - 刷新预览显示""" """裁剪任务完成 - 刷新预览显示"""
if self._crop_preview_handler is not None: if self._crop_preview_handler is not None:
print(f"[DataPreprocessHandler] 裁剪任务完成")
# 注意:不需要手动刷新,实时监控已经在工作 # 注意:不需要手动刷新,实时监控已经在工作
# 避免重新加载可能导致显示旧任务的图片 # 避免重新加载可能导致显示旧任务的图片
pass
def _connectSignals(self): def _connectSignals(self):
"""连接信号""" """连接信号"""
...@@ -1683,7 +1625,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1683,7 +1625,6 @@ class DataPreprocessHandler(QtCore.QObject):
def _onFolderSelected(self, folder_path): def _onFolderSelected(self, folder_path):
"""文件夹被选中(视频列表加载完成)""" """文件夹被选中(视频列表加载完成)"""
print(f"[DataPreprocessHandler] 文件夹被选中: {folder_path}")
# 延迟更新样式,确保视频网格已经加载完成 # 延迟更新样式,确保视频网格已经加载完成
# 使用QTimer.singleShot延迟100ms执行 # 使用QTimer.singleShot延迟100ms执行
...@@ -1691,7 +1632,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1691,7 +1632,6 @@ class DataPreprocessHandler(QtCore.QObject):
def _onVideoRenamed(self, old_path, new_path): def _onVideoRenamed(self, old_path, new_path):
"""视频被重命名,更新映射关系""" """视频被重命名,更新映射关系"""
print(f"[DataPreprocessHandler] 视频重命名: {osp.basename(old_path)} -> {osp.basename(new_path)}")
# 检查旧路径是否在映射中 # 检查旧路径是否在映射中
if old_path in self._video_crop_mapping: if old_path in self._video_crop_mapping:
...@@ -1704,8 +1644,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1704,8 +1644,6 @@ class DataPreprocessHandler(QtCore.QObject):
# 添加新路径的映射 # 添加新路径的映射
self._video_crop_mapping[new_path] = crop_info self._video_crop_mapping[new_path] = crop_info
print(f"[DataPreprocessHandler] 已更新映射关系: {osp.basename(old_path)} -> {osp.basename(new_path)}")
# 保存到文件 # 保存到文件
self._saveMappingToFile() self._saveMappingToFile()
...@@ -1713,7 +1651,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1713,7 +1651,6 @@ class DataPreprocessHandler(QtCore.QObject):
# 因为重命名任何视频都会导致视频列表重新加载,需要重新应用样式 # 因为重命名任何视频都会导致视频列表重新加载,需要重新应用样式
# 延迟执行,等待视频列表刷新完成 # 延迟执行,等待视频列表刷新完成
QTimer.singleShot(200, self.updateVideoGridStyles) QTimer.singleShot(200, self.updateVideoGridStyles)
print(f"[DataPreprocessHandler] 已安排更新视频网格样式")
def _onVideoSelected(self, video_path): def _onVideoSelected(self, video_path):
"""视频被选中""" """视频被选中"""
...@@ -1750,9 +1687,8 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1750,9 +1687,8 @@ class DataPreprocessHandler(QtCore.QObject):
if self._current_video_capture is not None: if self._current_video_capture is not None:
self._current_video_capture.release() self._current_video_capture.release()
self._current_video_capture = None self._current_video_capture = None
print(f"[DataPreprocessHandler] 已释放视频文件句柄")
except Exception as e: except Exception as e:
print(f"[DataPreprocessHandler] 释放视频文件句柄失败: {e}") pass
def _loadVideoInfo(self, video_path): def _loadVideoInfo(self, video_path):
"""加载视频信息""" """加载视频信息"""
...@@ -1791,7 +1727,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1791,7 +1727,6 @@ class DataPreprocessHandler(QtCore.QObject):
self._video_height = 0 self._video_height = 0
self._video_total_frames = 0 self._video_total_frames = 0
self._video_fps = 25.0 self._video_fps = 25.0
print(f"[ERROR] 加载视频信息失败: {e}")
def _showFrame(self, frame_index): def _showFrame(self, frame_index):
"""显示指定帧""" """显示指定帧"""
...@@ -1836,7 +1771,7 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1836,7 +1771,7 @@ class DataPreprocessHandler(QtCore.QObject):
control_bar.setCurrentFrame(frame_index) control_bar.setCurrentFrame(frame_index)
except Exception as e: except Exception as e:
print(f"[ERROR] 显示帧失败: {e}") pass
def _onPlayPause(self, is_playing): def _onPlayPause(self, is_playing):
"""播放/暂停按钮点击""" """播放/暂停按钮点击"""
...@@ -1850,7 +1785,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1850,7 +1785,6 @@ class DataPreprocessHandler(QtCore.QObject):
control_bar = self._panel.video_preview_widget.control_bar control_bar = self._panel.video_preview_widget.control_bar
if control_bar.isTimeRangeMode(): if control_bar.isTimeRangeMode():
start_frame, end_frame = control_bar.getTimeRange() start_frame, end_frame = control_bar.getTimeRange()
print(f"[DataPreprocessHandler] 播放选定时间段: 帧 {start_frame} - {end_frame}")
# 检查当前帧位置,决定从哪里开始播放 # 检查当前帧位置,决定从哪里开始播放
if self._current_frame_index < start_frame or self._current_frame_index >= end_frame: if self._current_frame_index < start_frame or self._current_frame_index >= end_frame:
...@@ -1895,7 +1829,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1895,7 +1829,6 @@ class DataPreprocessHandler(QtCore.QObject):
# 时间段模式:循环播放选定的时间段 # 时间段模式:循环播放选定的时间段
self._current_frame_index = start_frame self._current_frame_index = start_frame
self._showFrame(start_frame) self._showFrame(start_frame)
print(f"[DataPreprocessHandler] 循环播放时间段: 从帧 {start_frame} 重新开始")
else: else:
# 普通模式:停止播放 # 普通模式:停止播放
if self._play_timer is not None: if self._play_timer is not None:
...@@ -1955,8 +1888,6 @@ class DataPreprocessHandler(QtCore.QObject): ...@@ -1955,8 +1888,6 @@ class DataPreprocessHandler(QtCore.QObject):
duration_frames = end_frame - start_frame + 1 duration_frames = end_frame - start_frame + 1
duration_time = self._formatTimeFromFrame(duration_frames) duration_time = self._formatTimeFromFrame(duration_frames)
print(f"[DataPreprocessHandler] 时间段变化: {start_time} - {end_time} (共{duration_frames}帧, 时长{duration_time})")
# 不自动跳转,让用户自己控制播放位置(白点不跟随绿点移动) # 不自动跳转,让用户自己控制播放位置(白点不跟随绿点移动)
# if self._current_frame_index < start_frame or self._current_frame_index > end_frame: # if self._current_frame_index < start_frame or self._current_frame_index > end_frame:
# self._current_frame_index = start_frame # self._current_frame_index = start_frame
......
...@@ -53,7 +53,6 @@ def backup_file(filepath): ...@@ -53,7 +53,6 @@ def backup_file(filepath):
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_path = f"{filepath}.backup_{timestamp}" backup_path = f"{filepath}.backup_{timestamp}"
shutil.copy2(filepath, backup_path) shutil.copy2(filepath, backup_path)
print(f"✅ 已备份原文件到: {backup_path}")
return backup_path return backup_path
def find_method_range(lines, method_name): def find_method_range(lines, method_name):
...@@ -92,16 +91,12 @@ def find_method_range(lines, method_name): ...@@ -92,16 +91,12 @@ def find_method_range(lines, method_name):
def cleanup_test_code(filepath): def cleanup_test_code(filepath):
"""清理测试代码""" """清理测试代码"""
print("\n" + "=" * 60)
print("开始清理测试代码")
print("=" * 60)
# 读取文件 # 读取文件
with open(filepath, 'r', encoding='utf-8') as f: with open(filepath, 'r', encoding='utf-8') as f:
lines = f.readlines() lines = f.readlines()
original_line_count = len(lines) original_line_count = len(lines)
print(f"\n原文件行数: {original_line_count}")
# 记录删除的方法 # 记录删除的方法
deleted_methods = [] deleted_methods = []
...@@ -113,9 +108,6 @@ def cleanup_test_code(filepath): ...@@ -113,9 +108,6 @@ def cleanup_test_code(filepath):
if result: if result:
start, end = result start, end = result
method_lines = end - start method_lines = end - start
print(f"\n找到方法: {method_name}")
print(f" 位置: 第 {start + 1} 行到第 {end} 行")
print(f" 行数: {method_lines} 行")
# 删除方法 # 删除方法
del lines[start:end] del lines[start:end]
...@@ -126,9 +118,6 @@ def cleanup_test_code(filepath): ...@@ -126,9 +118,6 @@ def cleanup_test_code(filepath):
'lines': method_lines 'lines': method_lines
}) })
deleted_lines += method_lines deleted_lines += method_lines
print(f" ✅ 已删除")
else:
print(f"\n⚠️ 未找到方法: {method_name}")
# 写回文件 # 写回文件
with open(filepath, 'w', encoding='utf-8') as f: with open(filepath, 'w', encoding='utf-8') as f:
...@@ -136,20 +125,6 @@ def cleanup_test_code(filepath): ...@@ -136,20 +125,6 @@ def cleanup_test_code(filepath):
new_line_count = len(lines) 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') report_path = str(filepath).replace('.py', '_cleanup_report.txt')
with open(report_path, 'w', encoding='utf-8') as f: with open(report_path, 'w', encoding='utf-8') as f:
...@@ -167,25 +142,18 @@ def cleanup_test_code(filepath): ...@@ -167,25 +142,18 @@ def cleanup_test_code(filepath):
f.write(f" - {method['name']}: {method['lines']} 行 (第 {method['start']}-{method['end']} 行)\n") f.write(f" - {method['name']}: {method['lines']} 行 (第 {method['start']}-{method['end']} 行)\n")
f.write("\n" + "=" * 60 + "\n") f.write("\n" + "=" * 60 + "\n")
print(f"\n✅ 清理报告已保存到: {report_path}")
return deleted_methods return deleted_methods
def verify_file(filepath): def verify_file(filepath):
"""验证文件语法""" """验证文件语法"""
print("\n" + "=" * 60)
print("验证文件语法")
print("=" * 60)
try: try:
with open(filepath, 'r', encoding='utf-8') as f: with open(filepath, 'r', encoding='utf-8') as f:
code = f.read() code = f.read()
compile(code, filepath, 'exec') compile(code, filepath, 'exec')
print("✅ 文件语法正确")
return True return True
except SyntaxError as e: except SyntaxError as e:
print(f"❌ 语法错误: {e}")
return False return False
def main(): def main():
...@@ -194,25 +162,11 @@ def main(): ...@@ -194,25 +162,11 @@ def main():
filepath = script_dir / 'model_training_handler.py' filepath = script_dir / 'model_training_handler.py'
if not filepath.exists(): if not filepath.exists():
print(f"❌ 文件不存在: {filepath}")
return False 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): ") response = input("\n是否继续?(y/n): ")
if response.lower() != 'y': if response.lower() != 'y':
print("已取消")
return False return False
# 备份 # 备份
...@@ -224,26 +178,13 @@ def main(): ...@@ -224,26 +178,13 @@ def main():
# 验证 # 验证
if verify_file(filepath): 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 return True
else: else:
print("\n❌ 清理后文件有语法错误,正在恢复...")
shutil.copy2(backup_path, filepath) shutil.copy2(backup_path, filepath)
print(f"✅ 已从备份恢复")
return False return False
except Exception as e: except Exception as e:
print(f"\n❌ 清理失败: {e}")
import traceback
traceback.print_exc()
print("\n正在从备份恢复...")
shutil.copy2(backup_path, filepath) shutil.copy2(backup_path, filepath)
print(f"✅ 已从备份恢复")
return False return False
if __name__ == "__main__": if __name__ == "__main__":
......
...@@ -79,17 +79,11 @@ class ModelPageHandler: ...@@ -79,17 +79,11 @@ class ModelPageHandler:
self._model_operations = ModelOperations(handler=handlers['model_set_handler']) self._model_operations = ModelOperations(handler=handlers['model_set_handler'])
def create_model_page(self): def create_model_page(self):
""" """创建模型页面(已弃用,保留以兼容旧代码)"""
创建模型管理页面(已弃用) pass
注意:此方法已不再使用,推荐直接使用 app.py 中的 _createModelPage() 方法。
保留此方法仅用于向后兼容。
Returns:
QtWidgets.QWidget: 模型页面
"""
print("[WARNING] create_model_page() 方法已弃用,请使用 app.py 中的 _createModelPage()")
def _createModelPage(self):
"""创建模型页面的实际实现"""
# 导入页面组件(从 widgets.modelpage) # 导入页面组件(从 widgets.modelpage)
try: try:
from ...widgets.modelpage.modelset_page import ModelSetPage from ...widgets.modelpage.modelset_page import ModelSetPage
...@@ -99,8 +93,7 @@ class ModelPageHandler: ...@@ -99,8 +93,7 @@ class ModelPageHandler:
from widgets.modelpage.modelset_page import ModelSetPage from widgets.modelpage.modelset_page import ModelSetPage
from widgets.modelpage.training_page import TrainingPage from widgets.modelpage.training_page import TrainingPage
except ImportError as e: except ImportError as e:
print(f"[ERROR] 无法导入必要的页面组件: {e}") return None
return QtWidgets.QWidget()
# 导入训练处理器 # 导入训练处理器
try: try:
...@@ -112,7 +105,6 @@ class ModelPageHandler: ...@@ -112,7 +105,6 @@ class ModelPageHandler:
from handlers.modelpage.model_training_handler import ModelTrainingHandler from handlers.modelpage.model_training_handler import ModelTrainingHandler
except ImportError: except ImportError:
ModelTrainingHandler = None ModelTrainingHandler = None
print("[WARNING] 无法导入ModelTrainingHandler,训练功能将不可用")
# 创建主页面容器 # 创建主页面容器
page = QtWidgets.QWidget() page = QtWidgets.QWidget()
...@@ -130,8 +122,7 @@ class ModelPageHandler: ...@@ -130,8 +122,7 @@ class ModelPageHandler:
# 创建训练处理器 # 创建训练处理器
if ModelTrainingHandler: if ModelTrainingHandler:
self._parent.training_handler = ModelTrainingHandler() self._parent.training_handler = ModelTrainingHandler()
self._parent.training_handler._set_main_window(self._parent) self._parent.training_handler.connectSignals()
print("[OK] 训练处理器初始化成功")
else: else:
self._parent.training_handler = None self._parent.training_handler = None
...@@ -139,10 +130,6 @@ class ModelPageHandler: ...@@ -139,10 +130,6 @@ class ModelPageHandler:
self._parent.trainingPage = TrainingPage(parent=self._parent) self._parent.trainingPage = TrainingPage(parent=self._parent)
self._parent.modelStackWidget.addWidget(self._parent.trainingPage) 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) self._parent.modelStackWidget.setCurrentIndex(0)
...@@ -167,12 +154,7 @@ class ModelPageHandler: ...@@ -167,12 +154,7 @@ class ModelPageHandler:
self._handlers['model_signal_handler'].setupModelPageConnections() self._handlers['model_signal_handler'].setupModelPageConnections()
def add_test_models_to_list(self): def add_test_models_to_list(self):
""" """添加测试模型到列表(已弃用)"""
添加测试模型到模型列表(已弃用)
注意:此方法已不再使用,模型应通过"模型集管理"页面手动添加。
"""
print("[WARNING] add_test_models_to_list() 方法已弃用")
pass pass
# ==================== 信号处理方法 ==================== # ==================== 信号处理方法 ====================
...@@ -189,21 +171,11 @@ class ModelPageHandler: ...@@ -189,21 +171,11 @@ class ModelPageHandler:
QtWidgets.QMessageBox.warning(self._parent, "错误", f"运行模型测试失败: {e}") QtWidgets.QMessageBox.warning(self._parent, "错误", f"运行模型测试失败: {e}")
def on_browse_test_file(self): def on_browse_test_file(self):
""" """浏览测试文件(已弃用)"""
浏览测试文件(已弃用)
注意:模型测试功能已移除,此方法不再使用。
"""
print("[WARNING] on_browse_test_file() 方法已弃用")
pass pass
def on_browse_save_liquid_data_path(self): def on_browse_save_liquid_data_path(self):
""" """浏览保存路径(已弃用)"""
浏览保存路径(已弃用)
注意:此方法已不再使用。
"""
print("[WARNING] on_browse_save_liquid_data_path() 方法已弃用")
pass pass
def on_add_model_set(self): def on_add_model_set(self):
......
...@@ -417,44 +417,22 @@ class ModelSetHandler: ...@@ -417,44 +417,22 @@ class ModelSetHandler:
def loadModelsFromConfig(self): def loadModelsFromConfig(self):
"""从配置文件和模型目录加载所有模型""" """从配置文件和模型目录加载所有模型"""
try: try:
print("🚀 [模型加载] 开始加载模型列表...")
# 1. 加载配置文件
print(" [模型加载] 步骤1: 加载配置文件")
config = self._loadConfigFile() config = self._loadConfigFile()
if not config: if not config:
print("❌ [模型加载] 配置文件加载失败,停止加载")
return return
print("✅ [模型加载] 配置文件加载成功")
# 2. 跳过配置文件中的通道模型(只显示train_model目录下的模型)
print(" [模型加载] 步骤2: 跳过配置文件中的通道模型")
channel_models = [] # 不加载通道模型 channel_models = [] # 不加载通道模型
print(f"✅ [模型加载] 跳过通道模型,专注于train_model目录")
# 3. 扫描模型目录
print(" [模型加载] 步骤3: 扫描模型目录")
scanned_models = self._scanModelDirectory() scanned_models = self._scanModelDirectory()
print(f"✅ [模型加载] 从目录扫描到 {len(scanned_models)} 个模型")
# 4. 直接使用扫描到的模型(不合并通道模型)
print(" [模型加载] 步骤4: 使用扫描到的模型")
all_models = scanned_models # 直接使用扫描模型 all_models = scanned_models # 直接使用扫描模型
# 设置第一个模型为默认模型(如果有模型的话)
if len(all_models) > 0: if len(all_models) > 0:
all_models[0]['is_default'] = True 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) self._updateModelList(all_models)
print("✅ [模型加载] 模型列表加载完成")
except Exception as e: except Exception as e:
print(f"❌ [模型加载] 加载过程中发生异常: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -543,33 +521,18 @@ class ModelSetHandler: ...@@ -543,33 +521,18 @@ class ModelSetHandler:
current_dir = Path(__file__).parent.parent.parent current_dir = Path(__file__).parent.parent.parent
model_dir = current_dir / "database" / "model" / "train_model" 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(): if not model_dir.exists():
print("❌ [模型扫描] 模型目录不存在,返回空列表")
return models return models
# 列出目录中的所有项目
all_items = list(model_dir.iterdir()) 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 '') 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: for subdir in sorted_subdirs:
if subdir.is_dir(): if subdir.is_dir():
print(f" [模型扫描] 正在扫描子目录: {subdir.name} ({subdir})")
# 列出子目录中的所有文件
subdir_files = list(subdir.iterdir()) subdir_files = list(subdir.iterdir())
print(f" [模型扫描] 子目录 {subdir.name} 中的文件: {[f.name for f in subdir_files]}")
# 查找 .dat 文件(优先)
dat_files = list(subdir.glob("*.dat")) dat_files = list(subdir.glob("*.dat"))
print(f" [模型扫描] 找到的 .dat 文件: {[f.name for f in dat_files]}")
for model_file in sorted(dat_files): for model_file in sorted(dat_files):
model_info = { model_info = {
...@@ -580,11 +543,8 @@ class ModelSetHandler: ...@@ -580,11 +543,8 @@ class ModelSetHandler:
'format': 'dat' 'format': 'dat'
} }
models.append(model_info) models.append(model_info)
print(f"✅ [模型扫描] 添加 .dat 模型: {model_info}")
# 然后查找 .pt 文件
pt_files = list(subdir.glob("*.pt")) pt_files = list(subdir.glob("*.pt"))
print(f" [模型扫描] 找到的 .pt 文件: {[f.name for f in pt_files]}")
for model_file in sorted(pt_files): for model_file in sorted(pt_files):
model_info = { model_info = {
...@@ -595,16 +555,11 @@ class ModelSetHandler: ...@@ -595,16 +555,11 @@ class ModelSetHandler:
'format': 'pt' 'format': 'pt'
} }
models.append(model_info) models.append(model_info)
print(f"✅ [模型扫描] 添加 .pt 模型: {model_info}")
else:
print(f"⚠️ [模型扫描] 跳过非目录项: {subdir.name}")
except Exception as e: except Exception as e:
print(f"❌ [模型扫描] 扫描过程中发生异常: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
print(f" [模型扫描] 扫描完成,共找到 {len(models)} 个模型")
return models return models
def _mergeModelInfo(self, channel_models, scanned_models): def _mergeModelInfo(self, channel_models, scanned_models):
...@@ -612,19 +567,12 @@ class ModelSetHandler: ...@@ -612,19 +567,12 @@ class ModelSetHandler:
all_models = [] all_models = []
seen_paths = set() seen_paths = set()
print(f" [模型合并] 开始合并模型信息")
print(f" [模型合并] 通道模型数量: {len(channel_models)}")
print(f" [模型合并] 扫描模型数量: {len(scanned_models)}")
# 优先添加配置文件中的通道模型 # 优先添加配置文件中的通道模型
for model in channel_models: for model in channel_models:
path = model['path'] path = model['path']
if path not in seen_paths: if path not in seen_paths:
all_models.append(model) all_models.append(model)
seen_paths.add(path) seen_paths.add(path)
print(f"✅ [模型合并] 添加通道模型: {model['name']} ({path})")
else:
print(f"⚠️ [模型合并] 跳过重复通道模型: {model['name']} ({path})")
# 再添加扫描到的模型(跳过已存在的) # 再添加扫描到的模型(跳过已存在的)
for model in scanned_models: for model in scanned_models:
...@@ -632,37 +580,26 @@ class ModelSetHandler: ...@@ -632,37 +580,26 @@ class ModelSetHandler:
if path not in seen_paths: if path not in seen_paths:
all_models.append(model) all_models.append(model)
seen_paths.add(path) 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) has_default = any(model.get('is_default', False) for model in all_models)
if not has_default and len(all_models) > 0: if not has_default and len(all_models) > 0:
all_models[0]['is_default'] = True all_models[0]['is_default'] = True
print(f"✅ [模型合并] 设置默认模型: {all_models[0]['name']}")
print(f" [模型合并] 合并完成,最终模型数量: {len(all_models)}")
return all_models return all_models
def _updateModelList(self, all_models): def _updateModelList(self, all_models):
"""更新UI中的模型列表""" """更新UI中的模型列表"""
try: try:
print(f" [UI更新] 开始更新模型列表,模型数量: {len(all_models)}")
if not hasattr(self, 'modelSetPage') or not self.modelSetPage: if not hasattr(self, 'modelSetPage') or not self.modelSetPage:
print("❌ [UI更新] modelSetPage 不存在,无法更新UI")
return return
print(f"✅ [UI更新] 找到 modelSetPage,准备更新")
# 清空现有模型参数 # 清空现有模型参数
self.modelSetPage._model_params = {} self.modelSetPage._model_params = {}
# 添加所有模型到UI # 添加所有模型到UI
for i, model in enumerate(all_models): for i, model in enumerate(all_models):
model_name = model['name'] model_name = model['name']
print(f" [UI更新] 处理模型 {i+1}/{len(all_models)}: {model_name}")
# 创建模型参数 # 创建模型参数
model_params = self._createModelParams(model, {}) model_params = self._createModelParams(model, {})
...@@ -671,19 +608,11 @@ class ModelSetHandler: ...@@ -671,19 +608,11 @@ class ModelSetHandler:
# 设置默认模型 # 设置默认模型
if model.get('is_default', False): if model.get('is_default', False):
self.modelSetPage._current_default_model = model_name self.modelSetPage._current_default_model = model_name
print(f"✅ [UI更新] 设置默认模型: {model_name}")
# 刷新UI显示
if hasattr(self.modelSetPage, 'refreshModelList'): if hasattr(self.modelSetPage, 'refreshModelList'):
print(f" [UI更新] 调用 refreshModelList 刷新UI")
self.modelSetPage.refreshModelList() self.modelSetPage.refreshModelList()
else:
print(f"⚠️ [UI更新] modelSetPage 没有 refreshModelList 方法")
print(f"✅ [UI更新] 模型列表更新完成")
except Exception as e: except Exception as e:
print(f"❌ [UI更新] 更新UI时发生异常: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
......
...@@ -79,13 +79,10 @@ class ModelSignalHandler: ...@@ -79,13 +79,10 @@ class ModelSignalHandler:
# self.modelSetPage.setDefaultRequested.connect( # self.modelSetPage.setDefaultRequested.connect(
# self.model_set_handler.setAsDefaultModel # self.model_set_handler.setAsDefaultModel
# ) # )
if hasattr(self.modelSetPage, 'modelSetClicked'):
print("[OK] ModelSetPage 业务逻辑信号已连接到 model_set_handler") self.modelSetPage.modelSetClicked.connect(self._onModelSetPageModelSelected)
else:
print("[警告] model_set_handler 未初始化,业务逻辑信号未连接")
except Exception as e: except Exception as e:
print(f"[ModelSignalHandler] 建立连接时出错: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -96,7 +93,6 @@ class ModelSignalHandler: ...@@ -96,7 +93,6 @@ class ModelSignalHandler:
Args: Args:
model_name: 选中的模型名称 model_name: 选中的模型名称
""" """
print(f" [ModelSignalHandler] ModelSetPage 选中模型: {model_name}")
# 这里可以添加额外的处理逻辑,比如更新状态栏 # 这里可以添加额外的处理逻辑,比如更新状态栏
if hasattr(self, 'statusBar'): if hasattr(self, 'statusBar'):
self.statusBar().showMessage(f"当前选中模型: {model_name}") self.statusBar().showMessage(f"当前选中模型: {model_name}")
...@@ -108,7 +104,7 @@ class ModelSignalHandler: ...@@ -108,7 +104,7 @@ class ModelSignalHandler:
Args: Args:
model_name: 新添加的模型名称 model_name: 新添加的模型名称
""" """
print(f" [ModelSignalHandler] 新模型已添加: {model_name}") pass
def _onModelDeleted(self, model_name): def _onModelDeleted(self, model_name):
""" """
...@@ -117,6 +113,4 @@ class ModelSignalHandler: ...@@ -117,6 +113,4 @@ class ModelSignalHandler:
Args: Args:
model_name: 删除的模型名称 model_name: 删除的模型名称
""" """
print(f" [ModelSignalHandler] 模型已删除: {model_name}") pass
...@@ -95,11 +95,6 @@ class ModelTestThread(QThread): ...@@ -95,11 +95,6 @@ class ModelTestThread(QThread):
is_video = self.test_params['is_video'] is_video = self.test_params['is_video']
handler = self.test_params['handler'] 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: if is_video:
# 视频文件检测 # 视频文件检测
self.progress_updated.emit(20, "正在加载视频文件...") self.progress_updated.emit(20, "正在加载视频文件...")
...@@ -113,8 +108,6 @@ class ModelTestThread(QThread): ...@@ -113,8 +108,6 @@ class ModelTestThread(QThread):
self.error_occurred.emit("文件读取失败", f"无法读取测试文件: {test_file_path}") self.error_occurred.emit("文件读取失败", f"无法读取测试文件: {test_file_path}")
return return
print(f"[测试线程] 测试帧加载成功,尺寸: {test_frame.shape}")
self.progress_updated.emit(30, "正在执行液位检测...") self.progress_updated.emit(30, "正在执行液位检测...")
self._performImageDetection(handler, model_path, test_frame, annotation_file) self._performImageDetection(handler, model_path, test_frame, annotation_file)
...@@ -122,7 +115,6 @@ class ModelTestThread(QThread): ...@@ -122,7 +115,6 @@ class ModelTestThread(QThread):
self.test_finished.emit(True, "测试完成") self.test_finished.emit(True, "测试完成")
except Exception as e: except Exception as e:
print(f"[测试线程] 测试失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
self.error_occurred.emit(type(e).__name__, str(e)) self.error_occurred.emit(type(e).__name__, str(e))
...@@ -132,21 +124,17 @@ class ModelTestThread(QThread): ...@@ -132,21 +124,17 @@ class ModelTestThread(QThread):
try: try:
# 导入检测引擎 # 导入检测引擎
self.progress_updated.emit(40, "正在导入检测引擎...") self.progress_updated.emit(40, "正在导入检测引擎...")
print(f"[测试线程] 正在导入检测引擎...")
try: try:
from handlers.videopage.detection import LiquidDetectionEngine from handlers.videopage.detection import LiquidDetectionEngine
print(f"[测试线程] 检测引擎导入成功")
except ImportError: except ImportError:
try: try:
from ...handlers.videopage.detection import LiquidDetectionEngine from ...handlers.videopage.detection import LiquidDetectionEngine
print(f"[测试线程] 检测引擎导入成功(相对导入)")
except ImportError as e: except ImportError as e:
raise ImportError(f"无法导入LiquidDetectionEngine: {e}") raise ImportError(f"无法导入LiquidDetectionEngine: {e}")
# 读取标注数据 # 读取标注数据
self.progress_updated.emit(45, "正在读取标注数据...") self.progress_updated.emit(45, "正在读取标注数据...")
print(f"[测试线程] 开始读取标注文件: {annotation_file}")
with open(annotation_file, 'r', encoding='utf-8') as f: with open(annotation_file, 'r', encoding='utf-8') as f:
try: try:
...@@ -158,52 +146,38 @@ class ModelTestThread(QThread): ...@@ -158,52 +146,38 @@ class ModelTestThread(QThread):
else: else:
raise raise
print(f"[测试线程] 标注数据加载成功")
# 创建检测引擎
self.progress_updated.emit(50, "正在创建检测引擎...") self.progress_updated.emit(50, "正在创建检测引擎...")
print(f"[测试线程] 正在创建检测引擎...")
detection_engine = LiquidDetectionEngine(model_path=model_path) detection_engine = LiquidDetectionEngine(model_path=model_path)
self.progress_updated.emit(60, "正在加载模型权重...") self.progress_updated.emit(60, "正在加载模型权重...")
print(f"[测试线程] 正在加载模型权重...")
if not detection_engine.load_model(model_path): if not detection_engine.load_model(model_path):
raise RuntimeError(f"模型加载失败: {model_path}") raise RuntimeError(f"模型加载失败: {model_path}")
print(f"[测试线程] 模型权重加载成功")
# 配置标注数据 # 配置标注数据
self.progress_updated.emit(70, "正在配置检测参数...") self.progress_updated.emit(70, "正在配置检测参数...")
detection_engine.set_annotation_data(annotation_data) detection_engine.set_annotation_data(annotation_data)
# 执行检测 # 执行检测
self.progress_updated.emit(80, "正在执行液位检测...") self.progress_updated.emit(80, "正在执行液位检测...")
print(f"[测试线程] 开始执行液位检测...")
detection_result = detection_engine.detect_liquid_level(test_frame) detection_result = detection_engine.detect_liquid_level(test_frame)
if detection_result is None: if detection_result is None:
raise RuntimeError("检测结果为空") raise RuntimeError("检测结果为空")
print(f"[测试线程] 液位检测完成")
self._detection_result = detection_result self._detection_result = detection_result
# 保存图片测试结果
self.progress_updated.emit(90, "正在保存测试结果...") self.progress_updated.emit(90, "正在保存测试结果...")
print(f"[测试线程] 保存图片测试结果...")
self._saveImageTestResults(model_path, test_frame, detection_result, annotation_file) self._saveImageTestResults(model_path, test_frame, detection_result, annotation_file)
except Exception as e: except Exception as e:
print(f"[测试线程] 图片检测失败: {e}")
raise raise
def _performVideoDetection(self, handler, model_path, video_path, annotation_file): def _performVideoDetection(self, handler, model_path, video_path, annotation_file):
"""执行视频检测""" """执行视频检测"""
try: try:
print(f"[测试线程] 开始视频逐帧检测...")
# 视频检测需要在主线程中执行(涉及UI更新) # 视频检测需要在主线程中执行(涉及UI更新)
# 所以这里只是标记,实际检测由主线程的原有方法处理 # 所以这里只是标记,实际检测由主线程的原有方法处理
# 发送进度信号 # 发送进度信号
...@@ -211,16 +185,14 @@ class ModelTestThread(QThread): ...@@ -211,16 +185,14 @@ class ModelTestThread(QThread):
# 注意:视频检测由于涉及实时播放器等UI组件 # 注意:视频检测由于涉及实时播放器等UI组件
# 暂时保持在主线程执行,这里只做标记 # 暂时保持在主线程执行,这里只做标记
print(f"[测试线程] 视频检测将在主线程中执行") pass
except Exception as e: except Exception as e:
print(f"[测试线程] 视频检测失败: {e}")
raise raise
def stop(self): def stop(self):
"""停止线程""" """停止线程"""
self.is_running = False self.is_running = False
print(f"[测试线程] 收到停止信号")
def get_detection_result(self): def get_detection_result(self):
"""获取检测结果""" """获取检测结果"""
...@@ -287,14 +259,8 @@ class ModelTestHandler: ...@@ -287,14 +259,8 @@ class ModelTestHandler:
def _handleStopTest(self): def _handleStopTest(self):
"""停止测试并释放资源""" """停止测试并释放资源"""
print("\n" + "="*60)
print("[模型测试] 用户请求停止测试")
print("="*60)
try: try:
# 设置停止标志
self._detection_stopped = True self._detection_stopped = True
print("[模型测试] 已设置停止标志")
# 恢复按钮状态 # 恢复按钮状态
self.training_panel.setTestButtonState(False) self.training_panel.setTestButtonState(False)
...@@ -310,21 +276,14 @@ class ModelTestHandler: ...@@ -310,21 +276,14 @@ class ModelTestHandler:
""" """
self.training_panel.display_panel.setHtml(stop_html) self.training_panel.display_panel.setHtml(stop_html)
print("[模型测试] 测试已停止,资源已释放")
except Exception as e: except Exception as e:
print(f"[模型测试] 停止测试时出错: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
def _handleStartTestExecution(self): def _handleStartTestExecution(self):
"""执行开始测试操作 - 液位检测测试功能""" """执行开始测试操作 - 液位检测测试功能"""
try: try:
print("\n" + "="*60) # 切换按钮状态为“停止测试”
print("[模型测试] 开始模型测试流程")
print("="*60)
# 切换按钮状态为"停止测试"
self.training_panel.setTestButtonState(True) self.training_panel.setTestButtonState(True)
# 获取选择的测试模型和测试文件 # 获取选择的测试模型和测试文件
...@@ -334,11 +293,6 @@ class ModelTestHandler: ...@@ -334,11 +293,6 @@ class ModelTestHandler:
test_file_path_raw = self.training_panel.test_file_input.currentData() or "" test_file_path_raw = self.training_panel.test_file_input.currentData() or ""
test_file_display = self.training_panel.test_file_input.currentText() 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() project_root = get_project_root()
...@@ -346,7 +300,7 @@ class ModelTestHandler: ...@@ -346,7 +300,7 @@ class ModelTestHandler:
if test_model_path_raw and not os.path.isabs(test_model_path_raw): 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) test_model_path = os.path.join(project_root, test_model_path_raw)
print(f"[模型测试] 相对路径转换: {test_model_path_raw} -> {test_model_path}") pass
else: else:
test_model_path = test_model_path_raw test_model_path = test_model_path_raw
......
...@@ -134,7 +134,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -134,7 +134,6 @@ class ModelTrainingHandler(ModelTestHandler):
self.file_converter = PtToDatConverter() self.file_converter = PtToDatConverter()
except Exception as e: except Exception as e:
self.file_converter = None self.file_converter = None
print(f"[ERROR] 初始化模型文件转换器失败: {e}")
def _set_main_window(self, main_window): def _set_main_window(self, main_window):
"""设置主窗口引用""" """设置主窗口引用"""
...@@ -148,7 +147,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -148,7 +147,6 @@ class ModelTrainingHandler(ModelTestHandler):
self.config_file_path = os.path.join(config_dir, "default_config.json") self.config_file_path = os.path.join(config_dir, "default_config.json")
if not os.path.exists(self.config_file_path): if not os.path.exists(self.config_file_path):
print(f"[ERROR] 训练配置文件不存在: {self.config_file_path}")
self.train_config = None self.train_config = None
return return
...@@ -156,7 +154,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -156,7 +154,6 @@ class ModelTrainingHandler(ModelTestHandler):
self.train_config = json.load(f) self.train_config = json.load(f)
except Exception as e: except Exception as e:
print(f"[ERROR] 加载训练配置失败: {e}")
self.train_config = None self.train_config = None
def _onStartTraining(self, training_params): def _onStartTraining(self, training_params):
...@@ -248,7 +245,7 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -248,7 +245,7 @@ class ModelTrainingHandler(ModelTestHandler):
if os.path.exists(model_icon_path): if os.path.exists(model_icon_path):
msg_box.setWindowIcon(QtGui.QIcon(model_icon_path)) msg_box.setWindowIcon(QtGui.QIcon(model_icon_path))
except Exception as e: except Exception as e:
print(f"[确认对话框] 设置图标失败: {e}") pass
msg_box.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) msg_box.setStandardButtons(QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
msg_box.setDefaultButton(QtWidgets.QMessageBox.No) msg_box.setDefaultButton(QtWidgets.QMessageBox.No)
...@@ -482,7 +479,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -482,7 +479,6 @@ class ModelTrainingHandler(ModelTestHandler):
except Exception as refresh_error: except Exception as refresh_error:
pass pass
# 同步更新模型测试页面
try: try:
self._refreshModelTestPage() self._refreshModelTestPage()
except Exception as test_refresh_error: except Exception as test_refresh_error:
...@@ -542,7 +538,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -542,7 +538,6 @@ class ModelTrainingHandler(ModelTestHandler):
# 刷新模型集管理页面 # 刷新模型集管理页面
self._refreshModelSetPage() self._refreshModelSetPage()
# 同步更新模型测试页面
self._refreshModelTestPage() self._refreshModelTestPage()
# 获取 last.dat 路径(转换后应该是 dat 文件) # 获取 last.dat 路径(转换后应该是 dat 文件)
...@@ -657,11 +652,9 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -657,11 +652,9 @@ class ModelTrainingHandler(ModelTestHandler):
"""立即转换PT文件为DAT格式并删除PT文件""" """立即转换PT文件为DAT格式并删除PT文件"""
try: try:
if not self.file_converter: if not self.file_converter:
print("[ERROR] 未初始化文件转换器,无法执行pt到dat的转换")
return [] return []
if not os.path.exists(weights_dir): if not os.path.exists(weights_dir):
print(f"[ERROR] 权重目录不存在: {weights_dir}")
return [] return []
converted_files = [] converted_files = []
...@@ -673,11 +666,8 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -673,11 +666,8 @@ class ModelTrainingHandler(ModelTestHandler):
pt_files_found.append(file) pt_files_found.append(file)
if not pt_files_found: if not pt_files_found:
print("[INFO] 未找到需要转换的PT文件")
return [] return []
print(f"[INFO] 找到 {len(pt_files_found)} 个PT文件,开始转换...")
# 获取模型名称用于文件重命名 # 获取模型名称用于文件重命名
model_name = getattr(self, 'current_exp_name', 'trained_model') model_name = getattr(self, 'current_exp_name', 'trained_model')
...@@ -699,7 +689,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -699,7 +689,6 @@ class ModelTrainingHandler(ModelTestHandler):
dat_path = os.path.join(weights_dir, dat_filename) dat_path = os.path.join(weights_dir, dat_filename)
try: try:
print(f"[转换] {file} -> {dat_filename}")
converted_path = self.file_converter.convert_file(pt_path, dat_path) converted_path = self.file_converter.convert_file(pt_path, dat_path)
if converted_path and os.path.exists(converted_path): if converted_path and os.path.exists(converted_path):
...@@ -707,16 +696,11 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -707,16 +696,11 @@ class ModelTrainingHandler(ModelTestHandler):
# 立即删除PT文件 # 立即删除PT文件
try: try:
os.remove(pt_path) os.remove(pt_path)
print(f"[清理] 已删除PT文件: {file}")
except OSError as remove_error: except OSError as remove_error:
print(f"[WARNING] 无法删除PT文件 {file}: {remove_error}") pass
else:
print(f"[ERROR] 转换失败: {file}")
except Exception as convert_error: except Exception as convert_error:
print(f"[ERROR] 转换文件失败 {file}: {convert_error}") pass
print(f"[完成] 成功转换 {len(converted_files)} 个文件为DAT格式")
# 强制清理任何残留的PT文件 # 强制清理任何残留的PT文件
self._forceCleanupPtFiles(weights_dir) self._forceCleanupPtFiles(weights_dir)
...@@ -724,7 +708,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -724,7 +708,6 @@ class ModelTrainingHandler(ModelTestHandler):
return converted_files return converted_files
except Exception as e: except Exception as e:
print(f"[ERROR] PT到DAT转换失败: {e}")
return [] return []
def _convertTrainingmission_resultsToDat(self, exp_name, weights_dir=None): def _convertTrainingmission_resultsToDat(self, exp_name, weights_dir=None):
...@@ -782,7 +765,7 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -782,7 +765,7 @@ class ModelTrainingHandler(ModelTestHandler):
self.temp_trained_models.clear() self.temp_trained_models.clear()
except Exception as e: except Exception as e:
print(f"[ERROR] 清理临时文件失败: {e}") pass
def _forceCleanupPtFiles(self, weights_dir): def _forceCleanupPtFiles(self, weights_dir):
"""强制清理指定目录下的所有PT文件""" """强制清理指定目录下的所有PT文件"""
...@@ -796,16 +779,14 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -796,16 +779,14 @@ class ModelTrainingHandler(ModelTestHandler):
pt_files.append(os.path.join(weights_dir, file)) pt_files.append(os.path.join(weights_dir, file))
if pt_files: if pt_files:
print(f"[清理] 发现 {len(pt_files)} 个残留的PT文件,正在删除...")
for pt_file in pt_files: for pt_file in pt_files:
try: try:
os.remove(pt_file) os.remove(pt_file)
print(f"[清理] 已删除: {os.path.basename(pt_file)}")
except OSError as e: except OSError as e:
print(f"[WARNING] 无法删除PT文件 {os.path.basename(pt_file)}: {e}") pass
except Exception as e: except Exception as e:
print(f"[ERROR] 强制清理PT文件失败: {e}") pass
def _saveTrainingLogToWeightsDir(self, exp_name, weights_dir=None): def _saveTrainingLogToWeightsDir(self, exp_name, weights_dir=None):
""" """
...@@ -829,7 +810,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -829,7 +810,6 @@ class ModelTrainingHandler(ModelTestHandler):
weights_dir = os.path.join(train_root, "runs", "train", exp_name, "weights") weights_dir = os.path.join(train_root, "runs", "train", exp_name, "weights")
if not os.path.exists(weights_dir): if not os.path.exists(weights_dir):
print(f"[警告] weights目录不存在: {weights_dir}")
return None return None
# 获取训练日志内容 # 获取训练日志内容
...@@ -838,7 +818,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -838,7 +818,6 @@ class ModelTrainingHandler(ModelTestHandler):
log_content = self.training_panel.log_display.toPlainText() log_content = self.training_panel.log_display.toPlainText()
if not log_content: if not log_content:
print("[警告] 训练日志为空,跳过保存")
return None return None
# 生成日志文件名:training_log_[模型名称].txt # 生成日志文件名:training_log_[模型名称].txt
...@@ -858,11 +837,9 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -858,11 +837,9 @@ class ModelTrainingHandler(ModelTestHandler):
f.write("日志结束\n") f.write("日志结束\n")
f.write("=" * 80 + "\n") f.write("=" * 80 + "\n")
print(f"[保存日志] 训练日志已保存: {log_filepath}")
return log_filepath return log_filepath
except Exception as e: except Exception as e:
print(f"[ERROR] 保存训练日志失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return None return None
...@@ -968,7 +945,7 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -968,7 +945,7 @@ class ModelTrainingHandler(ModelTestHandler):
training_panel.exp_name_edit.setText('training_experiment') training_panel.exp_name_edit.setText('training_experiment')
except Exception as e: except Exception as e:
print(f"[ERROR] 初始化训练面板默认值失败: {e}") pass
def _handleStartTraining(self): def _handleStartTraining(self):
"""处理开始训练按钮点击""" """处理开始训练按钮点击"""
...@@ -1308,7 +1285,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1308,7 +1285,6 @@ class ModelTrainingHandler(ModelTestHandler):
return training_params return training_params
except Exception as e: except Exception as e:
print(f"[ERROR] 路径验证失败: {e}")
return training_params return training_params
def _prepareBaseModelForTraining(self, base_model_path): def _prepareBaseModelForTraining(self, base_model_path):
...@@ -1316,7 +1292,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1316,7 +1292,6 @@ class ModelTrainingHandler(ModelTestHandler):
try: try:
if base_model_path.endswith('.dat'): if base_model_path.endswith('.dat'):
# 如果是.dat文件,需要转换为.pt文件 # 如果是.dat文件,需要转换为.pt文件
print(f"[TRAINING] 检测到.dat文件,开始转换: {base_model_path}")
# 创建临时目录 # 创建临时目录
temp_dir = tempfile.mkdtemp(prefix="liquid_training_") temp_dir = tempfile.mkdtemp(prefix="liquid_training_")
...@@ -1324,15 +1299,12 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1324,15 +1299,12 @@ class ModelTrainingHandler(ModelTestHandler):
# 这里需要实现dat到pt的转换逻辑 # 这里需要实现dat到pt的转换逻辑
# 暂时返回原路径 # 暂时返回原路径
print(f"[TRAINING] 模型转换成功: {temp_model_path}")
return str(temp_model_path) return str(temp_model_path)
else: else:
# 如果是.pt文件,直接使用 # 如果是.pt文件,直接使用
print(f"[TRAINING] 使用.pt文件: {base_model_path}")
return base_model_path return base_model_path
except Exception as e: except Exception as e:
print(f"[TRAINING] 处理基础模型失败: {e}")
return base_model_path return base_model_path
def _validateTrainingDataInThread(self, save_liquid_data_path): def _validateTrainingDataInThread(self, save_liquid_data_path):
...@@ -1531,14 +1503,10 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1531,14 +1503,10 @@ class ModelTrainingHandler(ModelTestHandler):
try: try:
# 通过主窗口访问模型集管理页面 # 通过主窗口访问模型集管理页面
if hasattr(self, 'main_window') and hasattr(self.main_window, 'modelSetPage'): if hasattr(self, 'main_window') and hasattr(self.main_window, 'modelSetPage'):
print("[ModelTrainingHandler] 训练完成,刷新模型集管理页面")
# 调用模型集页面的刷新方法 # 调用模型集页面的刷新方法
self.main_window.modelSetPage.loadModelsFromConfig() self.main_window.modelSetPage.loadModelsFromConfig()
self._appendLog("\n 模型集管理页面已更新\n") self._appendLog("\n 模型集管理页面已更新\n")
else:
print("[ModelTrainingHandler] 无法访问模型集管理页面")
except Exception as e: except Exception as e:
print(f"[ModelTrainingHandler] 刷新模型集页面失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -1577,7 +1545,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1577,7 +1545,6 @@ class ModelTrainingHandler(ModelTestHandler):
return engine return engine
except Exception as e: except Exception as e:
print(f"[错误] 创建标注引擎失败: {e}")
return None return None
def _handleStartAnnotation(self): def _handleStartAnnotation(self):
...@@ -1603,9 +1570,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1603,9 +1570,6 @@ class ModelTrainingHandler(ModelTestHandler):
test_file_path = self.training_panel.test_file_input.currentData() or "" test_file_path = self.training_panel.test_file_input.currentData() or ""
test_file_display = self.training_panel.test_file_input.currentText() test_file_display = self.training_panel.test_file_input.currentText()
print(f"[调试] 显示的测试文件: {test_file_display}")
print(f"[调试] 实际文件路径: {test_file_path}")
if not test_file_path: if not test_file_path:
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self.training_panel, self.training_panel,
...@@ -1613,27 +1577,18 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1613,27 +1577,18 @@ class ModelTrainingHandler(ModelTestHandler):
"请先选择测试文件" "请先选择测试文件"
) )
return return
print(f"[调试] 完整文件路径: {test_file_path}")
# 读取标注帧 # 读取标注帧
annotation_frame = None annotation_frame = None
test_path = Path(test_file_path) test_path = Path(test_file_path)
# 检查文件/文件夹是否存在
print(f"[调试] 路径是否存在: {test_path.exists()}")
print(f"[调试] 是否为文件: {test_path.is_file()}")
print(f"[调试] 是否为文件夹: {test_path.is_dir()}")
# 视频格式 # 视频格式
video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv'] video_extensions = ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv']
image_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp'] image_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
if test_path.is_file(): if test_path.is_file():
print(f"[调试] 文件扩展名: {test_path.suffix.lower()}")
# 检查是否为视频文件 # 检查是否为视频文件
if test_path.suffix.lower() in video_extensions: if test_path.suffix.lower() in video_extensions:
print(f"[调试] 识别为视频文件,开始读取第10帧")
# 读取视频的第10帧 # 读取视频的第10帧
cap = cv2.VideoCapture(str(test_path)) cap = cv2.VideoCapture(str(test_path))
if cap.isOpened(): if cap.isOpened():
...@@ -1641,12 +1596,8 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1641,12 +1596,8 @@ class ModelTrainingHandler(ModelTestHandler):
ret, frame = cap.read() ret, frame = cap.read()
if ret: if ret:
annotation_frame = frame annotation_frame = frame
print(f"[调试] 视频第10帧读取成功,帧大小: {frame.shape}")
else:
print(f"[调试] 视频第10帧读取失败")
cap.release() cap.release()
else: else:
print(f"[调试] 无法打开视频文件")
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self.training_panel, self.training_panel,
"视频打开失败", "视频打开失败",
...@@ -1655,26 +1606,15 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1655,26 +1606,15 @@ class ModelTrainingHandler(ModelTestHandler):
# 检查是否为图片文件 # 检查是否为图片文件
elif test_path.suffix.lower() in image_formats: elif test_path.suffix.lower() in image_formats:
print(f"[调试] 识别为图片文件,开始读取")
# 直接读取图片 # 直接读取图片
try: try:
annotation_frame = cv2.imread(test_file_path) annotation_frame = cv2.imread(test_file_path)
if annotation_frame is not None: if annotation_frame is None:
print(f"[调试] 图片读取成功,图片大小: {annotation_frame.shape}")
else:
print(f"[调试] cv2.imread返回None,可能的原因:")
print(f" - 文件路径包含中文字符")
print(f" - 文件损坏")
print(f" - 文件格式不支持")
print(f" - 文件权限问题")
# 尝试使用不同的方法读取 # 尝试使用不同的方法读取
try: try:
import numpy as np import numpy as np
from PIL import Image from PIL import Image
print(f"[调试] 尝试使用PIL读取图片")
pil_image = Image.open(test_file_path) pil_image = Image.open(test_file_path)
print(f"[调试] PIL读取成功,图片模式: {pil_image.mode}, 大小: {pil_image.size}")
# 转换为OpenCV格式 # 转换为OpenCV格式
if pil_image.mode == 'RGB': if pil_image.mode == 'RGB':
annotation_frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR) annotation_frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
...@@ -1682,40 +1622,25 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1682,40 +1622,25 @@ class ModelTrainingHandler(ModelTestHandler):
annotation_frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGBA2BGR) annotation_frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGBA2BGR)
else: else:
annotation_frame = np.array(pil_image) annotation_frame = np.array(pil_image)
print(f"[调试] PIL转OpenCV成功,最终图片大小: {annotation_frame.shape}")
except Exception as pil_e: except Exception as pil_e:
print(f"[调试] PIL读取也失败: {pil_e}") pass
except Exception as e: except Exception as e:
print(f"[错误] 读取图片失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
else:
print(f"[调试] 文件扩展名 {test_path.suffix.lower()} 不在支持的格式中")
print(f"[调试] 支持的图片格式: {image_formats}")
print(f"[调试] 支持的视频格式: {video_extensions}")
# 文件夹 # 文件夹
elif test_path.is_dir(): elif test_path.is_dir():
print(f"[调试] 识别为文件夹,开始读取第一张图片")
# 读取文件夹内第一张图片 # 读取文件夹内第一张图片
try: try:
files = os.listdir(test_file_path) files = os.listdir(test_file_path)
print(f"[调试] 文件夹内文件列表: {files}")
for file in files: for file in files:
print(f"[调试] 检查文件: {file}")
if any(file.lower().endswith(fmt) for fmt in image_formats): if any(file.lower().endswith(fmt) for fmt in image_formats):
first_image_path = os.path.join(test_file_path, file) first_image_path = os.path.join(test_file_path, file)
print(f"[调试] 找到图片文件: {first_image_path}")
annotation_frame = cv2.imread(first_image_path) annotation_frame = cv2.imread(first_image_path)
if annotation_frame is not None:
print(f"[调试] 文件夹内图片读取成功,图片大小: {annotation_frame.shape}")
else:
print(f"[调试] 文件夹内图片读取失败: {first_image_path}")
break break
else: else:
print(f"[调试] 文件夹内未找到支持的图片格式")
# 给出更友好的提示 # 给出更友好的提示
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self.training_panel, self.training_panel,
...@@ -1732,11 +1657,8 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1732,11 +1657,8 @@ class ModelTrainingHandler(ModelTestHandler):
) )
return return
except Exception as e: except Exception as e:
print(f"[错误] 读取文件夹内图片失败: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
else:
print(f"[调试] 路径既不是文件也不是文件夹")
if annotation_frame is None: if annotation_frame is None:
error_msg = f"无法读取标注帧\n\n调试信息:\n" error_msg = f"无法读取标注帧\n\n调试信息:\n"
...@@ -1789,11 +1711,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1789,11 +1711,6 @@ class ModelTrainingHandler(ModelTestHandler):
# 连接标注完成信号 # 连接标注完成信号
def on_annotation_completed(boxes, bottoms, tops): def on_annotation_completed(boxes, bottoms, tops):
print(f"\n[标注完成] 接收到标注数据:")
print(f" - boxes: {boxes}")
print(f" - bottoms: {bottoms}")
print(f" - tops: {tops}")
# 保存标注结果到临时配置 # 保存标注结果到临时配置
self._saveTestAnnotationResult(boxes, bottoms, tops, self._saveTestAnnotationResult(boxes, bottoms, tops,
self.annotation_widget.area_names, self.annotation_widget.area_names,
...@@ -1805,7 +1722,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1805,7 +1722,6 @@ class ModelTrainingHandler(ModelTestHandler):
# 切换到显示面板 # 切换到显示面板
if hasattr(self.training_panel, 'display_layout'): if hasattr(self.training_panel, 'display_layout'):
self.training_panel.display_layout.setCurrentIndex(1) self.training_panel.display_layout.setCurrentIndex(1)
print(f"[标注预览] 已切换到显示面板")
# 显示预览图 # 显示预览图
self._showAnnotationPreview( self._showAnnotationPreview(
frame, boxes, bottoms, tops, frame, boxes, bottoms, tops,
...@@ -1816,7 +1732,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1816,7 +1732,6 @@ class ModelTrainingHandler(ModelTestHandler):
QtCore.QTimer.singleShot(200, show_preview) QtCore.QTimer.singleShot(200, show_preview)
def on_annotation_cancelled(): def on_annotation_cancelled():
print("[标注取消]")
# 隐藏标注界面,显示提示标签 # 隐藏标注界面,显示提示标签
if hasattr(self.training_panel, 'display_layout'): if hasattr(self.training_panel, 'display_layout'):
self.training_panel.display_layout.setCurrentIndex(0) # 切换到提示标签 self.training_panel.display_layout.setCurrentIndex(0) # 切换到提示标签
...@@ -1830,8 +1745,6 @@ class ModelTrainingHandler(ModelTestHandler): ...@@ -1830,8 +1745,6 @@ class ModelTrainingHandler(ModelTestHandler):
# 标注界面配置为全屏显示(在_initUI中已设置) # 标注界面配置为全屏显示(在_initUI中已设置)
# 这样用户可以进行全屏标注操作 # 这样用户可以进行全屏标注操作
self.annotation_widget.setWindowTitle("模型测试标注 - 全屏模式") self.annotation_widget.setWindowTitle("模型测试标注 - 全屏模式")
# 标注界面已在loadFrame中通过_applyFullScreen进行全屏显示
print("[标注界面] 已显示为全屏标注模式")
else: else:
QtWidgets.QMessageBox.warning( QtWidgets.QMessageBox.warning(
self.training_panel, self.training_panel,
......
...@@ -43,6 +43,10 @@ class DisplayThread: ...@@ -43,6 +43,10 @@ class DisplayThread:
# 保存上次的液位线数据(用于历史数据回退) # 保存上次的液位线数据(用于历史数据回退)
last_liquid_positions = {} last_liquid_positions = {}
# 调试计数器(用于追踪检测启动后的帧数)
debug_frame_count = 0
last_detection_enabled = False
while context.display_flag: while context.display_flag:
try: try:
frame_start_time = time.time() frame_start_time = time.time()
...@@ -59,7 +63,13 @@ class DisplayThread: ...@@ -59,7 +63,13 @@ class DisplayThread:
display_frame = frame 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: if context.detection_enabled:
debug_frame_count += 1
# 从 detection_mission_results 队列读取液位线数据(非阻塞) # 从 detection_mission_results 队列读取液位线数据(非阻塞)
liquid_positions = {} liquid_positions = {}
......
...@@ -63,8 +63,21 @@ class StorageThread: ...@@ -63,8 +63,21 @@ class StorageThread:
if not save_liquid_data_path or save_liquid_data_path == "0000": if not save_liquid_data_path or save_liquid_data_path == "0000":
return 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) 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_files = {}
csv_writers = {} csv_writers = {}
...@@ -81,6 +94,9 @@ class StorageThread: ...@@ -81,6 +94,9 @@ class StorageThread:
# 存储线程不受 save_data_rate 限制,全速消费队列,避免数据丢失 # 存储线程不受 save_data_rate 限制,全速消费队列,避免数据丢失
# save_data_rate 仅用于配置文件记录,实际存储线程会保存所有检测结果 # save_data_rate 仅用于配置文件记录,实际存储线程会保存所有检测结果
# print(f" [存储线程-{channel_id}] 启动成功")
# print(f" - 注意:存储线程全速运行,保存所有检测结果(不受save_data_rate限制)")
data_count = 0 data_count = 0
last_log_time = time.time() last_log_time = time.time()
last_flush_time = time.time() # 记录上次刷新时间 last_flush_time = time.time() # 记录上次刷新时间
...@@ -93,18 +109,44 @@ class StorageThread: ...@@ -93,18 +109,44 @@ class StorageThread:
# 从独立的 storage_data 队列读取,避免与曲线线程竞争 # 从独立的 storage_data 队列读取,避免与曲线线程竞争
detection_mission_result = context.storage_data.get(timeout=0.1) 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: if detection_mission_result and 'liquid_line_positions' in detection_mission_result:
liquid_positions = detection_mission_result['liquid_line_positions'] liquid_positions = detection_mission_result['liquid_line_positions']
current_time = datetime.now().strftime("%Y-%m-%d-%H:%M:%S.%f")[:-3] 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(): for area_idx, position_data in liquid_positions.items():
if area_idx in csv_writers: if area_idx in csv_writers:
# 统一使用mm单位,直接读取height_mm # 统一使用mm单位,直接读取height_mm
height_mm = position_data.get('height_mm', 0.0) 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) height_decimal = round(height_mm, 1)
# print(f" - 最终写入CSV: {height_decimal}mm")
# 写入格式:时间戳 高度值(mm, 保留1位小数) # 写入格式:时间戳 高度值(mm, 保留1位小数)
csv_writers[area_idx].write(f"{current_time} {height_decimal:.1f}\n") csv_writers[area_idx].write(f"{current_time} {height_decimal:.1f}\n")
# 不再立即刷新,改为批量刷新 # 不再立即刷新,改为批量刷新
...@@ -112,20 +154,22 @@ class StorageThread: ...@@ -112,20 +154,22 @@ class StorageThread:
data_count += 1 data_count += 1
# 定时批量刷新到磁盘(每0.5秒一次) # 定时批量刷新到磁盘(每0.5秒一次)
# 定时批量刷新到磁盘(每0.5秒一次)
current_time_check = time.time() current_time_check = time.time()
if current_time_check - last_flush_time >= flush_interval: if current_time_check - last_flush_time >= flush_interval:
for csv_file in csv_writers.values(): for csv_file in csv_writers.values():
csv_file.flush() csv_file.flush()
last_flush_time = current_time_check last_flush_time = current_time_check
# 每5秒打印一次统计
if time.time() - last_log_time > 5.0: if time.time() - last_log_time > 5.0:
# print(f" [存储线程-{channel_id}] 已保存 {data_count} 条数据,队列大小: {context.storage_data.qsize()}")
last_log_time = time.time() last_log_time = time.time()
except queue.Empty: except queue.Empty:
# 队列为空,继续等待 # 队列为空,继续等待
pass pass
except Exception as e: except Exception as e:
# print(f" [存储线程-{channel_id}] CSV写入错误: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
...@@ -136,15 +180,21 @@ class StorageThread: ...@@ -136,15 +180,21 @@ class StorageThread:
# 队列的 get(timeout=0.1) 已经提供了适当的等待 # 队列的 get(timeout=0.1) 已经提供了适当的等待
except Exception as e: except Exception as e:
# print(f" [存储线程-{channel_id}] 错误: {e}")
time.sleep(0.1) time.sleep(0.1)
# 清理资源 # 清理资源
# print(f" [存储线程-{channel_id}] 正在停止...")
# 关闭CSV文件 # 关闭CSV文件
for csv_file in csv_files.values(): for csv_file in csv_files.values():
csv_file.close() csv_file.close()
# TODO: 未来需要释放视频写入器 # TODO: 未来需要释放视频写入器
# TODO: 未来需要释放视频写入器 # if display_writer:
# display_writer.release()
# print(f" [存储线程-{channel_id}] 已停止")
@staticmethod @staticmethod
def _load_channel_config(channel_id: str): def _load_channel_config(channel_id: str):
......
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