当前位置:   article > 正文

(超详细流程-适合小白入门-一篇就够)基于YOLOv5和PYQT5进行检测界面的制作_pyqt5怎么设计一个检测界面

pyqt5怎么设计一个检测界面

 前言

主要将自己基于PYQT5和YOLOv5进行检测界面制作的全程流程做一个总结,进行分享,在看这篇文章前,请先阅读我的上一篇文章,所有详细内容在上一篇中:

(超详细流程-适合小白入门-一篇就够)基于YOLOv8和PYQT5进行检测界面的制作-CSDN博客

以下是我的项目代码:

mbl1234/YOLOv5_PYQT5_GUI: 基于YOLOv5和PYQT5的检测界面 (github.com)

想直接使用我的项目,避免YOLOv5的版本变化,可以直接使用我当时的版本进行模型训练,再将模型直接嵌入项目代码,进行测试使用就行:

mbl1234/YOLOv5_PYQT5_GUI: 基于YOLOv5和PYQT5的检测界面 (github.com)

项目介绍

以上是项目目录,除了跑GUI文件YOLOv5中需要的文件外:

test文件夹中存放:测试YOLOv5_PYQT5_GUI所需要的权重文件和图像,用的都是官方权重和图像.

ui文件夹中存放:QT Designer制作的.ui文件和转换生成的.py文件.

ui_img文件夹中存放:QT Designer制作GUI界面需要的图像文件.

Detect_GUI.py文件主要是直接进入检测界面.

Login_GUI.py文件主要是从注册和登录界面进入检测界面.

userInfo.csv文件中主要存放注册界面生成的账号.

登录

注册

检测

除了正常的登录和注册界面以外,检测界面主要能够完成以下任务:

最优模型选择,模型初始化,选择检测图像,保存结果图像,清除结果图像,退出应用

Detect_GUI.py文件

可以好好看看这段代码中的注释,对于各个功能模块所牵涉到的功能函数进行了备注.

