使用pyqt5搭建yolo3目标识别界面

已有重制版,yolo3检测界面重制版,更简单,完善。

由于这是我第一次写这种博客,其目的也不是为了赚取积分,主要是为了记录我的学习过程中的一些方法,以便以后我再次需要用的时候可以知道我当时是怎么做的。所以文中会有很多地方并不会解释其原理(主要是我自己压根也没搞明白,当时只想知道怎么用就行了,遇到需要用其他的再百度),主要着重于怎么运用。如有不当之处,请指出我当改正。

代码地址:
github:https://github.com/lavenderlove52/YOLOV3-detection-interface-pyqt5
gitee:https://gitee.com/lavenderlove52/YOLOV3-detection-interface-pyqt5

搭建pyqt5环境

我用的IDE是PyCharm,深度学习环境搭建可以参考其他博主的教程。
pyqt5的环境搭建流程参考的是b站up主@刘金玉编程。

  1. 安装Anaconda3,搭建好虚拟环境,在虚拟环境里配置好yolo3所需的库,并在这个虚拟环境里安装pyqt5。

  2. 用win + R打开快速运行,搜索cmd打开命令行窗口。

    打开命令提示符窗口,输入’activate’+空格+所在虚拟环境的名称。然后输入’pip install pyqt5’+回车,就会开始安装pyqt5。

  3. 在PyCharm中配置好pyqt5。首先打开设置,在’External Tool’中添加ptqt5组件。点击 ‘+‘号,

    点击 ‘+‘号,创建工具,工具名字是自己设定的,第一个可以命名为’QTDesinger’,Program路径选择Anaconda安装路径下的’Ananconda3\Library\bin\designer.exe’,因为我是直接装在D盘的,所以完整路径为’D:\Ananconda3\Library\bin\designer.exe’。点击Program这一行末尾的’+‘号即可选择路径。选择好之后,Argument不用填,Working directory会自己填好。

    然后再添加一个工具,名字可以命名为’PyUIC’,Program选择路径为虚拟环境的路径,一般都安装在Ananconda3下的evns文件夹里,下一级文件夹就是虚拟环境的名称,找到你创建的虚拟环境文件夹,在里面找到 python.exe文件,完整路径为’D:\Ananconda3\envs\python3-6\python.exe’,Argument填入

-m PyQt5.uic.pyuic $FileName$ -o $FileNameWithoutExtension$.py

Working directory填入

$FileDir$

完成以上步骤,即可配置好所需工具,开始设计界面了。
可以右键项目名称选择External Tool里的QTDesinger可以直接开始设计界面,最后需要保存在项目根目录里,会生成一个后缀为’ui’的文件,然后右键点击这个文件选择External Tool里的PyUIC即可将其转换为’py’文件,就可以从代码中对界面进行调用和编辑。


我没有从直接设计界面开始,而是从代码中设计界面。

程序流程

主界面

Created with Raphaël 2.3.0开始选择训练模型上传数据集开始训练模型检测退出?结束yesno

子界面

Created with Raphaël 2.3.0检测选择检测模型选择检测图片开始检测退出?结束yesno

设计界面

1.主函数

需要导入以下常用的库:

from PyQt5.QtWidgets import *                    #这两个是pyqt5常用的库
from PyQt5.QtGui import QIcon, QPixmap          #可以满足小白大多数功能
import os                   #这两个是其他的库
import sys                  #可以完成一些打开文件保存文件的功能
from yolov3 import train, predict           #这是我自己将yolov3模型整体放在我项目的子文件夹中,从中调用我的训练和预测函数

下面是主程序:

# 创立一个主界面,并保持它,从各种按钮或者组件中接受信号完成界面功能,相当于无限循环
# 只有选择退出后才会关掉程序退出循环
if __name__ == '__main__':app = QApplication(sys.argv)mc = MyClass()      #这里相当于实例化一个主界面,myclass是自己定义的主界面类sys.exit(app.exec_())        #监听退出,如果选择退出,界面就会关掉

2.定义主界面的类

(1)主界面

首先是初始化,需要继承父类。

