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. 响应式布局:适配不同屏幕分辨率,窗口缩放时自动调整控件尺寸。

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

相关推荐
向哆哆3 天前
高精度织物缺陷检测数据集(适用YOLO系列/1000+标注)(已标注+划分/可直接训练)
yolo·目标检测
前网易架构师-高司机4 天前
带标注的驾驶员安全带识别数据集,识别率99.5%,可识别有无系安全带,支持yolo,coco json,pascal voc xml格式
xml·yolo·数据集·交通·安全带
向哆哆4 天前
粉尘环境分类检测千张图数据集(适用YOLO系列)(已标注+划分/可直接训练)
yolo·分类·数据挖掘
琅琊榜首20204 天前
移动端AI挂机新范式:YOLOv8+NCNN实现无Root视觉自动化
人工智能·yolo·自动化
智驱力人工智能5 天前
地铁隧道轨道障碍物实时检测方案 守护城市地下动脉的工程实践 轨道障碍物检测 高铁站区轨道障碍物AI预警 铁路轨道异物识别系统价格
人工智能·算法·yolo·目标检测·计算机视觉·边缘计算
智驱力人工智能5 天前
机场鸟类活动智能监测 守护航空安全的精准工程实践 飞鸟检测 机场鸟击预防AI预警系统方案 机场停机坪鸟类干扰实时监测机场航站楼鸟击预警
人工智能·opencv·算法·安全·yolo·目标检测·边缘计算
前端摸鱼匠5 天前
YOLOv8使用 Ultralytics 内置功能简化格式转换:介绍如何使用 yolo mode=data 等相关功能或辅助工具来加速和简化数据格式的准备工作
人工智能·yolo·目标检测·机器学习·目标跟踪·视觉检测
hans汉斯5 天前
《数据挖掘》期刊推介&征稿指南
图像处理·人工智能·算法·yolo·数据挖掘·超分辨率重建·汉斯出版社
卓越软件开发5 天前
毕设全栈开发一条龙:Java/SpringBoot/Vue/ 小程序 / Python / 安卓 / AI 图像识别 人脸检测 车牌识别 YOLO
开发语言·spring boot·python·yolo·小程序·毕业设计·课程设计
向哆哆5 天前
单车/共享单车目标检测数据集(适用YOLO系列)(已标注+划分/可直接训练)
人工智能·yolo·目标检测