前言
主要将自己基于PYQT5和YOLOv8进行检测界面制作的全程流程做一个总结,进行分享,其中对于自己借鉴学习的内容就不再发文章书写了,会将借鉴的文章链接贴在下面致敬,大家直接点击链接进行学习就好.
以下是我的项目代码:
mbl1234/YOLOv8_PYQT5_GUI: 基于YOLOv8和PYQT5的检测界面 (github.com)
想直接使用我的项目,避免YOLOv8的版本变化,可以直接使用我当时的版本进行模型训练,再将模型直接嵌入项目代码,进行测试使用就行:
mbl1234/YOLOv8_GUI: YOLOv8训练网络,与YOLOv8_PYQT5_GUI相关联 (github.com)
这一篇是基于YOLOv5和PYQT5进行检测界面的制作的内容:
(超详细流程-适合小白入门-一篇就够)基于YOLOv5和PYQT5进行检测界面的制作-CSDN博客
一.PYQT5的安装和QT Designer的学习
我是基于python语言,pycharm编译器,Anaconda包管理器.如果是初学者以上安装可以直接看此博主的链接进行学习:
目标检测---教你利用yolov5训练自己的目标检测模型_目标检测 教你利用-CSDN博客
基本内容安装成功后,进行PYQT5安装和配置,参考此博主链接进行学习:
[主要是在pycharm编译器中配置:
QT Designer(用于界面的可视化制作)
PyUIC(将QT Designer生成的.ui文件转换为编译器可以通过代码进行编译的.py文件)
Pyrcc(用于将QT Designer中引用图像文件生成的.qrc文件转换成.py文件,以便上一个.ui转换成的.py文件可以进行导入)]
PyQt5保姆级入门教程——从安装到使用_pyqt5教程-CSDN博客
整体基本安装配置完成之后,进行QT Designer的学习,进行检测界面的制作,参考此博主的链接进行学习:
GUI设计 PyQt5学习(二)——QtDesigner的基本使用方法_qt的designer在哪里-CSDN博客
Python-GUI编程-PyQt5 (少)_哔哩哔哩_bilibili
实验室项目展示用PyQt系列(2)设计基本流程、Qt Designer使用、界面中添加图片等_qt designer怎么显示图片-CSDN博客
基于YOLO系列代码和PYQT5进行GUI制作,可以参考此博主的链接进行学习:
使用PyQt5为YoloV5添加界面(一)_pyqt pyvista-CSDN博客
在代码跑动过程中,会遇到pycharm编译器中的GUI.py文件直接闪退不报错的问题,建议大家参考以下链接进行设置,直接会显示报错原因,方便进行修改:
解决pycharm调试Pyqt5异常退出,没有错误日志的问题_pyqt5界面无论登录错误还是成功都出现退出代码现象-CSDN博客
二.项目介绍
以上是项目目录,除了跑GUI文件YOLOv8中需要的文件外:
test文件夹中存放:测试YOLOv8_PYQT5_GUI所需要的权重文件和图像,用的都是官方权重和图像.
ui文件夹中存放:QT Designer制作的.ui文件和转换生成的.py文件.
ui_img文件夹中存放:QT Designer制作GUI界面需要的图像文件.
Detect_GUI.py文件主要是直接进入检测界面.
Login_GUI.py文件主要是从注册和登录界面进入检测界面.
userInfo.csv文件中主要存放注册界面生成的账号.
项目所能完成的任务
检测
除了正常的登录和注册界面以外,检测界面主要能够完成以下任务:
模型加载,图像加载,图像保存,图像保存,应用退出
Detect_GUI.py文件
可以好好看看这段代码中的注释,对于各个功能模块所牵涉到的功能函数进行了备注.
其中在图像打开之后直接嵌入了模型调用命令行进行调用和检测.
import sys
import cv2
from ultralytics.yolo.engine.model import YOLO
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
import ui_img.detect_images_rc
class Ui_MainWindow(QMainWindow):
def __init__(self):
super(Ui_MainWindow, self).__init__()
self.setWindowTitle("基于YOLOv8的检测演示软件V1.0")
self.resize(1500, 1000)
self.setStyleSheet("QWidget#centralwidget{background-image: url(:/detect_background/detect.JPG);}")
self.centralwidget = QWidget()
self.centralwidget.setObjectName("centralwidget")
# 模型选择
self.btn_selet_model = QtWidgets.QPushButton(self.centralwidget)
self.btn_selet_model.setGeometry(QtCore.QRect(70, 810, 70, 70))
self.btn_selet_model.setStyleSheet("border-image: url(:/detect_button_background/upload.png);")
self.btn_selet_model.setText("")
self.btn_selet_model.setObjectName("btn_selet_model")
self.btn_selet_model.clicked.connect(self.seletModels)
# 选择图像进行检测
self.btn_detect_img = QtWidgets.QPushButton(self.centralwidget)
self.btn_detect_img.setGeometry(QtCore.QRect(390, 810, 70, 70))
self.btn_detect_img.setStyleSheet("border-image: url(:/detect_button_background/images.png);")
self.btn_detect_img.setText("")
self.btn_detect_img.setObjectName("btn_detect_img")
self.btn_detect_img.clicked.connect(self.openImage)
# 保存结果图像
self.btn_save_img = QtWidgets.QPushButton(self.centralwidget)
self.btn_save_img.setGeometry(QtCore.QRect(730, 810, 70, 70))
self.btn_save_img.setStyleSheet("border-image: url(:/detect_button_background/save.png);")
self.btn_save_img.setText("")
self.btn_save_img.setObjectName("btn_save_img")
self.btn_save_img.clicked.connect(self.saveImage)
# 清除结果图像
self.btn_clear_img = QtWidgets.QPushButton(self.centralwidget)
self.btn_clear_img.setGeometry(QtCore.QRect(1050, 810, 70, 70))
self.btn_clear_img.setStyleSheet("border-image: url(:/detect_button_background/delete.png);")
self.btn_clear_img.setText("")
self.btn_clear_img.setObjectName("btn_clear_img")
self.btn_clear_img.clicked.connect(self.clearImage)
# 退出应用
self.btn_exit_app = QtWidgets.QPushButton(self.centralwidget)
self.btn_exit_app.setGeometry(QtCore.QRect(1360, 810, 70, 70))
self.btn_exit_app.setStyleSheet("border-image: url(:/detect_button_background/exit.png);")
self.btn_exit_app.setText("")
self.btn_exit_app.setObjectName("btn_exit_app")
self.btn_exit_app.clicked.connect(self.exitApp)
# 呈现原始图像
self.label_show_yuanshi = QtWidgets.QLabel(self.centralwidget)
self.label_show_yuanshi.setGeometry(QtCore.QRect(0, 80, 700, 700))
self.label_show_yuanshi.setStyleSheet("background-color: rgb(255, 255, 255);")
self.label_show_yuanshi.setObjectName("label_show_yuanshi")
# 呈现结果图像
self.label_show_jieguo = QtWidgets.QLabel(self.centralwidget)
self.label_show_jieguo.setGeometry(QtCore.QRect(800, 80, 700, 700))
self.label_show_jieguo.setStyleSheet("background-color: rgb(255, 255, 255);")
self.label_show_jieguo.setObjectName("label_show_jieguo")
# 呈现功能按键
self.label_show_button = QtWidgets.QLabel(self.centralwidget)
self.label_show_button.setGeometry(QtCore.QRect(0, 800, 1501, 141))
self.label_show_button.setStyleSheet("background-color: rgb(255, 255, 255);")
self.label_show_button.setText("")
self.label_show_button.setObjectName("label_show_button")
#编写模型加载
self.edit_selet_model = QtWidgets.QLineEdit(self.centralwidget)
self.edit_selet_model.setGeometry(QtCore.QRect(20, 890, 161, 40))
font = QtGui.QFont()
font.setFamily("Adobe 宋体 Std L")
font.setPointSize(28)
self.edit_selet_model.setFont(font)
self.edit_selet_model.setLayoutDirection(QtCore.Qt.RightToLeft)
self.edit_selet_model.setObjectName("edit_selet_model")
#编写图像加载
self.edit_detect_img = QtWidgets.QLineEdit(self.centralwidget)
self.edit_detect_img.setGeometry(QtCore.QRect(350, 890, 161, 40))
font = QtGui.QFont()
font.setFamily("Adobe 宋体 Std L")
font.setPointSize(28)
self.edit_detect_img.setFont(font)
self.edit_detect_img.setObjectName("edit_detect_img")
#编写图像保存
self.edit_save_img = QtWidgets.QLineEdit(self.centralwidget)
self.edit_save_img.setGeometry(QtCore.QRect(690, 890, 161, 40))
font = QtGui.QFont()
font.setFamily("Adobe 宋体 Std L")
font.setPointSize(28)
self.edit_save_img.setFont(font)
self.edit_save_img.setObjectName("edit_save_img")
#编写图像清除
self.edit_clear_img = QtWidgets.QLineEdit(self.centralwidget)
self.edit_clear_img.setGeometry(QtCore.QRect(1000, 890, 161, 40))
font = QtGui.QFont()
font.setFamily("Adobe 宋体 Std L")
font.setPointSize(28)
self.edit_clear_img.setFont(font)
self.edit_clear_img.setObjectName("edit_clear_img")
#编写应用退出
self.edit_exit_app = QtWidgets.QLineEdit(self.centralwidget)
self.edit_exit_app.setGeometry(QtCore.QRect(1300, 890, 161, 40))
font = QtGui.QFont()
font.setFamily("Adobe 宋体 Std L")
font.setPointSize(28)
self.edit_exit_app.setFont(font)
self.edit_exit_app.setObjectName("edit_exit_app")
# 标题
self.label_show_title = QtWidgets.QLabel(self.centralwidget)
self.label_show_title.setGeometry(QtCore.QRect(190, 10, 1101, 80))
font = QtGui.QFont()
font.setFamily("Adobe 黑体 Std R")
font.setPointSize(28)
self.label_show_title.setFont(font)
self.label_show_title.setStyleSheet("")
self.label_show_title.setObjectName("label_show_title")
self.label_show_button.raise_()
self.btn_selet_model.raise_()
self.btn_detect_img.raise_()
self.btn_save_img.raise_()
self.btn_clear_img.raise_()
self.btn_exit_app.raise_()
self.label_show_title.raise_()
self.label_show_yuanshi.raise_()
self.label_show_jieguo.raise_()
self.edit_selet_model.raise_()
self.edit_detect_img.raise_()
self.edit_save_img.raise_()
self.edit_clear_img.raise_()
self.edit_exit_app.raise_()
# 主窗口
self.setCentralWidget(self.centralwidget)
self.retranslateUi(self.centralwidget)
QtCore.QMetaObject.connectSlotsByName(self.centralwidget)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_show_title.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:28pt; font-weight:600; color:#ffffff;\">基于YOLOv8的检测演示软件</span></p></body></html>"))
self.label_show_yuanshi.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:20pt;\">原始图像</span></p></body></html>"))
self.label_show_jieguo.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:20pt;\">检测图像</span></p></body></html>"))
self.edit_selet_model.setText(_translate("MainWindow", "模型加载"))
self.edit_detect_img.setText(_translate("MainWindow", "图像加载"))
self.edit_save_img.setText(_translate("MainWindow", "图像保存"))
self.edit_clear_img.setText(_translate("MainWindow", "图像清除"))
self.edit_exit_app.setText(_translate("MainWindow", "应用退出"))
# 模型选择函数
def seletModels(self):
self.openfile_name_model, _ = QFileDialog.getOpenFileName(self.btn_selet_model, '选择weights文件', '.', '权重文件(*.pt)')
if not self.openfile_name_model:
QMessageBox.warning(self, "Warning:", "打开权重失败", buttons=QMessageBox.Ok,)
else:
print('加载weights文件地址为:' + str(self.openfile_name_model))
QMessageBox.information(self, u"Notice", u"权重打开成功", buttons=QtWidgets.QMessageBox.Ok)
# 图像选择函数
def openImage(self):
name_list = []
fname, _ = QFileDialog.getOpenFileName(self, '打开文件', '.', '图像文件(*.jpg)')
self.fname = fname
pixmap = QtGui.QPixmap(fname)
self.label_show_yuanshi.setPixmap(pixmap)
self.label_show_yuanshi.setScaledContents(True)
img = cv2.imread(fname)
# 引入模型
model = YOLO(self.openfile_name_model)
# 通过引用模型进行图像检测
results = model.predict(source=self.fname)
annotated_frame = results[0].plot()
# 将图像数据转换为QImage格式
height, width, channel = annotated_frame.shape
bytes_per_line = 3 * width
qimage = QtGui.QImage(annotated_frame.data, width, height, bytes_per_line, QtGui.QImage.Format_RGB888)
self.qImg = qimage
# 将QImage转换为QPixmap
pixmap = QtGui.QPixmap.fromImage(qimage)
self.label_show_jieguo.setPixmap(pixmap)
self.label_show_jieguo.setScaledContents(True)
return self.qImg
# 图像保存函数
def saveImage(self):
fd, _ = QFileDialog.getSaveFileName(self, "保存图片", ".", "*.jpg")
self.qImg.save(fd)
# 图像清除函数
def clearImage(self, stopp):
result = QMessageBox.question(self, "Warning:", "是否清除本次检测结果", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if result == QMessageBox.Yes:
self.label_show_yuanshi.clear()
self.label_show_jieguo.clear()
else:
stopp.ignore()
# 应用退出函数
def exitApp(self, event):
event = QApplication.instance()
result = QMessageBox.question(self, "Notice:", "您真的要退出此应用吗", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
if result == QMessageBox.Yes:
event.quit()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = Ui_MainWindow()
ui.show()
sys.exit(app.exec_())
Login_GUI.py
登录界面中包含登录和检测,其中还需要导入你在QT Designer中制作的的登录注册界面的.ui文件转换成的.py文件
import sys
from datetime import datetime
from PyQt5.QtWidgets import *
from utils.id_utils import get_id_info, sava_id_info # 账号信息工具函数
from lib.share import shareInfo # 公共变量名
# 导入QT-Design生成的UI
from ui.login_ui import Ui_Form
from ui.registe_ui import Ui_Dialog
# 导入设计好的检测界面
from Detect_GUI import Ui_MainWindow
import matplotlib.backends.backend_tkagg
# 界面登录
class win_Login(QMainWindow):
def __init__(self, parent = None):
super(win_Login, self).__init__(parent)
self.ui_login = Ui_Form()
self.ui_login.setupUi(self)
self.init_slots()
self.hidden_pwd()
# 密码输入框隐藏
def hidden_pwd(self):
self.ui_login.edit_password.setEchoMode(QLineEdit.Password)
# 绑定信号槽
def init_slots(self):
self.ui_login.btn_login.clicked.connect(self.onSignIn) # 点击按钮登录
self.ui_login.edit_password.returnPressed.connect(self.onSignIn) # 按下回车登录
self.ui_login.btn_regeist.clicked.connect(self.create_id)
# 跳转到注册界面
def create_id(self):
shareInfo.createWin = win_Registe()
shareInfo.createWin.show()
# 保存登录日志
def sava_login_log(self, username):
with open('login_log.txt', 'a', encoding='utf-8') as f:
f.write(username + '\t log in at' + datetime.now().strftimestrftime+ '\r')
# 登录
def onSignIn(self):
print("You pressed sign in")
# 从登陆界面获得输入账户名与密码
username = self.ui_login.edit_username.text().strip()
password = self.ui_login.edit_password.text().strip()
print(username)
print(password)
# 获得账号信息
USER_PWD = get_id_info()
# print(USER_PWD)
if username not in USER_PWD.keys():
replay = QMessageBox.warning(self,"登陆失败!", "账号或密码输入错误", QMessageBox.Yes)
else:
# 若登陆成功,则跳转主界面
if USER_PWD.get(username) == password:
print("Jump to main window")
# 所以使用公用变量名
# shareInfo.mainWin = UI_Logic_Window()
shareInfo.mainWin = Ui_MainWindow()
shareInfo.mainWin.show()
# 关闭当前窗口
self.close()
else:
replay = QMessageBox.warning(self, "!", "账号或密码输入错误", QMessageBox.Yes)
# 注册界面
class win_Registe(QMainWindow):
def __init__(self, parent = None):
super(win_Registe, self).__init__(parent)
self.ui_registe = Ui_Dialog()
self.ui_registe.setupUi(self)
self.init_slots()
# 绑定槽信号
def init_slots(self):
self.ui_registe.pushButton_regiser.clicked.connect(self.new_account)
self.ui_registe.pushButton_cancer.clicked.connect(self.cancel)
# 创建新账户
def new_account(self):
print("Create new account")
USER_PWD = get_id_info()
# print(USER_PWD)
new_username = self.ui_registe.edit_username.text().strip()
new_password = self.ui_registe.edit_password.text().strip()
# 判断用户名是否为空
if new_username == "":
replay = QMessageBox.warning(self, "!", "账号不准为空", QMessageBox.Yes)
else:
# 判断账号是否存在
if new_username in USER_PWD.keys():
replay = QMessageBox.warning(self, "!", "账号已存在", QMessageBox.Yes)
else:
# 判断密码是否为空
if new_password == "":
replay = QMessageBox.warning(self, "!", "密码不能为空", QMessageBox.Yes)
else:
# 注册成功
print("Successful!")
sava_id_info(new_username, new_password)
replay = QMessageBox.warning(self, "!", "注册成功!", QMessageBox.Yes)
# 关闭界面
self.close()
# 取消注册
def cancel(self):
self.close() # 关闭当前界面
if __name__ == "__main__":
app = QApplication(sys.argv)
# 利用共享变量名来实例化对象
shareInfo.loginWin = win_Login() # 登录界面作为主界面
shareInfo.loginWin.show()
sys.exit(app.exec_())