class MyClass(QWidget):def __init__(self):super().__init__()     #继承父类self.initUI()          #自己定义的函数,初始化类界面,里面放着自己各种定义的按钮组件及布局self.child_window = ChildClass()       #子界面的调用,本质和主界面一样是一个类,在这里将其声明为主界面的成员

(2)主界面布局

功能实现在代码注释都有详细说明,关于self.TModelSelectSignal = [0, 0]self.TModel= [1, 0],可以理解为一种主界面和子界面的信号传递,由于我对深层次的参数传递不清楚,所以只能采用一种的最笨的方法,在主界面的类里活得已训练好模型的序号,放在数组self.TModel里,数组的第一位为1表示第一个模型已训练,为0表示未训练。同理第二位则表示第二个模型,如果有更多模型,可以设置更多位。数组的设置实在模型训练之后,因此将赋值数组的代码放在训练函数里。

     def initUI(self):self.setWindowTitle("COC缺陷检测")       #设置界面名称# self.setWindowIcon(QIcon("iconimg/zhou.png"))        #设计界面的图标,图片放在项目文件夹的子文件夹里就不会出错,名字也要对应self.resize(350, 200)     #设置界面大小self.TModelSelectSignal = [0, 0]   #选择按钮对应的模型self.TModel= [0, 0]                 #表示已经训练好的模型编号myframe = QFrame(self)      #实例化一个QFrame可以定义一下风格样式,相当于一个框架,可以移动,其内部组件也可以移动btn2 = QPushButton("开始训练模型", self)        #定义一个按钮,括号里需要一个self,如果需要在类内传递,则应该定义为self.btn2btn2.clicked.connect(self.TestModel)  #将点击事件与一个函数相连,clicked表示按钮的点击事件,还有其他的功能函数,后面连接的是一个类内函数,调用时无需加括号btn3 = QPushButton("上传数据集", self)btn3.clicked.connect(self.DataExplorerSelect)   #连接一个选择文件夹的函数btn5 = QPushButton("退出程序", self)btn5.clicked.connect(self.close)  #将按钮与关闭事件相连,这个关闭事件是重写的,它自带一个关闭函数,这里重写为点击关闭之后会弹窗提示是否需要关闭btn6 = QPushButton("检测", self)btn6.clicked.connect(self.show_child) #这里将联系弹出子界面函数,具体弹出方式在函数里说明combol1 = QComboBox(myframe)   #定义为一个下拉框,括号里为这个下拉框从属的骨架(框架)combol1.addItem("                      选择模型")   #添加下拉选项的文本表示,这里因为没有找到文字对齐方式,所以采用直接打空格,网上说文字对齐需要重写展示函数combol1.addItem("                     YOLOv3")combol1.addItem("                     YOLOv4")combol1.activated[str].connect(self.TModelSelect) #|--将选择好的模型序号存到模型选择数组里#|--后面的训练函数会根据这个数组判断需要训练哪个模型#|--[str]表示会将下拉框里的文字随着选择信号传过去#|--activated表示该选项可以被选中并传递信号vlo = QVBoxLayout()  #创建一个垂直布局,需要将需要垂直布局的组件添加进去vlo.addWidget(combol1)    #添加相关组件到垂直布局里vlo.addWidget(btn3)vlo.addWidget(btn2)vlo.addWidget(btn6)vlo.addWidget(btn5)vlo.addStretch(1)  #一个伸缩函数,可以一定程度上防止界面放大之后排版不协调hlo = QVBoxLayout(self) #创建整体框架布局,即主界面的布局hlo.addLayout(vlo)  #将按钮布局添加到主界面的布局之中hlo.addWidget(myframe) #将框架也加入到总体布局中,当然也可以不需要这框架,直接按照整体框架布局来排版#之所以这里有这个myframe,是因为尝试过很多种布局,其中一个布局就是将其他组件都放到这个myframe中,移动这个myframe#其里面的组件布局相对位置不会改变,后面又尝试了多种布局,所以这个myframe最后里面其实就剩下一个下拉框self.show()   #显示主界面