其中在图像打开之后直接嵌入了模型调用命令行进行调用和检测.

  1. # -*- coding: utf-8 -*-
  2. # Form implementation generated from reading ui file 'ui/ui/detect_ui.ui'
  3. #
  4. # Created by: PyQt5 UI code generator 5.15.4
  5. #
  6. # WARNING: Any manual changes made to this file will be lost when pyuic5 is
  7. # run again. Do not edit this file unless you know what you are doing.
  8. import sys
  9. import cv2
  10. import argparse
  11. import random
  12. import torch
  13. import numpy as np
  14. import torch.backends.cudnn as cudnn
  15. from models.common import DetectMultiBackend
  16. from models.experimental import attempt_load
  17. from utils.augmentations import letterbox
  18. from utils.general import check_img_size, non_max_suppression, scale_coords, increment_path
  19. from utils.torch_utils import select_device
  20. from utils.plots import Annotator, plot_one_box2
  21. from PyQt5 import QtCore, QtGui, QtWidgets
  22. from PyQt5.QtCore import *
  23. from PyQt5.QtGui import *
  24. from PyQt5.QtWidgets import *
  25. import ui_img.detect_rc
  26. class Ui_MainWindow(QMainWindow):
  27. def __init__(self):
  28. super(Ui_MainWindow, self).__init__()
  29. self.setWindowTitle("基于YOLOv5的识别检测演示软件V1.0")
  30. self.resize(1600, 900)
  31. self.centralwidget = QWidget()
  32. self.centralwidget.setObjectName("centralwidget")
  33. # 背景图像
  34. self.listView = QtWidgets.QListView(self.centralwidget)
  35. self.listView.setGeometry(QtCore.QRect(-11, -10, 1661, 931))
  36. self.listView.setStyleSheet("background-image: url(:/detect/detect.JPG);")
  37. self.listView.setObjectName("listView")
  38. # 模型选择
  39. self.btn_selet_model = QtWidgets.QPushButton(self.centralwidget)
  40. self.btn_selet_model.setGeometry(QtCore.QRect(70, 810, 112, 51))
  41. font = QtGui.QFont()
  42. font.setFamily("Adobe 宋体 Std L")
  43. font.setPointSize(12)
  44. self.btn_selet_model.setFont(font)
  45. self.btn_selet_model.setObjectName("btn_selet_model")
  46. self.btn_selet_model.clicked.connect(self.seletModels)
  47. # 呈现原始图像
  48. self.label_show_yuanshi = QtWidgets.QLabel(self.centralwidget)
  49. self.label_show_yuanshi.setGeometry(QtCore.QRect(70, 80, 700, 700))
  50. self.label_show_yuanshi.setStyleSheet("background-color: rgb(255, 255, 255);")
  51. self.label_show_yuanshi.setObjectName("label_show_yuanshi")
  52. # 模型初始化
  53. self.btn_init_model = QtWidgets.QPushButton(self.centralwidget)
  54. self.btn_init_model.setGeometry(QtCore.QRect(220, 810, 112, 51))
  55. font = QtGui.QFont()
  56. font.setFamily("Adobe 宋体 Std L")
  57. font.setPointSize(12)
  58. self.btn_init_model.setFont(font)
  59. self.btn_init_model.setObjectName("btn_init_model")
  60. self.btn_init_model.clicked.connect(self.initModels)
  61. # 选择图像进行检测
  62. self.btn_detect_img = QtWidgets.QPushButton(self.centralwidget)
  63. self.btn_detect_img.setGeometry(QtCore.QRect(370, 810, 112, 51))
  64. font = QtGui.QFont()
  65. font.setFamily("Adobe 宋体 Std L")
  66. font.setPointSize(12)
  67. self.btn_detect_img.setFont(font)
  68. self.btn_detect_img.setObjectName("btn_detect_img")
  69. self.btn_detect_img.clicked.connect(self.openImage)
  70. # 保存结果图像
  71. self.btn_save_img = QtWidgets.QPushButton(self.centralwidget)
  72. self.btn_save_img.setGeometry(QtCore.QRect(1125, 810, 112, 51))
  73. font = QtGui.QFont()
  74. font.setFamily("Adobe 宋体 Std L")
  75. font.setPointSize(12)
  76. self.btn_save_img.setFont(font)
  77. self.btn_save_img.setObjectName("btn_save_img")
  78. self.btn_save_img.clicked.connect(self.saveImage)
  79. # 清除结果图像
  80. self.btn_clear_img = QtWidgets.QPushButton(self.centralwidget)
  81. self.btn_clear_img.setGeometry(QtCore.QRect(1275, 810, 112, 51))
  82. font = QtGui.QFont()
  83. font.setFamily("Adobe 宋体 Std L")
  84. font.setPointSize(12)
  85. self.btn_clear_img.setFont(font)
  86. self.btn_clear_img.setObjectName("btn_clear_img")
  87. self.btn_clear_img.clicked.connect(self.clearImage)
  88. # 退出应用
  89. self.btn_exit_app = QtWidgets.QPushButton(self.centralwidget)
  90. self.btn_exit_app.setGeometry(QtCore.QRect(1425, 810, 112, 51))
  91. font = QtGui.QFont()
  92. font.setFamily("Adobe 宋体 Std L")
  93. font.setPointSize(12)
  94. self.btn_exit_app.setFont(font)
  95. self.btn_exit_app.setObjectName("btn_exit_app")
  96. self.btn_exit_app.clicked.connect(self.exitApp)
  97. # 呈现结果图像
  98. self.label_show_jieguo = QtWidgets.QLabel(self.centralwidget)
  99. self.label_show_jieguo.setGeometry(QtCore.QRect(840, 80, 700, 700))
  100. self.label_show_jieguo.setStyleSheet("background-color: rgb(255, 255, 255);")
  101. self.label_show_jieguo.setObjectName("label_show_jieguo")
  102. # 标题
  103. self.label_show_title = QtWidgets.QLabel(self.centralwidget)
  104. self.label_show_title.setGeometry(QtCore.QRect(430, 20, 800, 41))
  105. self.label_show_title.setObjectName("label_show_title")
  106. # 主窗口
  107. self.setCentralWidget(self.centralwidget)
  108. self.retranslateUi(self.centralwidget)
  109. QtCore.QMetaObject.connectSlotsByName(self.centralwidget)
  110. # 图像检测函数
  111. def detectImage(self, name_list, img):
  112. '''
  113. :param name_list: 文件名列表
  114. :param img: 待检测图片
  115. :return: info_show:检测输出的文字信息
  116. '''
  117. showimg = img
  118. with torch.no_grad():
  119. img = letterbox(img, new_shape=self.opt.imgsz)[0]
  120. # Convert
  121. img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416
  122. img = np.ascontiguousarray(img)
  123. img = torch.from_numpy(img).to(self.device)
  124. img = img.half() if self.opt.half else img.float() # uint8 to fp16/32
  125. img /= 255.0 # 0 - 255 to 0.0 - 1.0
  126. if len(img.shape) == 3:
  127. img = img[None]
  128. # Inference
  129. pred = self.model(img, augment=self.opt.augment, visualize=self.opt.visualize)
  130. # Apply NMS
  131. pred = non_max_suppression(pred, self.opt.conf_thres, self.opt.iou_thres, classes=self.opt.classes, agnostic=self.opt.agnostic_nms, max_det=self.opt.max_det)
  132. info_show = ""
  133. # Process detections
  134. annotator = Annotator(img, line_width=self.opt.line_thickness, example=str(self.names))
  135. for i, det in enumerate(pred):
  136. if det is not None and len(det):
  137. # Rescale boxes from img_size to im0 size
  138. det[:, :4] = scale_coords(img.shape[2:], det[:, :4], showimg.shape).round()
  139. for *xyxy, conf, cls in reversed(det):
  140. c = int(cls)
  141. print(c)
  142. label = None if self.opt.hide_labels else (self.names[c] if self.opt.hide_conf else f'{self.names[c]} {conf:.2f}')
  143. name_list.append(self.names[int(cls)])
  144. single_info = plot_one_box2(xyxy, showimg, label=label, color=self.colors[int(cls)], line_thickness=2)
  145. print(single_info)
  146. info_show = info_show + single_info + "\n"
  147. # 模型选择函数
  148. def seletModels(self):
  149. self.openfile_name_model, _ = QFileDialog.getOpenFileName(self.btn_selet_model, '选择weights文件', '.', '权重文件(*.pt)')
  150. if not self.openfile_name_model:
  151. QMessageBox.warning(self, "Warning:", "打开权重失败", buttons=QMessageBox.Ok,)
  152. else:
  153. print('加载weights文件地址为:' + str(self.openfile_name_model))
  154. QMessageBox.information(self, u"Notice", u"权重打开成功", buttons=QtWidgets.QMessageBox.Ok)
  155. # 模型初始化函数
  156. def initModels(self):
  157. # 模型相关参数配置
  158. parser = argparse.ArgumentParser()
  159. parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp/weights/best.pt', help='model path(s)')
  160. parser.add_argument('--source', type=str, default='data/applenew5/images/test/', help='file/dir/URL/glob, 0 for webcam')
  161. parser.add_argument('--data', type=str, default='data/coco128.yaml', help='(optional) dataset.yaml path')
  162. parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=640, help='inference size h,w')
  163. parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold')
  164. parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold')
  165. parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image')
  166. parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
  167. parser.add_argument('--view-img', action='store_true', help='show results')
  168. parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
  169. parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
  170. parser.add_argument('--save-crop', action='store_true', help='save cropped prediction boxes')
  171. parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
  172. parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3')
  173. parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
  174. parser.add_argument('--augment', action='store_true', help='augmented inference')
  175. parser.add_argument('--visualize', action='store_true', help='visualize features')
  176. parser.add_argument('--update', action='store_true', help='update all models')
  177. parser.add_argument('--project', default='runs/detect', help='save results to project/name')
  178. parser.add_argument('--name', default='exp', help='save results to project/name')
  179. parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
  180. parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)')
  181. parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels')
  182. parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences')
  183. parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
  184. parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference')
  185. self.opt = parser.parse_args()
  186. print(self.opt)
  187. # 默认使用opt中的设置(权重等)来对模型进行初始化
  188. source, weights, view_img, save_txt, imgsz, half, data, dnn, visualize, max_det = \
  189. self.opt.source, self.opt.weights, self.opt.view_img, self.opt.save_txt, self.opt.imgsz, self.opt.half, self.opt.data, self.opt.dnn, self.opt.visualize, self.opt.max_det
  190. # 若openfile_name_model不为空,则使用此权重进行初始化
  191. if self.openfile_name_model:
  192. weights = self.openfile_name_model
  193. print("Using button choose model")
  194. self.device = select_device(self.opt.device)
  195. cudnn.benchmark = True
  196. # Load model
  197. self.model = DetectMultiBackend(weights, device=self.device, dnn=self.opt.dnn, data=self.opt.data, fp16=half)
  198. stride = self.model.stride # model stride
  199. self.imgsz = check_img_size(imgsz, s=stride) # check img_size
  200. # Get names and colors
  201. self.names = self.model.names
  202. self.colors = [[random.randint(0, 255) for _ in range(3)] for _ in self.names]
  203. print("model initial done")
  204. # 设置提示框
  205. QtWidgets.QMessageBox.information(self, u"Notice", u"模型加载完成", buttons=QtWidgets.QMessageBox.Ok,
  206. defaultButton=QtWidgets.QMessageBox.Ok)
  207. # 图像选择函数
  208. def openImage(self):
  209. print('openImage')
  210. name_list = []
  211. fname, _ = QFileDialog.getOpenFileName(self, '打开文件', '.', '图像文件(*.jpg)')
  212. print(fname)
  213. # if not fname:
  214. # QMessageBox.warning(self, u"Warning", u"打开图片失败", buttons=QMessageBox.Ok)
  215. # else:
  216. self.label_show_yuanshi.setPixmap(QPixmap(fname))
  217. self.label_show_yuanshi.setScaledContents(True)
  218. img = cv2.imread(fname)
  219. print(img)
  220. print("model initial done21")
  221. self.detectImage(name_list, img)
  222. info_show = self.detectImage(name_list, img)
  223. print(info_show)
  224. # 检测结果显示在界面
  225. print("model initial done23")
  226. self.result = cv2.cvtColor(img, cv2.COLOR_BGR2BGRA)
  227. self.result = cv2.resize(self.result, (1000, 1000), interpolation=cv2.INTER_AREA)
  228. self.QtImg = QImage(self.result.data, self.result.shape[1], self.result.shape[0], QImage.Format_RGB32)
  229. self.qImg = self.QtImg
  230. self.label_show_jieguo.setPixmap(QtGui.QPixmap.fromImage(self.QtImg))
  231. print(self.label_show_jieguo)
  232. self.label_show_jieguo.setScaledContents(True) # 设置图像自适应界面大小
  233. return self.qImg
  234. # 图像保存函数
  235. def saveImage(self):
  236. fd, _ = QFileDialog.getSaveFileName(self, "保存图片", ".", "*.jpg")
  237. self.qImg.save(fd)
  238. # 图像清除函数
  239. def clearImage(self, stopp):
  240. result = QMessageBox.question(self, "Warning:", "是否清除本次检测结果", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
  241. if result == QMessageBox.Yes:
  242. self.label_show_yuanshi.clear()
  243. self.label_show_jieguo.clear()
  244. else:
  245. stopp.ignore()
  246. # 应用退出函数
  247. def exitApp(self, event):
  248. event = QApplication.instance()
  249. result = QMessageBox.question(self, "Notice:", "您真的要退出此应用吗", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
  250. if result == QMessageBox.Yes:
  251. event.quit()
  252. else:
  253. event.ignore()
  254. def retranslateUi(self, MainWindow):
  255. _translate = QtCore.QCoreApplication.translate
  256. MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
  257. self.btn_selet_model.setText(_translate("MainWindow", "最优模型选择"))
  258. self.label_show_yuanshi.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:16pt;\">原始图像</span></p></body></html>"))
  259. self.btn_init_model.setText(_translate("MainWindow", "模型初始化"))
  260. self.btn_detect_img.setText(_translate("MainWindow", "选择检测图像"))
  261. self.btn_save_img.setText(_translate("MainWindow", "保存结果图像"))
  262. self.btn_clear_img.setText(_translate("MainWindow", "清除结果图像"))
  263. self.btn_exit_app.setText(_translate("MainWindow", "退出应用"))
  264. self.label_show_jieguo.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:16pt;\">结果图像</span></p></body></html>"))
  265. self.label_show_title.setText(_translate("MainWindow", "<html><head/><body><p align=\"center\"><span style=\" font-size:26pt; color:#ffffff;\">基于YOLOv5的识别检测演示软件</span></p></body></html>"))
  266. if __name__ == '__main__':
  267. app = QApplication(sys.argv)
  268. ui = Ui_MainWindow()
  269. ui.show()
  270. sys.exit(app.exec_())

