YOLOv8+PyQt5 实战:高颜值目标检测可视化桌面应用(优化版)

一、界面优化说明

针对原版界面样式简陋、布局比例不合理、交互体验差的问题,本次优化聚焦视觉美观度交互合理性

  1. 新增应用标题栏,突出品牌感与功能定位;
  2. 优化布局比例,画面显示区尺寸适中,按钮区更紧凑且层级分明;
  3. 美化按钮样式(hover 效果、圆角、配色),提升交互反馈;
  4. 增加界面主题色,统一视觉风格;
  5. 优化画面显示区边框、背景,提升整体质感;
  6. 调整控件间距、字体大小,增强可读性。

二、优化后完整代码

复制代码
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. 细节体验提升

  • 初始状态下显示区添加提示文字,引导用户操作;
  • 统一应用字体为 "微软雅黑",解决中文显示乱码 / 丑的问题;
  • 停止检测时自动重置显示区提示文字,交互更完整;
  • 画面显示区背景色区分,提升帧显示的对比度。

四、运行效果

  1. 启动后界面整洁美观,标题醒目,按钮分组清晰;
  2. 按钮悬浮时有颜色变化,按下时有深度反馈,禁用状态灰显,交互体验佳;
  3. 画面显示区尺寸适中,检测结果标注清晰,且不会过度占用屏幕空间;
  4. 整体风格接近商用桌面应用,告别原生 PyQt 的简陋样式。

五、拓展优化建议

  1. 主题切换:可增加亮色 / 暗色模式切换按钮,适配不同使用场景;
  2. 加载动画:检测过程中添加加载转圈动画,提升等待体验;
  3. 结果统计:新增检测结果统计面板(如检测到的目标数量、类别分布);
  4. 自定义样式:允许用户调整界面主题色、字体大小等;
  5. 响应式布局:适配不同屏幕分辨率,窗口缩放时自动调整控件尺寸。

该版本在保留核心功能的基础上,大幅提升了界面美观度和交互体验,既满足功能需求,又符合现代桌面应用的视觉设计规范。如果需要进一步定制化(如更换主题色、调整布局比例),只需修改样式表中的参数即可快速实现。

相关推荐
QQ676580088 小时前
服装计算机视觉数据集 连衣裙数据集 衣服类别识别 毛衣数据集 夹克衫AI识别 衬衫识别 裤子 数据集 yolo格式数据集
人工智能·yolo·计算机视觉·连衣裙·衣服类别·毛衣数据集·夹克衫ai
云程笔记14 小时前
021.损失函数深度解读:YOLO的定位、置信度、分类损失计算
人工智能·yolo·机器学习·计算机视觉·分类·数据挖掘
羊羊小栈15 小时前
基于「YOLO目标检测 + 多模态AI分析」的智慧农业茶叶病害检测预警系统
人工智能·yolo·目标检测·计算机视觉·毕业设计·大作业
angleboy816 小时前
【原创】如何WIN 10/11系统下解决YOLOv13训练异常的安装指南
人工智能·深度学习·yolo
前端摸鱼匠17 小时前
YOLOv11 在零售领域实战:利用公开的商品检测数据集 (如 SKU110K 的子集),训练一个 YOLOv11 模型,用于识别货架上的各种商品
人工智能·yolo·目标检测·ai·目标跟踪·视觉检测·零售
深度学习lover17 小时前
<数据集>yolo微藻识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·微藻识别
superior tigre18 小时前
某为25.9.28 Yolo检测器中的anchor聚类(python实现)
python·yolo·聚类
小卡布聊技术19 小时前
YOLOv8
yolo
动物园猫19 小时前
电缆损坏目标检测数据集分享(YOLO系列)| 电缆断裂 雷击损伤 断股 烧蚀痕迹 输电线路巡检 目标检测标注
人工智能·yolo·目标检测
动物园猫19 小时前
道路表面缺陷数据集分享(YOLO系列分类检测)| 路面病害 目标检测 坑洼裂缝 训练集
yolo·目标检测·分类