(3)主界面的功能函数(槽函数)

  1. 选择数据上传,其本质是打开一个文件夹,然后将相关照片按照规定排列好。这里采用的是绝对路径,按理来说相对路径较好,但是没有找到具体实现方法,一般的相对路径方法打不开对应的文件夹,所以暂时选择用这个。
 def DataExplorerSelect(self):path = r'D:\pycharm\QTYOLOV3\yolov3\VOCdevkit\VOC2007'os.system("explorer.exe %s" % path)
  1. 打开子界面函数
    def show_child(self):TModel1 = self.TModel                  #|--这是子界面的类内函数self.child_window.GetTModel(TModel1)  #|--将训练好的模型序号传到子界面的类内参数里面self.child_window.show()       #|--子界面相当于主界面的一个类内成员#|--但是本质还是一个界面类,也有show函数将其展示
  1. 选择需要训练的模型序号
    如果这里报错,有可能是下拉框中文本信息与这里的判断文本信息不同。
    def TModelSelect(self, s):       #s是形参,表示传回来的选中的选项的文字if s == '                     YOLOv3':self.TModelSelectSignal[0] = 1        #如果选中的是YOLOv3-COC就将第一位置1# print(self.TModelSelectSignal[0])elif s == '                     YOLOv4':self.TModelSelectSignal[1] = 1      #如果选中的是YOLO-Efficientnet就将第二位置1# print(self.TModelSelectSignal[1])
  1. 训练函数。因为这里只导入一个训练函数,所以只有一个判别选项,训练完之后会将self.TModelSelectSignal的对应位置零以便下一次可以继续训练。
    def TestModel(self):if self.TModelSelectSignal[0] == 1:train.run()self.TModelSelectSignal[0] = 0else:print("没有该模型")
  1. 关闭函数。这里是将其重写,多了一个关闭时会有弹窗出现的功能。前一个文本参数时弹出框的名字,后一个文本参数是显示在窗口的文本。
   def closeEvent(self, event):result = QMessageBox.question(self, "提示:", "您真的要退出程序吗", QMessageBox.Yes|QMessageBox.No, QMessageBox.Yes)if result == QMessageBox.Yes:event.accept()else:event.ignore()

3.定义子界面

(1)子函数

同样需要初始化并继承父类。

class ChildClass(QWidget):def __init__(self):super().__init__()self.initUI()self.TModel = []    #用来接收主界面的训练好的模型的序号self.openfile_name_image = ''  #存储原始图像的地址self.result_name_image = ''        #存储检测好的图像的地址

(2)子界面布局

    def initUI(self):self.resize(1100, 450)  #缩放界面大小self.setWindowTitle("目标检测")    #设置界面标题# self.setWindowIcon(QIcon("iconimg/zhou.png"))        #设置界面图标self.PModelSelectSignal = [0, 0]    #设置需要预测模型的序号,在下拉框里选择myframe = QFrame(self)self.label1 = QLabel("检测模型", self)combol1 = QComboBox(myframe)combol1.addItem("选择检测模型")combol1.addItem("YOLOV3")combol1.addItem("YOLOV4")combol1.activated[str].connect(self.PModelSelect)  #链接预测模型序号选择函数btn1 = QPushButton("选择检测图片", self)btn1.clicked.connect(self.select_image)       #链接检测图片选择函数,本质是打开一个文件夹btn2 = QPushButton("开始检测", self)btn2.clicked.connect(self.PredictModel)     #链接预测模型函数self.label2 = QLabel("", self)          #创建一个label,可以存放文字或者图片,在这里是用来存放图片,文本参数为空就会显示为空,留出空白区域,选择好图片时会有函数展示图片self.label2.resize(400, 400)self.label3 = QLabel("", self)self.label3.resize(400, 400)label4 = QLabel("                                         原始图片", self)        #用来放在图片底部表示这是哪一种图片label5 = QLabel("                                         检测图片", self)vlo2 = QHBoxLayout()        #创建一个子布局,将图片水平排放vlo2.addWidget(label4)vlo2.addWidget(label5)vlo = QHBoxLayout()     #创建一个子布局,将按钮水平排放vlo.addStretch()vlo.addWidget(self.label1)vlo.addWidget(combol1)vlo.addWidget(btn1)vlo.addWidget(btn2)vlo.addStretch(1)vlo1 = QHBoxLayout() #创建一个水平布局,将两个提示标签竖直排放vlo1.addWidget(self.label2)vlo1.addWidget(self.label3)hlo = QVBoxLayout(self)      #创建一个总的垂直布局,将三个子布局垂直排放hlo.addLayout(vlo)hlo.addLayout(vlo1)hlo.addStretch(1)hlo.addLayout(vlo2)hlo.addStretch(0)hlo.addWidget(myframe)

