Commit 29a54b5f by Yuhaibo

1

parent 81c47ac5
......@@ -306,7 +306,7 @@ exe = EXE(
bootloader_ignore_signals=False,
strip=False, # 不strip二进制文件
upx=False, # 不使用UPX压缩(避免兼容性问题)
console=True, # True表示显示控制台窗口(用于调试)
console=False, # True表示显示控制台窗口(用于调试)
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
......
......@@ -147,7 +147,7 @@ except ImportError:
# 支持相对导入(作为模块运行)和绝对导入(独立运行)
try:
from .widgets import MenuBar
from .widgets.font_manager import FontManager
# 导入所有处理器 (Mixin类)
from .handlers import (
ChannelPanelHandler,
......
......@@ -689,6 +689,9 @@ class MainWindow(
# 默认显示模式1
self.videoLayoutStack.setCurrentIndex(0)
self._video_layout_mode = 0 # 0=默认模式, 1=曲线模式
# 初次创建页面后刷新一次按钮状态(默认布局)
self._updateCurveButtonsByMission()
return page
......@@ -989,6 +992,12 @@ class MainWindow(
# ========== 曲线面板信号 ==========
self.curvePanel.backClicked.connect(self.switchToRealTimeDetectionPage) # 返回实时检测管理页面
# 页面堆栈切换与视频子布局切换时,刷新曲线按钮状态
if hasattr(self, 'stackedWidget'):
self.stackedWidget.currentChanged.connect(self._onMainStackChanged)
if hasattr(self, 'videoLayoutStack'):
self.videoLayoutStack.currentChanged.connect(self._onVideoLayoutChanged)
def _initMenuBar(self):
"""初始化菜单栏(委托给MenuBarHandler处理)"""
......@@ -1026,6 +1035,60 @@ class MainWindow(
"""显示实时检测管理页面"""
self.stackedWidget.setCurrentWidget(self.videoPage)
self.statusBar().showMessage(self.tr("当前页面: 实时检测管理"))
# 切到视频页时刷新默认布局下的曲线按钮状态
self._updateCurveButtonsByMission()
def _onMainStackChanged(self, index: int):
"""主页面堆栈变化时,根据当前页面刷新按钮状态"""
try:
if index == self.PAGE_VIDEO:
self._updateCurveButtonsByMission()
except Exception:
pass
def _onVideoLayoutChanged(self, index: int):
"""视频页面子布局变化时刷新按钮状态"""
try:
self._video_layout_mode = index
# 仅在默认模式下需要检查并启用曲线按钮
if index == 0:
self._updateCurveButtonsByMission()
except Exception:
pass
def _updateCurveButtonsByMission(self):
"""
根据每个通道的任务标签是否有任务,启用或禁用“查看曲线”按钮。
仅在默认模式布局(任务表格 + 2x2通道面板)下生效。
"""
try:
# 仅在视频页默认布局下处理
if (
not hasattr(self, 'stackedWidget')
or self.stackedWidget.currentIndex() != self.PAGE_VIDEO
or not hasattr(self, 'videoLayoutStack')
or self.videoLayoutStack.currentIndex() != 0
):
return
# 遍历四个通道面板
for panel in getattr(self, 'channelPanels', []):
# 任务标签文本
mission_label = getattr(panel, 'taskLabel', None)
text = ''
if mission_label and hasattr(mission_label, 'text'):
text = mission_label.text().strip()
# 判断是否有有效任务
has_mission = bool(text) and text not in ('请选择任务', '未选择任务')
# 找到“查看曲线”按钮并设置可用性
curve_btn = getattr(panel, 'btn_curve', None)
if curve_btn and hasattr(curve_btn, 'setEnabled'):
curve_btn.setEnabled(has_mission)
except Exception:
# 安静失败,不影响主流程
pass
def showModelPage(self):
"""显示模型管理页面"""
......
......@@ -1207,7 +1207,7 @@ class ModelTestHandler:
height = area_data['liquid_height']
print(f"[液位检测] {area_name}: {height}mm")
self._showTestDetectionResult(test_frame, detection_result, boxes, bottoms, tops)
self._showTestDetectionResult(test_frame, detection_result, boxes, bottoms, tops, actual_heights)
print(f"[液位检测] 检测结果已显示在右侧面板中")
else:
......@@ -1217,7 +1217,7 @@ class ModelTestHandler:
print(f" 2. 检测区域设置不正确(位置偏移)")
print(f" 3. 图像质量或光照条件不佳")
self._showTestDetectionResult(test_frame, None, boxes, bottoms, tops)
self._showTestDetectionResult(test_frame, None, boxes, bottoms, tops, actual_heights)
print(f"[液位检测] 原始图像和标注信息已显示在右侧面板中")
......@@ -1227,7 +1227,7 @@ class ModelTestHandler:
traceback.print_exc()
try:
self._showTestDetectionResult(test_frame, None, boxes, bottoms, tops)
self._showTestDetectionResult(test_frame, None, boxes, bottoms, tops, actual_heights)
print(f"[液位检测] 原始图像已显示(检测失败)")
except Exception as show_error:
print(f"[液位检测] 显示原始图像也失败: {show_error}")
......@@ -1518,8 +1518,17 @@ class ModelTestHandler:
if hasattr(self, '_detection_stopped'):
print(f"[视频检测] 最终停止标志: {self._detection_stopped}")
def _showTestDetectionResult(self, original_frame, detection_result, boxes, bottoms, tops):
"""在显示面板中显示检测结果(带液位线的图像)"""
def _showTestDetectionResult(self, original_frame, detection_result, boxes, bottoms, tops, actual_heights=None):
"""在显示面板中显示检测结果(带液位线的图像)
Args:
original_frame: 原始图像帧
detection_result: 检测结果
boxes: 检测框列表
bottoms: 底部点列表
tops: 顶部点列表
actual_heights: 实际容器高度列表(毫米),如果为None则使用默认值20mm
"""
try:
from datetime import datetime
......@@ -1527,6 +1536,12 @@ class ModelTestHandler:
print(f"[检测结果显示] 原始帧尺寸: {original_frame.shape}")
print(f"[检测结果显示] 检测区域数量: {len(boxes)}")
print(f"[检测结果显示] 检测结果: {detection_result}")
print(f"[检测结果显示] 容器实际高度: {actual_heights}")
# 如果没有提供actual_heights,使用默认值
if actual_heights is None:
actual_heights = [20.0] * len(boxes)
print(f"[检测结果显示] 未提供容器高度,使用默认值: {actual_heights}")
# 复制原始帧
result_frame = original_frame.copy()
......@@ -1541,6 +1556,9 @@ class ModelTestHandler:
bottom_y = bottoms[i][1]
top_y = tops[i][1]
# 获取该区域的实际容器高度
actual_height = actual_heights[i] if i < len(actual_heights) else 20.0
# 提取液位高度(默认为0)
liquid_height = 0.0
......@@ -1550,7 +1568,7 @@ class ModelTestHandler:
area_name, area_data = area_items[i]
if 'liquid_height' in area_data:
liquid_height = area_data['liquid_height']
print(f"[检测结果显示] 区域{i+1}: 检测到液位 {liquid_height}mm")
print(f"[检测结果显示] 区域{i+1}: 检测到液位 {liquid_height}mm (容器高度: {actual_height}mm)")
else:
print(f"[检测结果显示] 区域{i+1}: 未检测到液位,使用默认值 0mm")
else:
......@@ -1558,10 +1576,10 @@ class ModelTestHandler:
else:
print(f"[检测结果显示] 区域{i+1}: 无检测结果,使用默认值 0mm")
# 计算液位线的Y坐标
container_height = bottom_y - top_y
liquid_ratio = min(1.0, max(0.0, liquid_height / 100.0))
liquid_y = int(bottom_y - container_height * liquid_ratio)
# 计算液位线的Y坐标 - 使用实际容器高度
container_height_px = bottom_y - top_y
liquid_ratio = min(1.0, max(0.0, liquid_height / actual_height))
liquid_y = int(bottom_y - container_height_px * liquid_ratio)
# 绘制液位线(红色)
cv2.line(result_frame, (left, liquid_y), (right, liquid_y), (0, 0, 255), 3)
......
......@@ -439,9 +439,10 @@ class ViewHandler:
for panel in self.channelPanels:
if hasattr(panel, 'btnCurve'):
if target_index == 0:
print(1)
# 曲线模式的同步布局:禁用查看曲线按钮
panel.btnCurve.setEnabled(False)
panel.btnCurve.setToolTip("同步布局下无法查看曲线")
# panel.btnCurve.setEnabled(False)
# panel.btnCurve.setToolTip("同步布局下无法查看曲线")
else:
# 曲线模式的历史回放布局:检查通道是否有任务
has_task = False
......
task: segment
mode: train
model: C:\Users\admin\AppData\Local\Temp\yolo_train_wobn62b4.pt
data: D:/restructure/liquid_level_line_detection_system/dataset1/train\data.yaml
epochs: 100
time: null
patience: 100
batch: 3
imgsz: 640
save: true
save_period: 1
cache: false
device: '0'
workers: 0
project: null
name: train
exist_ok: false
pretrained: true
optimizer: auto
verbose: true
seed: 0
deterministic: true
single_cls: false
rect: false
cos_lr: false
close_mosaic: 10
resume: false
amp: true
fraction: 1.0
profile: false
freeze: null
multi_scale: false
compile: false
overlap_mask: true
mask_ratio: 4
dropout: 0.0
val: true
split: val
save_json: false
conf: null
iou: 0.7
max_det: 300
half: false
dnn: false
plots: true
source: null
vid_stride: 1
stream_buffer: false
visualize: false
augment: false
agnostic_nms: false
classes: null
retina_masks: false
embed: null
show: false
save_frames: false
save_txt: false
save_conf: false
save_crop: false
show_labels: true
show_conf: true
show_boxes: true
line_width: null
format: torchscript
keras: false
optimize: false
int8: false
dynamic: false
simplify: true
opset: null
workspace: null
nms: false
lr0: 0.01
lrf: 0.01
momentum: 0.937
weight_decay: 0.0005
warmup_epochs: 3.0
warmup_momentum: 0.8
warmup_bias_lr: 0.1
box: 7.5
cls: 0.5
dfl: 1.5
pose: 12.0
kobj: 1.0
nbs: 64
hsv_h: 0.015
hsv_s: 0.7
hsv_v: 0.4
degrees: 0.0
translate: 0.1
scale: 0.5
shear: 0.0
perspective: 0.0
flipud: 0.0
fliplr: 0.5
bgr: 0.0
mosaic: 1.0
mixup: 0.0
cutmix: 0.0
copy_paste: 0.0
copy_paste_mode: flip
auto_augment: randaugment
erasing: 0.4
cfg: null
tracker: botsort.yaml
save_dir: D:\restructure\liquid_level_line_detection_system\runs\segment\train
......@@ -1706,7 +1706,13 @@ class ModelSetPage(QtWidgets.QWidget):
# 查找.dat文件(优先在根目录,兼容旧的weights子目录)
dat_files = list(subdir.glob("*.dat"))
# 如果根目录没有.dat文件,检查weights子目录(兼容旧结构)
# 如果根目录没有.dat文件,检查train/weights子目录(训练后的模型)
if not dat_files:
train_weights_dir = subdir / "train" / "weights"
if train_weights_dir.exists():
dat_files = list(train_weights_dir.glob("*.dat"))
# 如果train/weights也没有,检查weights子目录(兼容旧结构)
if not dat_files:
weights_dir = subdir / "weights"
if weights_dir.exists():
......
......@@ -1418,8 +1418,8 @@ class AnnotationWidget(QtWidgets.QWidget):
instructions = [
"标注操作指南",
"1. 左键拖动放置检测区域框",
"2. 拖动设置容器底部点",
"3. 拖动设置容器顶部点",
"2. 点击设置容器顶部点",
"3. 点击设置容器底部点",
"4. 双击编辑名称/高度,Enter确认",
"5. 双击状态标签切换状态\n(初始空满状态逻辑优化中,敬请期待)",
"\n6. 双击空白区域完成标注",
......@@ -1480,8 +1480,8 @@ class AnnotationWidget(QtWidgets.QWidget):
instructions_en = [
"Annotation Guide",
"1. Drag detection box",
"2. Click bottom line",
"3. Click top line",
"2. Click top point",
"3. Click bottom point",
"4. Double-click label to edit",
"5. Enter=Confirm, ESC=Cancel",
"6. Repeat steps",
......@@ -1589,13 +1589,13 @@ class AnnotationWidget(QtWidgets.QWidget):
# 检查点击位置是否在最后一个检测框内
if self._isPointInLastBox(image_x, image_y):
self.annotation_engine.bottom_points.append((image_x, image_y))
self.annotation_engine.step = 2
self.annotation_engine.step = 0 # 完成一组标注,回到画框模式
self._updateDisplay()
elif self.annotation_engine.step == 2: # 点击顶部模式
# 检查点击位置是否在最后一个检测框内
if self._isPointInLastBox(image_x, image_y):
self.annotation_engine.top_points.append((image_x, image_y))
self.annotation_engine.step = 0
self.annotation_engine.step = 1 # 切换到标注底部点模式
self._updateDisplay()
def _onMouseMove(self, event):
......@@ -1644,11 +1644,11 @@ class AnnotationWidget(QtWidgets.QWidget):
cy = (self.box_start[1] + y2) // 2
size = length
# 🔥 调用 add_box 方法,自动生成顶部点和底部点
# 调用 add_box 方法添加检测框
self.annotation_engine.add_box(cx, cy, size)
# 🔥 保持 step = 0(画框模式),不再需要手动点击设置顶部和底部点
# self.annotation_engine.step = 1 # 旧逻辑:进入点击底部点模式
# 切换到标注顶部点模式(先标顶点)
self.annotation_engine.step = 2 # step=2 是标注顶部点模式
self._updateDisplay()
......
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