Login_GUI.py

登录界面中包含登录和检测,其中还需要导入你在QT Designer中制作的的登录注册界面的.ui文件转换成的.py文件.

  1. import sys
  2. from datetime import datetime
  3. from PyQt5 import QtWidgets
  4. from PyQt5.QtWidgets import *
  5. from utils.id_utils import get_id_info, sava_id_info # 账号信息工具函数
  6. from lib.share import shareInfo # 公共变量名
  7. # 导入QT-Design生成的UI
  8. from ui.login_ui import Ui_Form
  9. from ui.registe_ui import Ui_Dialog
  10. # 导入设计好的检测界面
  11. from Detect_GUI import Ui_MainWindow
  12. import matplotlib.backends.backend_tkagg
  13. # 界面登录
  14. class win_Login(QMainWindow):
  15. def __init__(self, parent = None):
  16. super(win_Login, self).__init__(parent)
  17. self.ui_login = Ui_Form()
  18. self.ui_login.setupUi(self)
  19. self.init_slots()
  20. self.hidden_pwd()
  21. # 密码输入框隐藏
  22. def hidden_pwd(self):
  23. self.ui_login.edit_password.setEchoMode(QLineEdit.Password)
  24. # 绑定信号槽
  25. def init_slots(self):
  26. self.ui_login.btn_login.clicked.connect(self.onSignIn) # 点击按钮登录
  27. self.ui_login.edit_password.returnPressed.connect(self.onSignIn) # 按下回车登录
  28. self.ui_login.btn_regeist.clicked.connect(self.create_id)
  29. # 跳转到注册界面
  30. def create_id(self):
  31. shareInfo.createWin = win_Register()
  32. shareInfo.createWin.show()
  33. # 保存登录日志
  34. def sava_login_log(self, username):
  35. with open('login_log.txt', 'a', encoding='utf-8') as f:
  36. f.write(username + '\t log in at' + datetime.now().strftimestrftime+ '\r')
  37. # 登录
  38. def onSignIn(self):
  39. print("You pressed sign in")
  40. # 从登陆界面获得输入账户名与密码
  41. username = self.ui_login.edit_username.text().strip()
  42. password = self.ui_login.edit_password.text().strip()
  43. print(username)
  44. print(password)
  45. # 获得账号信息
  46. USER_PWD = get_id_info()
  47. # print(USER_PWD)
  48. if username not in USER_PWD.keys():
  49. replay = QMessageBox.warning(self,"登陆失败!", "账号或密码输入错误", QMessageBox.Yes)
  50. else:
  51. # 若登陆成功,则跳转主界面
  52. if USER_PWD.get(username) == password:
  53. print("Jump to main window")
  54. # 所以使用公用变量名
  55. # shareInfo.mainWin = UI_Logic_Window()
  56. shareInfo.mainWin = Ui_MainWindow()
  57. shareInfo.mainWin.show()
  58. # 关闭当前窗口
  59. self.close()
  60. else:
  61. replay = QMessageBox.warning(self, "!", "账号或密码输入错误", QMessageBox.Yes)
  62. # 注册界面
  63. class win_Register(QMainWindow):
  64. def __init__(self, parent = None):
  65. super(win_Register, self).__init__(parent)
  66. self.ui_register = Ui_Dialog()
  67. self.ui_register.setupUi(self)
  68. self.init_slots()
  69. # 绑定槽信号
  70. def init_slots(self):
  71. self.ui_register.pushButton_regiser.clicked.connect(self.new_account)
  72. self.ui_register.pushButton_cancer.clicked.connect(self.cancel)
  73. # 创建新账户
  74. def new_account(self):
  75. print("Create new account")
  76. USER_PWD = get_id_info()
  77. # print(USER_PWD)
  78. new_username = self.ui_register.edit_username.text().strip()
  79. new_password = self.ui_register.edit_password.text().strip()
  80. # 判断用户名是否为空
  81. if new_username == "":
  82. replay = QMessageBox.warning(self, "!", "账号不准为空", QMessageBox.Yes)
  83. else:
  84. # 判断账号是否存在
  85. if new_username in USER_PWD.keys():
  86. replay = QMessageBox.warning(self, "!", "账号已存在", QMessageBox.Yes)
  87. else:
  88. # 判断密码是否为空
  89. if new_password == "":
  90. replay = QMessageBox.warning(self, "!", "密码不能为空", QMessageBox.Yes)
  91. else:
  92. # 注册成功
  93. print("Successful!")
  94. sava_id_info(new_username, new_password)
  95. replay = QMessageBox.warning(self, "!", "注册成功!", QMessageBox.Yes)
  96. # 关闭界面
  97. self.close()
  98. # 取消注册
  99. def cancel(self):
  100. self.close() # 关闭当前界面
  101. if __name__ == "__main__":
  102. app = QApplication(sys.argv)
  103. # 利用共享变量名来实例化对象
  104. shareInfo.loginWin = win_Login() # 登录界面作为主界面
  105. shareInfo.loginWin.show()
  106. sys.exit(app.exec_())

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/568288
推荐阅读
相关标签
  

闽ICP备14008679号