(3)子界面功能函数(槽函数)

  1. 一个赋值函数,在外部调用给类内成员赋值
    def GetTModel(self, a):self.TModel = a
  1. 关闭事件,和主界面一样是重写之后的。
    def closeEvent(self, event):result = QMessageBox.question(self, "提示:", "您真的要退出程序吗", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)if result == QMessageBox.Yes:event.accept()else:event.ignore()
    def select_image(self):self.openfile_name_image, _ = QFileDialog.getOpenFileName(self, "选择照片文件",r"./yolov3/imgtest/")#弹出一个对话窗,是一个文件夹,可以选择一个文件然后返回地址到 self.openfile_name_image中print('加载照片文件地址为:' + str(self.openfile_name_image))self.label2.setPixmap(QPixmap(str(self.openfile_name_image))) #将选中的文件名字传入QPixmap()中,括号内为文件地址,就会读取这个图片self.label2.resize(300, 400)self.label2.setScaledContents(True)   #表示这个label可以可以自适应窗口大小,可以让图片随窗口大小而变化
  1. 选择需要预测的模型,s是形参,传回的是下拉框中的文本信息。
   def PModelSelect(self, s):if s == 'YOLOV3':if self.TModel[0] == 1:self.PModelSelectSignal[0] = 1self.PModelSelectSignal[1] = 0print(self.PModelSelectSignal[0])else:print("模型YOLOV3未训练")    ##如果已经训练好的模型数组里对应的位置为0,则表示该模型未训练self.PModelSelectSignal[1] = 0      #同时也要讲模型选择信号清零,以便下次可以继续选择赋值elif s == 'YOLOV4':if self.TModel[1] == 1:self.PModelSelectSignal[1] = 1self.PModelSelectSignal[0] = 0print(self.PModelSelectSignal[1])else:print("模型YOLOV4未训练")self.PModelSelectSignal[0] = 0
  1. 图像预测。由于只导入了一个模型,所以只有一个判别程序,我写的预测函数是可以读取文件路径的图片,所以我只需将需要预测的图片的路径传入预测函数,就会将预测好的图片保存在指定文件夹,然后后面用程序将其读出展示在界面里。
   def PredictModel(self):if self.PModelSelectSignal[0] == 1:predict.predict(self.openfile_name_image) #将需要预测的图片传入导入的预测函数elif self.PModelSelectSignal[1] == 1:print('YOLOV4正在检测')  #这里应该放入另外一个模型else:print('没有该模型')a = self.openfile_name_imagea = a.split('/')  #将预测图片里的编号分离出来a = './yolov3/imgtestresult/' + a[-1] #将指定路径与图片编号组合,即可得到预测好的图片的路径self.label3.setPixmap(QPixmap(a)) #直接读取预测好的图片self.label3.resize(300, 400)self.label3.setScaledContents(True)print(a)

界面展示


一些尚未解决的问题

由于保存图片路径变量覆盖的问题,会导致选择第二张检测图片之后,检测图片的结果仍然展示的是第一张,可以在选择检测图片的函数里加上每当选择一张新的图片,即可清除上一张图片。
另外一个问题就是无法连续两次检测,具体原因还没有查明,可能是用的同一个保存图片文件的变量,最后并没有传入预测函数。
另外一个还没有实现的功能就是实时展示训练进程,在原始训练函数里,是会实时打印出训练进程,所以应该可以做到读取训练函数里的打印的文本,然后传递到界面类里的一个函数,然后展示在界面里。

