一、界面优化说明
针对原版界面样式简陋、布局比例不合理、交互体验差的问题,本次优化聚焦视觉美观度 和交互合理性:
- 新增应用标题栏,突出品牌感与功能定位;
- 优化布局比例,画面显示区尺寸适中,按钮区更紧凑且层级分明;
- 美化按钮样式(hover 效果、圆角、配色),提升交互反馈;
- 增加界面主题色,统一视觉风格;
- 优化画面显示区边框、背景,提升整体质感;
- 调整控件间距、字体大小,增强可读性。
二、优化后完整代码
import sys
import cv2
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QPushButton, QLabel, QFileDialog, QFrame)
from PyQt5.QtGui import QImage, QPixmap, QFont
from PyQt5.QtCore import QTimer, Qt, QSize
from ultralytics import YOLO
class YOLOv8Detector(QMainWindow):
def __init__(self):
super().__init__()
# 基础配置
self.setWindowTitle("YOLOv8 智能目标检测工具")
self.setGeometry(200, 100, 1100, 750)
self.setStyleSheet("""
QMainWindow {
background-color: #f5f7fa;
}
""")
# 核心变量初始化
self.model = YOLO("yolov8n.pt")
self.cap = None
self.timer = QTimer()
self.timer.timeout.connect(self.update_frame)
self.current_source = None
self.frame = None
# 构建优化后的界面
self._init_ui()
def _init_ui(self):
# 主部件与布局
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
main_layout.setContentsMargins(20, 20, 20, 20)
main_layout.setSpacing(15)
# 1. 标题栏
title_label = QLabel("YOLOv8 智能目标检测工具")
title_label.setAlignment(Qt.AlignCenter)
title_font = QFont("Microsoft YaHei", 20, QFont.Bold)
title_label.setFont(title_font)
title_label.setStyleSheet("""
QLabel {
color: #2d3748;
padding: 10px 0;
}
""")
main_layout.addWidget(title_label)
# 2. 核心内容区(画面+按钮)
content_layout = QHBoxLayout()
content_layout.setSpacing(20)
# 2.1 画面显示区(优化尺寸和样式)
self._create_display_area(content_layout)
# 2.2 功能按钮区(美化+分组)
self._create_button_area(content_layout)
main_layout.addLayout(content_layout)
def _create_display_area(self, parent_layout):
"""创建优化后的画面显示区"""
display_frame = QFrame()
display_frame.setStyleSheet("""
QFrame {
background-color: white;
border: 2px solid #e1e4e8;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
""")
display_layout = QVBoxLayout(display_frame)
display_layout.setContentsMargins(10, 10, 10, 10)
# 显示标签(尺寸适中,不再过度拉伸)
self.label_display = QLabel()
self.label_display.setAlignment(Qt.AlignCenter)
self.label_display.setMinimumSize(700, 500)
self.label_display.setMaximumSize(800, 600)
self.label_display.setStyleSheet("""
QLabel {
background-color: #f8f9fa;
border-radius: 4px;
}
""")
# 初始提示文字
self.label_display.setText("请选择输入源并开始检测")
hint_font = QFont("Microsoft YaHei", 14)
self.label_display.setFont(hint_font)
display_layout.addWidget(self.label_display)
parent_layout.addWidget(display_frame, stretch=7)
def _create_button_area(self, parent_layout):
"""创建美化后的按钮区"""
button_frame = QFrame()
button_frame.setStyleSheet("""
QFrame {
background-color: white;
border: 2px solid #e1e4e8;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
""")
button_layout = QVBoxLayout(button_frame)
button_layout.setContentsMargins(20, 20, 20, 20)
button_layout.setSpacing(15)
button_layout.setAlignment(Qt.AlignTop)
# 按钮通用样式
btn_common_style = """
QPushButton {
font-family: Microsoft YaHei;
font-size: 14px;
padding: 12px 20px;
border-radius: 6px;
border: none;
background-color: #4299e1;
color: white;
}
QPushButton:hover {
background-color: #3182ce;
}
QPushButton:disabled {
background-color: #a0aec0;
color: #e2e8f0;
}
QPushButton:pressed {
background-color: #2b6cb0;
}
"""
# 输入源选择按钮组
source_label = QLabel("输入源选择")
source_label.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
source_label.setStyleSheet("color: #2d3748; margin-bottom: 5px;")
button_layout.addWidget(source_label)
# 导入图片按钮
self.btn_import_img = QPushButton("导入图片")
self.btn_import_img.setStyleSheet(btn_common_style)
self.btn_import_img.clicked.connect(self.import_image)
button_layout.addWidget(self.btn_import_img)
# 导入视频按钮
self.btn_import_video = QPushButton("导入视频")
self.btn_import_video.setStyleSheet(btn_common_style)
self.btn_import_video.clicked.connect(self.import_video)
button_layout.addWidget(self.btn_import_video)
# 打开摄像头按钮
self.btn_open_camera = QPushButton("打开摄像头")
self.btn_open_camera.setStyleSheet(btn_common_style)
self.btn_open_camera.clicked.connect(self.open_camera)
button_layout.addWidget(self.btn_open_camera)
# 检测控制按钮组
control_label = QLabel("检测控制")
control_label.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
control_label.setStyleSheet("color: #2d3748; margin: 20px 0 5px 0;")
button_layout.addWidget(control_label)
# 开始检测按钮
self.btn_start_detect = QPushButton("开始检测")
self.btn_start_detect.setStyleSheet(btn_common_style)
self.btn_start_detect.clicked.connect(self.start_detection)
button_layout.addWidget(self.btn_start_detect)
# 停止检测按钮
self.btn_stop_detect = QPushButton("停止检测")
self.btn_stop_detect.setStyleSheet(btn_common_style)
self.btn_stop_detect.clicked.connect(self.stop_detection)
self.btn_stop_detect.setEnabled(False)
button_layout.addWidget(self.btn_stop_detect)
parent_layout.addWidget(button_frame, stretch=2)
# 核心功能逻辑(与原版一致,仅保留)
def import_image(self):
self.stop_detection()
file_path, _ = QFileDialog.getOpenFileName(
self, "选择图片", "", "Image Files (*.png *.jpg *.jpeg)"
)
if file_path:
self.current_source = "image"
self.frame = cv2.imread(file_path)
self._display_frame(self.frame)
def import_video(self):
self.stop_detection()
file_path, _ = QFileDialog.getOpenFileName(
self, "选择视频", "", "Video Files (*.mp4 *.avi *.mov)"
)
if file_path:
self.current_source = "video"
self.cap = cv2.VideoCapture(file_path)
ret, self.frame = self.cap.read()
if ret:
self._display_frame(self.frame)
def open_camera(self):
self.stop_detection()
self.current_source = "camera"
self.cap = cv2.VideoCapture(0)
ret, self.frame = self.cap.read()
if ret:
self._display_frame(self.frame)
def start_detection(self):
if self.current_source is None:
return
self.btn_start_detect.setEnabled(False)
self.btn_stop_detect.setEnabled(True)
if self.current_source == "image":
self._detect_image()
else:
self.timer.start(30)
def stop_detection(self):
self.btn_start_detect.setEnabled(True)
self.btn_stop_detect.setEnabled(False)
self.timer.stop()
if self.cap is not None:
self.cap.release()
self.cap = None
self.current_source = None
# 重置显示区提示文字
self.label_display.setText("请选择输入源并开始检测")
def _detect_image(self):
if self.frame is None:
return
results = self.model.predict(self.frame, save=False)
annotated_frame = results[0].plot()
self._display_frame(annotated_frame)
def update_frame(self):
if self.cap is None:
return
ret, frame = self.cap.read()
if not ret:
self.stop_detection()
return
results = self.model.predict(frame, save=False)
self.frame = results[0].plot()
self._display_frame(self.frame)
def _display_frame(self, frame):
"""优化帧显示逻辑,保持比例且适配显示区"""
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_frame.shape
bytes_per_line = ch * w
qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
# 适配显示区尺寸,保持比例且不超出最大尺寸
pixmap = QPixmap.fromImage(qt_image).scaled(
self.label_display.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation
)
self.label_display.setPixmap(pixmap)
def closeEvent(self, event):
self.stop_detection()
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
# 设置应用字体(统一中文显示)
font = QFont("Microsoft YaHei")
app.setFont(font)
window = YOLOv8Detector()
window.show()
sys.exit(app.exec_())
三、核心优化点详解
1. 视觉风格统一
- 采用现代简约风格,主色调选用柔和的蓝色(#4299e1),搭配浅灰 / 白色背景,符合桌面应用视觉审美;
- 所有控件使用圆角设计(8px/6px),减少尖锐感,增加友好度;
- 加入轻微阴影效果,提升界面层次感。
2. 布局结构优化
- 新增独立标题栏,明确应用名称,字体加粗放大;
- 将画面显示区和按钮区分别封装在带边框 / 阴影的容器中,视觉边界更清晰;
- 调整画面显示区尺寸(最小 700x500,最大 800x600),避免过度拉伸;
- 按钮区分组(输入源选择 / 检测控制),增加分组标题,逻辑更清晰;
- 优化所有布局的间距(margin/padding/spacing),避免控件拥挤或松散。
3. 按钮交互美化
- 按钮增加 hover(悬浮)、pressed(按下)、disabled(禁用)三种状态样式,交互反馈明确;
- 按钮字体放大,内边距增加,点击区域更大,操作更便捷;
- 统一按钮配色和圆角,视觉更协调。
4. 细节体验提升
- 初始状态下显示区添加提示文字,引导用户操作;
- 统一应用字体为 "微软雅黑",解决中文显示乱码 / 丑的问题;
- 停止检测时自动重置显示区提示文字,交互更完整;
- 画面显示区背景色区分,提升帧显示的对比度。
四、运行效果
- 启动后界面整洁美观,标题醒目,按钮分组清晰;
- 按钮悬浮时有颜色变化,按下时有深度反馈,禁用状态灰显,交互体验佳;
- 画面显示区尺寸适中,检测结果标注清晰,且不会过度占用屏幕空间;
- 整体风格接近商用桌面应用,告别原生 PyQt 的简陋样式。

五、拓展优化建议
- 主题切换:可增加亮色 / 暗色模式切换按钮,适配不同使用场景;
- 加载动画:检测过程中添加加载转圈动画,提升等待体验;
- 结果统计:新增检测结果统计面板(如检测到的目标数量、类别分布);
- 自定义样式:允许用户调整界面主题色、字体大小等;
- 响应式布局:适配不同屏幕分辨率,窗口缩放时自动调整控件尺寸。
该版本在保留核心功能的基础上,大幅提升了界面美观度和交互体验,既满足功能需求,又符合现代桌面应用的视觉设计规范。如果需要进一步定制化(如更换主题色、调整布局比例),只需修改样式表中的参数即可快速实现。