Commit 4f8ebab8 by Yuhaibo

1

parent 21a67d1a
...@@ -1240,6 +1240,9 @@ class MainWindow( ...@@ -1240,6 +1240,9 @@ class MainWindow(
# 默认显示第一个子页面(数据采集) # 默认显示第一个子页面(数据采集)
self.datasetStackWidget.setCurrentIndex(0) self.datasetStackWidget.setCurrentIndex(0)
# 连接切换信号,实现切换时刷新文件列表
self.datasetStackWidget.currentChanged.connect(self._onDatasetSubPageChanged)
page_layout.addWidget(self.datasetStackWidget) page_layout.addWidget(self.datasetStackWidget)
return page return page
...@@ -1369,6 +1372,21 @@ class MainWindow( ...@@ -1369,6 +1372,21 @@ class MainWindow(
self.datasetStackWidget.setCurrentIndex(2) # 切换到数据标注子页面 self.datasetStackWidget.setCurrentIndex(2) # 切换到数据标注子页面
self.statusBar().showMessage(self.tr("当前页面: 数据集管理 - 数据标注")) self.statusBar().showMessage(self.tr("当前页面: 数据集管理 - 数据标注"))
def _onDatasetSubPageChanged(self, index):
"""
数据集子页面切换时的回调
Args:
index: 当前子页面索引(0=数据采集, 1=数据预处理, 2=数据标注, 3=模型训练)
"""
# 刷新数据采集和数据预处理页面的左侧文件列表
if index == 0: # 数据采集
if hasattr(self, 'dataCollectionPanel') and self.dataCollectionPanel:
self.dataCollectionPanel.refreshFolders()
elif index == 1: # 数据预处理
if hasattr(self, 'dataPreprocessPanel') and self.dataPreprocessPanel:
self.dataPreprocessPanel.refreshFolders()
def _showModelSetsTab(self): def _showModelSetsTab(self):
"""显示模型集管理选项卡""" """显示模型集管理选项卡"""
self.showModelPage() # 先切换到模型管理页面 self.showModelPage() # 先切换到模型管理页面
......
...@@ -184,12 +184,12 @@ class DataCollectionChannelHandler: ...@@ -184,12 +184,12 @@ class DataCollectionChannelHandler:
if channel_config: if channel_config:
success = self._connectRealChannel(channel_config) success = self._connectRealChannel(channel_config)
if not success: if not success:
error_detail = f"无法连接到配置的通道 {channel_source}\n请检查:\n1. 相机是否已开机并连接到网络\n2. IP地址和端口是否正确" error_detail = f"无法连接到配置的通道 {channel_source}\n请检查:\n 相机是否已开机并连接到网络\n2. IP地址和端口是否正确"
else: else:
# 如果没有配置,尝试直接连接USB通道 # 如果没有配置,尝试直接连接USB通道
success = self._connectUSBChannel(channel_source) success = self._connectUSBChannel(channel_source)
if not success: if not success:
error_detail = f"无法连接到USB通道 {channel_source}\n请检查:\n1. USB相机是否已连接\n2. 相机驱动是否已安装\n3. 相机是否被其他程序占用" error_detail = f"无法连接到USB通道 {channel_source}\n请检查:\nUSB相机是否已连接\n2. 相机驱动是否已安装\n3. 相机是否被其他程序占用"
else: else:
# 如果是RTSP地址,直接连接 # 如果是RTSP地址,直接连接
success = self._connectRTSPChannel(channel_source) success = self._connectRTSPChannel(channel_source)
...@@ -853,6 +853,9 @@ class DataCollectionChannelHandler: ...@@ -853,6 +853,9 @@ class DataCollectionChannelHandler:
self._dc_video_writer.release() self._dc_video_writer.release()
self._dc_video_writer = None self._dc_video_writer = None
# 等待文件系统完成写入(确保文件完全写入磁盘)
time.sleep(0.5)
return True return True
except Exception as e: except Exception as e:
......
...@@ -116,14 +116,21 @@ class SettingsHandler: ...@@ -116,14 +116,21 @@ class SettingsHandler:
def showAbout(self): def showAbout(self):
"""显示关于对话框""" """显示关于对话框"""
QtWidgets.QMessageBox.about( try:
self, from widgets.style_manager import DialogManager
self.tr("关于"), except ImportError:
self.tr( DialogManager = None
"<h2>帕特智能油液位检测</h2>"
"<p>版本: 1.0</p>" message = (
) "<h2>帕特智能油液位检测</h2>"
"<p>版本: 1.0</p>"
) )
if DialogManager:
DialogManager.show_about(self, "关于", message)
else:
# 降级方案:使用标准对话框
QtWidgets.QMessageBox.about(self, "关于", message)
def showDocumentation(self): def showDocumentation(self):
"""显示帮助文档 - 打开用户手册""" """显示帮助文档 - 打开用户手册"""
......
...@@ -511,6 +511,7 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -511,6 +511,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
folder_path = osp.join(self._root_path, folder_name) folder_path = osp.join(self._root_path, folder_name)
if not osp.exists(folder_path): if not osp.exists(folder_path):
print(f"[数据采集] 文件夹不存在: {folder_path}")
return return
try: try:
...@@ -519,6 +520,8 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -519,6 +520,8 @@ class DataCollectionPanel(QtWidgets.QWidget):
if osp.isfile(osp.join(folder_path, f))] if osp.isfile(osp.join(folder_path, f))]
files.sort() files.sort()
print(f"[数据采集] 在文件夹 {folder_name} 中找到 {len(files)} 个文件")
# 添加到列表 # 添加到列表
for file in files: for file in files:
file_path = osp.join(folder_path, file) file_path = osp.join(folder_path, file)
...@@ -543,8 +546,9 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -543,8 +546,9 @@ class DataCollectionPanel(QtWidgets.QWidget):
if thumbnail: if thumbnail:
item.setIcon(QtGui.QIcon(thumbnail)) item.setIcon(QtGui.QIcon(thumbnail))
else: else:
# 缩略图生成失败,不显示图标(避免在录制过程中显示播放按钮) # 缩略图生成失败,使用默认视频图标
item.setIcon(QtGui.QIcon()) # 空图标 icon = self.style().standardIcon(QtWidgets.QStyle.SP_MediaPlay)
item.setIcon(icon)
item.setText(f"\n{display_name}") item.setText(f"\n{display_name}")
elif file_ext in ['.jpg', '.jpeg', '.png', '.bmp']: elif file_ext in ['.jpg', '.jpeg', '.png', '.bmp']:
# 图片文件 - 加载图片作为缩略图 # 图片文件 - 加载图片作为缩略图
...@@ -575,11 +579,19 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -575,11 +579,19 @@ class DataCollectionPanel(QtWidgets.QWidget):
"""生成视频缩略图(提取第一帧)""" """生成视频缩略图(提取第一帧)"""
try: try:
import cv2 import cv2
import time
# 打开视频文件 # 尝试多次打开视频文件(刚录制完成的文件可能需要等待)
cap = cv2.VideoCapture(video_path) cap = None
for attempt in range(3):
cap = cv2.VideoCapture(video_path)
if cap.isOpened():
break
if cap:
cap.release()
time.sleep(0.1) # 等待100ms后重试
if not cap.isOpened(): if not cap or not cap.isOpened():
return None return None
# 读取第一帧 # 读取第一帧
...@@ -589,6 +601,11 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -589,6 +601,11 @@ class DataCollectionPanel(QtWidgets.QWidget):
if not ret or frame is None: if not ret or frame is None:
return None return None
# 检查 QGuiApplication 是否存在(避免应用关闭时出错)
from qtpy.QtWidgets import QApplication
if not QApplication.instance():
return None
# 转换颜色空间 BGR -> RGB # 转换颜色空间 BGR -> RGB
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
...@@ -613,6 +630,11 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -613,6 +630,11 @@ class DataCollectionPanel(QtWidgets.QWidget):
def _generateImageThumbnail(self, image_path): def _generateImageThumbnail(self, image_path):
"""生成图片缩略图""" """生成图片缩略图"""
try: try:
# 检查 QGuiApplication 是否存在(避免应用关闭时出错)
from qtpy.QtWidgets import QApplication
if not QApplication.instance():
return None
# 加载图片 # 加载图片
pixmap = QtGui.QPixmap(image_path) pixmap = QtGui.QPixmap(image_path)
...@@ -635,11 +657,11 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -635,11 +657,11 @@ class DataCollectionPanel(QtWidgets.QWidget):
"""检查文件是否正在被录制""" """检查文件是否正在被录制"""
try: try:
# 检查父窗口是否有录制状态信息 # 检查父窗口是否有录制状态信息
if not hasattr(self._parent, '_dc_save_flag'): if not hasattr(self._parent, '_dc_video_recording'):
return False return False
# 如果没有在录制,返回False # 如果没有在录制,返回False
if not getattr(self._parent, '_dc_save_flag', False): if not getattr(self._parent, '_dc_video_recording', False):
return False return False
# 检查是否是当前录制的文件 # 检查是否是当前录制的文件
...@@ -657,7 +679,7 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -657,7 +679,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
except (IOError, OSError): except (IOError, OSError):
# 文件被占用,可能正在录制 # 文件被占用,可能正在录制
# 但只有在确实在录制状态时才返回True # 但只有在确实在录制状态时才返回True
return getattr(self._parent, '_dc_save_flag', False) return getattr(self._parent, '_dc_video_recording', False)
except Exception as e: except Exception as e:
# 发生异常时,为安全起见不隐藏文件 # 发生异常时,为安全起见不隐藏文件
...@@ -923,7 +945,7 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -923,7 +945,7 @@ class DataCollectionPanel(QtWidgets.QWidget):
if self._current_folder: if self._current_folder:
self._loadFolderContent(self._current_folder) self._loadFolderContent(self._current_folder)
self._showInformation("成功", f"文件已删除\n{file_name}")
except Exception as e: except Exception as e:
self._showCritical("错误", f"删除文件失败:\n{str(e)}") self._showCritical("错误", f"删除文件失败:\n{str(e)}")
...@@ -1152,9 +1174,12 @@ class DataCollectionPanel(QtWidgets.QWidget): ...@@ -1152,9 +1174,12 @@ class DataCollectionPanel(QtWidgets.QWidget):
self.btn_record_video.clicked.connect(self._onRecordVideo) self.btn_record_video.clicked.connect(self._onRecordVideo)
if success: if success:
print(f"[数据采集] 录制停止成功,准备刷新文件列表")
print(f"[数据采集] 当前文件夹: {self._current_folder}")
# 刷新内容列表(显示新录制的视频) # 刷新内容列表(显示新录制的视频)
if self._current_folder: if self._current_folder:
self._loadFolderContent(self._current_folder) self._loadFolderContent(self._current_folder)
print(f"[数据采集] 文件列表已刷新")
else: else:
self._showWarning("录制失败", "录制时间过短,未能保存任何视频帧\n请确保录制时间足够长") self._showWarning("录制失败", "录制时间过短,未能保存任何视频帧\n请确保录制时间足够长")
else: else:
......
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