学习记录01:使用pyqt5搭建yolo3目标识别界面相关推荐

  1. 【ArcGIS学习记录01】--利用CRU TS数据集绘制降雨量分布图

    [ArcGIS学习记录01]–利用CRU TS数据集绘制降雨量分布图 注:仅作为本人的学习记录方便以后复习查阅. 一.介绍 CRU TS 是目前使用最广泛的气候数据集之一,由英国国家大气科学中心 (N ...

  2. JavaScript学习记录01快速入门、基本语法、严格检查模式

    文章目录 JavaScript学习记录01快速入门.基本语法.严格检查模式 1.1什么是JavaScript 1.2认识JavaScript框架 1.3快速入门 1.4基本语法入门 1.5数据类型简介 ...

  3. java开源项目之IQQ学习记录之项目环境搭建与启动

    本文链接地址:http://blog.csdn.net/sushengmiyan/article/details/18779727 作者:sushengmiyan 现在就码字说说今天晚上搞定的一个项目 ...

  4. jadx学习记录01

    原计划是先学习 okHttp 和拦截器,再用 Android Studio 来 demo 下,奈何 Android Studio 装完 sync 一直失败,后续换个电脑再试下.一并整理 okHttp ...

  5. echarts引入geo地图数据,前端学习记录01

    最近遇到项目需要使用使用geoJson数据在echarts上进行地图的绘制,仅使用此文记录学习的过程. 首先需要在项目中引入echart相关依赖,在package.json中添加如下依赖: " ...

  6. 【C语言学习记录01】使用递归实现十进制转二进制

    前言 我本人也在慢慢学习C语言,看的是C Primer Plus这本书,为了激励自己学习下去,所以会慢慢发分享一些学习心得,也当是记录一下吧,以后也好回顾回顾,本人很菜,高手们不要嘲笑,有问题欢迎指点 ...

  7. Dart学习笔记01:环境搭建与开发环境配置

    文章目录 一.Dart概述 二.下载Dart for Windows 三.安装Dart for Windows 四.命令行方式安装Dart (一)安装Chocolatey 1.启动PowerShell ...

  8. Linux学习记录-01(Linux系统发展史)

    对计算机一直感觉很神秘,想要学习,奈何不是计算机专业出身,最近决定开始学习,也算是充实一下自己,希望自己可以坚持下去. 一.Linux系统 Linux是一套免费使用和自由传播的类Unix操作系统,是一 ...

  9. 【品优购电商学习记录01】工程结构

    不依赖service 远程调用     cart order 商家管理后台 运营商管理后台 数据库 框架搭建:

最新文章

  1. Android 接口回调
  2. Web登录很简单?开玩笑!
  3. 关闭linux服务器电源,linux关闭ACPI电源管理模块
  4. KMP算法的实现以及改进
  5. node.js初步探究
  6. 服务器安装红帽系统进入不图形界面,CentOS 安装图形化界面方法
  7. NYOJ90 整数划分(经典递归和dp)
  8. [html] 说说你对H5的SharedWorker的理解,它有什么运用场景?
  9. 前端学习(2466):在前端页面中引入百度地图
  10. 【转】TFS上分支和标签的用法
  11. 基于Opencv--图像上采样
  12. CSS3(七) 前端预处理技术(Less、Sass、CoffeeScript)
  13. 虚拟货币公有链项目集体爆发,AE超过历史最高点
  14. 【渝粤题库】陕西师范大学800009 环境变迁
  15. 大道至简-第一张 伪代码
  16. 20191201每日一句
  17. 如何优雅的给你的APK文件打上签名
  18. (附源码)springboot宠物管理系统 毕业设计 121654
  19. Senparc.Weixin.MP SDK 微信公众平台开发教程(一):微信公众平台注册
  20. 几万网友选出的坑爹景点,你可别再去了

热门文章

  1. NPOI合并单元格后边框显示不正确?
  2. GNURadio中的PMTs(Polymorphic Types)数据类型
  3. 谷歌、三星、腾讯...全球上市公司巨头投资了哪些区块链项目?
  4. python通达信股票分价表数据_通达信指标——分价图(主图)
  5. wamp环境下如何安装composer?
  6. 聊聊后台5种常见的几种布局
  7. 关于虚拟机镜像无法检测
  8. python pickle反序列化漏洞_Python反序列化漏洞
  9. 为什么非常想要一样东西的时候却得不到,但慢慢就不想要了?
  10. L1006 连续因子