YOLOv5实战记录05 Pyside6可视化界面

个人打卡,慎看。

指路大佬:【手把手带你实战YOLOv5-入门篇】YOLOv5 Pyside6可视化界面_哔哩哔哩_bilibili

零、虚拟环境迁移路径后pip报错解决

yolov5-master文件夹我换位置后,无法pip install了。解决如下:

  • activate.bat中修改:@set "VIRTUAL_ENV=D:\yolov5-master\venv"
  • activate中修改:VIRTUAL_ENV='D:\yolov5-master\venv'
  • 更新pip:python -m pip install --upgrade pip

参考:Python 虚拟环境迁移路径后pip报错解决记录_pybot移动路径后-CSDN博客

 

【建议挂v,速度会快】

一、环境安装

  • 下载Pyside6:  pip install pyside6

我的pyside6不在Python.exe的上级文件夹的子目录下,packages和python.exe的位置也不同,发现解释器的位置设置错了,之前一直提示我Invalid,我也没有注意。

一般python.exe和site-packages的位置关系是,python.exe和它的上级在同一文件夹下。

比如anaconda下python.exe, lib

lib下site-packages ,也可以输入以下命令,查找site-packages的位置。

import site
print(site.getsitepackages())

以后安装了包,但是无法import,也可以查找site-packages的位置,很有可能这里面没有那个包。是python.exe选取的错误,修改为对应的python.exe即可。

  • 找到pyside6/designer.exe,将快捷方式发送到桌面。
  • up主用vscode安装了qt for python插件,但是我使用的是Pycharm,vscode不熟练,在pycharm中,设置setting->tools->external tools,点击+ ,添加,在Program中,输入designer.exe的位置。name和group随便设置,点击ok。

二、设计UI

  1. 新建mainwindow
  2. 把两个textlabel拖到mainwindow中【存放图片】,用vertical line隔离他们。拖两个pushbutton【按钮】。
  3. 勾选scaledcontents可以实现label中存放内容缩放。将alignment设置水平中心对齐。
  4. 修改对象的名字,便于记忆。比如label1改成input
  5. 保存到yolov5-master文件夹下,修改名字为main_window

三、将ui转换成py

添加external tool

我的血泪教训,改这个错改了40min:

  1. program不要选site-packages\Pyside6\uic.exe 这样转换出来的结果可能是C++代码。
  2. 选\Scripts\pyside6-uic.exe这个文件

  • Program: D:\anaconda\Scripts\pyside6-uic.exe 【输入自己的pyside6-uic.exe文件路径】
  • Arguments: $FileName$ -o $FileNameWithoutExtension$.py
  • working directory: $FileDir$

四、调用mainwindow

import sysfrom PySide6.QtWidgets import QMainWindow, QApplicationfrom main_window import Ui_MainWindow
#这里的main_window是你的ui转换成的py名字
#Ui_MainWindow是main_window里的class名字class MainWindow(QMainWindow,Ui_MainWindow):def __init__(self):super(MainWindow,self).__init__()   #self后不要加(),我加了()报错无法调用mainwindowself.setupUi(self)if __name__=="__main__":app=QApplication(sys.argv)window1 = MainWindow()window1.show()app.exec()

运行上面的指令即可弹出UI设计界面。

五、关联按钮和代码

bing_slots()函数负责绑定。det_image和pushButton_2【忘改了】是那两个按钮的名字。

import sysfrom PySide6.QtWidgets import QMainWindow, QApplication,QFileDialog
#QFileDialog可以访问文件资源管理器from main_window import Ui_MainWindowclass MainWindow(QMainWindow,Ui_MainWindow):def __init__(self):super(MainWindow,self).__init__()self.setupUi(self)self.bind_slots()  #不要忘记调用,不写这句话无法显示。def open_image(self):print("点击显示图片!")def open_video(self):print("点击显示视频!")def bind_slots(self):#绑定self.det_image.clicked.connect(self.open_image)self.pushButton_2.clicked.connect(self.open_video)if __name__=="__main__":app=QApplication(sys.argv)window1 = MainWindow()window1.show()app.exec()

六、获取图片

  • 一开始无法显示,我设置QPixmap("./datasets/images/train/30.jpg")发现可以显示,于是判断是filepath格式的问题;
  • QPixmap的参数是string类型的。打印file_path[0]发现打印出来的仍然是list格式。
  • 于是转换list为string类型。filePath=','.join(file_path[0])
#与上个代码省略了相同的部分,方便理解。from PySide6.QtGui import QPixmap
#显示图片def open_image(self):file_path=QFileDialog.getOpenFileNames(self,dir="./datasets/images/train",filter="*.jpg;*.png")#设置从dir里找图片, filter分号隔离不同格式#file_path返回的是有两个元素的数组,我们运行后,发现第一个元素是路径,第二个元素是格式。我们只输出路径。if file_path[0]:filePath=','.join(file_path[0])print(file_path[0])print(filePath)self.input.setPixmap(QPixmap(filePath))  #图片显示

七、训练图片

  • 首先,遇到了问题,我运行页面卡住了,一直在下载某个包,经查找,发现是下面这行代码的问题。我运行提示卡在了“'Downloading torch-2.2.2-cp310-cp310-win_amd64.whl (198.6 MB)”,
  • model = torch.hub.load("./","custom",path="runs/train/exp2/weights/best.pt",trust_repo=True, source="local") 运行这行代码时卡住了,其他代码不会卡。
  • 已解决:下载几个包即可:pip install torch torchvision torchaudio
  • 参考:通过pip安装pytorch超时问题解决 - 知乎 (zhihu.com)

运行代码:

import sys
import torch
from PySide6.QtWidgets import QMainWindow, QApplication,QFileDialog
#QFileDialog可以访问文件资源管理器from PySide6.QtGui import QPixmap,QImage
#显示图片from main_window import Ui_MainWindowdef convert2QImage(img):height,width,channel=img.shapereturn QImage(img,width,height,width*channel,QImage.Format_RGB888)class MainWindow(QMainWindow,Ui_MainWindow):def __init__(self):super(MainWindow,self).__init__()self.setupUi(self)self.model=torch.hub.load("./","custom",path="runs/train/exp2/weights/best.pt",source="local")self.bind_slots()  #不要忘记调用,不写这句话无法显示def image_pred(self,filePath):results=self.model(filePath)image=results.render()[0]return convert2QImage(image)#检测后的图片def open_image(self):file_path=QFileDialog.getOpenFileNames(self,dir="./datasets/images/train",filter="*.jpg;*.png")#设置从dir里找图片, filter分号隔离不同格式#file_path返回的是有两个元素的数组,我们运行后,发现第一个元素是路径,第二个元素是格式。我们只输出路径。if file_path[0]:filePath=','.join(file_path[0])qimage=self.image_pred(filePath)self.input.setPixmap(QPixmap(filePath))self.output.setPixmap(QPixmap.fromImage(qimage))def open_video(self):print("点击显示视频!")def bind_slots(self):#绑定self.det_image.clicked.connect(self.open_image)self.pushButton_2.clicked.connect(self.open_video)if __name__=="__main__":app=QApplication(sys.argv)window1 = MainWindow()window1.show()app.exec()

八、训练视频

仍然遇到了报错:Traceback (most recent call last):
  File "D:\yolov5-master\yolov5-master\base_ui.py", line 57, in open_video
    self.input.setPixmap(QPixmap(convert2QImage(filePath)))
  File "D:\yolov5-master\yolov5-master\base_ui.py", line 13, in convert2QImage
    height,width,channel=imag.shape
AttributeError: 'str' object has no attribute 'shape'

但是我训练图片时, height,width,channel=imag.shape这行代码就没有出现问题,于是查找包含改行代码的函数调用的参数,果然写错了self.input.setPixmap(QPixmap(convert2QImage(frame)))是frame不是filePath。 一定要细心!!!

import sys
import cv2
import torch
from PySide6.QtWidgets import QMainWindow, QApplication,QFileDialog
#QFileDialog可以访问文件资源管理器from PySide6.QtGui import QPixmap,QImage
#显示图片from main_window import Ui_MainWindowdef convert2QImage(imag):height,width,channel=imag.shapereturn QImage(imag,width,height,width*channel,QImage.Format_RGB888)class MainWindow(QMainWindow,Ui_MainWindow):def __init__(self):super(MainWindow,self).__init__()self.setupUi(self)self.model=torch.hub.load("./","custom",path="runs/train/exp2/weights/best.pt",source="local")self.bind_slots()  #不要忘记调用,不写这句话无法显示def image_pred(self,filePath):results=self.model(filePath)image=results.render()[0]return convert2QImage(image)#检测后的图片def video_pred(self,img):results=self.model(img)image=results.render()[0]return convert2QImage(image)def open_image(self):file_path=QFileDialog.getOpenFileNames(self,dir="./datasets/images/train",filter="*.jpg;*.png")#设置从dir里找图片, filter分号隔离不同格式#file_path返回的是有两个元素的数组,我们运行后,发现第一个元素是路径,第二个元素是格式。我们只输出路径。if file_path[0]:filePath=','.join(file_path[0])qimage=self.image_pred(filePath)self.input.setPixmap(QPixmap(filePath))self.output.setPixmap(QPixmap.fromImage(qimage))def open_video(self):#视频检测是一帧一帧地检测,利用opencv抽帧。file_path = QFileDialog.getOpenFileNames(self, dir="./datasets", filter="*.mp4")if file_path[0]:filePath=','.join(file_path[0])print(filePath)video = cv2.VideoCapture(filePath)while True:ret,frame=video.read()if not ret:breakframe = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)qimage=self.video_pred(frame)self.input.setPixmap(QPixmap(convert2QImage(frame)))self.output.setPixmap(QPixmap.fromImage(qimage))print("点击显示视频!")def bind_slots(self):#绑定self.det_image.clicked.connect(self.open_image)self.pushButton_2.clicked.connect(self.open_video)if __name__=="__main__":app=QApplication(sys.argv)window1 = MainWindow()window1.show()app.exec()

不过我运行后很慢,并且只显示了视频最后一帧的检测结果和原图片。

问题:界面刷新不及时。

解决:加入计时器from PySide6.QtCore import QTimer
 

import sys
import cv2
import torch
from PySide6.QtWidgets import QMainWindow, QApplication,QFileDialog
#QFileDialog可以访问文件资源管理器from PySide6.QtGui import QPixmap,QImage
#显示图片
from PySide6.QtCore import QTimer
#计时器from main_window import Ui_MainWindowdef convert2QImage(imag):height,width,channel=imag.shapereturn QImage(imag,width,height,width*channel,QImage.Format_RGB888)class MainWindow(QMainWindow,Ui_MainWindow):def __init__(self):super(MainWindow,self).__init__()self.setupUi(self)self.model=torch.hub.load("./","custom",path="runs/train/exp2/weights/best.pt",source="local")self.timer=QTimer()self.timer.setInterval(100) #时间间隔。默认单位毫秒ms ,可以设置的小一点儿,视频更加丝滑。self.bind_slots()  #不要忘记调用,不写这句话无法显示def image_pred(self,filePath):results=self.model(filePath)image=results.render()[0]return convert2QImage(image)#检测后的图片def video_pred(self):ret, frame = self.video.read()if not ret:self.timer.stop()else:frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)self.input.setPixmap(QPixmap.fromImage(convert2QImage(frame)))#放在这儿而不是self.output上面,因为可能受检测的图像影响。在检测之前先显示出来。results=self.model(frame)image=results.render()[0]self.output.setPixmap(QPixmap.fromImage(convert2QImage(image)))def open_image(self):file_path=QFileDialog.getOpenFileNames(self,dir="./datasets/images/train",filter="*.jpg;*.png")#设置从dir里找图片, filter分号隔离不同格式#file_path返回的是有两个元素的数组,我们运行后,发现第一个元素是路径,第二个元素是格式。我们只输出路径。if file_path[0]:filePath=','.join(file_path[0])qimage=self.image_pred(filePath)self.input.setPixmap(QPixmap(filePath))self.output.setPixmap(QPixmap.fromImage(qimage))def open_video(self):#视频检测是一帧一帧地检测,利用opencv抽帧。file_path = QFileDialog.getOpenFileNames(self, dir="./datasets", filter="*.mp4")if file_path[0]:filePath=','.join(file_path[0])print(filePath)self.video = cv2.VideoCapture(filePath)self.timer.start()# while True:#     ret,frame=video.read()##     if not ret:#         break#     frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)#     qimage=self.video_pred(frame)#     self.input.setPixmap(QPixmap(convert2QImage(frame)))#     self.output.setPixmap(QPixmap.fromImage(qimage))print("点击显示视频!")def bind_slots(self):#绑定self.det_image.clicked.connect(self.open_image)self.pushButton_2.clicked.connect(self.open_video)self.timer.timeout.connect(self.video_pred)if __name__=="__main__":app=QApplication(sys.argv)window1 = MainWindow()window1.show()app.exec()

仍然存在问题,如果再点击“图片检测”按钮,不会停下,这是因为计时器没有停。

解决方案:在打开图片时,关闭计时器,def open_image(self): self.timer.stop()

全部代码:

import sys
import cv2
import torch
from PySide6.QtWidgets import QMainWindow, QApplication,QFileDialog
#QFileDialog可以访问文件资源管理器from PySide6.QtGui import QPixmap,QImage
#显示图片
from PySide6.QtCore import QTimer
#计时器from main_window import Ui_MainWindowdef convert2QImage(imag):height,width,channel=imag.shapereturn QImage(imag,width,height,width*channel,QImage.Format_RGB888)class MainWindow(QMainWindow,Ui_MainWindow):def __init__(self):super(MainWindow,self).__init__()self.setupUi(self)self.model=torch.hub.load("./","custom",path="runs/train/exp2/weights/best.pt",source="local")self.timer=QTimer()self.timer.setInterval(1) #默认单位毫秒msself.bind_slots()  #不要忘记调用,不写这句话无法显示def image_pred(self,filePath):results=self.model(filePath)image=results.render()[0]return convert2QImage(image)#检测后的图片def video_pred(self):ret, frame = self.video.read()if not ret:self.timer.stop()else:frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)self.input.setPixmap(QPixmap.fromImage(convert2QImage(frame)))# 放在这儿而不是self.output上面,因为可能受检测的图像影响。在检测之前先显示出来。results=self.model(frame)image=results.render()[0]self.output.setPixmap(QPixmap.fromImage(convert2QImage(image)))def open_image(self):self.timer.stop()file_path=QFileDialog.getOpenFileNames(self,dir="./datasets/images/train",filter="*.jpg;*.png")#设置从dir里找图片, filter分号隔离不同格式#file_path返回的是有两个元素的数组,我们运行后,发现第一个元素是路径,第二个元素是格式。我们只输出路径。if file_path[0]:filePath=','.join(file_path[0])qimage=self.video_pred(filePath)self.input.setPixmap(QPixmap(filePath))self.output.setPixmap(QPixmap.fromImage(qimage))def open_video(self):#视频检测是一帧一帧地检测,利用opencv抽帧。file_path = QFileDialog.getOpenFileNames(self, dir="./datasets", filter="*.mp4")if file_path[0]:filePath=','.join(file_path[0])print(filePath)self.video = cv2.VideoCapture(filePath)self.timer.start()# while True:#     ret,frame=video.read()##     if not ret:#         break#     frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)#     qimage=self.video_pred(frame)#     self.input.setPixmap(QPixmap(convert2QImage(frame)))#     self.output.setPixmap(QPixmap.fromImage(qimage))print("点击显示视频!")def bind_slots(self):#绑定self.det_image.clicked.connect(self.open_image)self.pushButton_2.clicked.connect(self.open_video)self.timer.timeout.connect(self.video_pred)if __name__=="__main__":app=QApplication(sys.argv)window1 = MainWindow()window1.show()app.exec()

九、复盘

  1. 首先利用Pyside6的designer设计了UI界面。两个button,两个label,一条线。导出生成ui文件。将ui文件编译生成成py文件,注意external tool选的是pyside6-uic.exe,不是uic.exe!!!
  2. 构建程序,设计函数:初始化;绑定按键与函数事件;打开图片;打开视频;图片预测;视频预测【预测部分利用了torch.hub,实际上是对每一帧的图片进行预测,利用了计时器】


今天最大的收获就是可以平静地对待报错了,之前从大一开始每次改报错都特别烦躁,今天竟然可以平静地坐着改几个小时的bug。我之前特别怵头以后做机器学习、python相关的研究,现在不怕了。

要相信你遇到的问题,别人也遇到过,并且他们解决了。

如果别人没有遇到过,那正好,你会是第一个发现问题并解决的人,之后的人都会借鉴你的解决方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/796342.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET8 和 Vue.js 的前后端分离

在.NET 8中实现前后端分离主要涉及到两个部分:后端API的开发和前端应用的开发。后端API通常使用ASP.NET Core来构建,而前端应用则可以使用任何前端框架或技术栈,比如Vue.js、React或Angular等。下面是一个简化的步骤指南,帮助你在…

汇川PLC学习Day4:电机参数和气缸控制参数

汇川PLC学习Day4:伺服电机参数和气缸控制参数 一、伺服电机参数二、气缸参数1. 输入IO映射(1)输入IO映射(2) 输入IO触摸屏标签显示映射 2. 输出IO映射(1)输出IO映射(2) …

基于单片机电动车电压电流监测系统

**单片机设计介绍,基于单片机电动车电压电流监测系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的电动车电压电流监测系统是一个集成了电子技术、单片机编程以及电压电流测量技术的系统。其主要目的是…

Open3D (C++) 从.txt文件中读取数据到矩阵

目录 一、算法概述二、代码实现三、结果展示四、测试数据本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法概述 在进行实验的时候有时需要借助不同的工具来实现一些比较复杂的操作,比如使用matlab中自带的拉…

lua学习笔记4(运算符的学习)

print("*****************************lua运算符的学习*******************************") print("*****************************基本运算符*******************************") a1145 b8848 print("加法运算"..ab) print("减法运算".…

Spark-Scala语言实战(14)

在之前的文章中,我们学习了如何在spark中使用键值对中的fullOuterJoin,zip,combineByKey三种方法。想了解的朋友可以查看这篇文章。同时,希望我的文章能帮助到你,如果觉得我的文章写的不错,请留下你宝贵的点…

考研高数(平面图形的面积,旋转体的体积)

1.平面图形的面积 纠正:参数方程求面积 2.旋转体的体积(做题时,若以x为自变量不好计算,可以求反函数,y为自变量进行计算)

【STL学习】(3)vector容器

前言 本章主要内容为两个部分: vector是什么?vector常用接口的使用。 一、vector的介绍 vector是表示可变大小数组的容器就像数组一样,vector也采用的连续空间来存储元素。也意味着可以采用下标对vector的元素进行访问,和数组一样…

【二分查找】Leetcode 在排序数组中查找元素的第一个和最后一个位置

题目解析 34. 在排序数组中查找元素的第一个和最后一个位置 我们使用暴力方法进行算法演化,寻找一个数字的区间,我们可以顺序查找,记录最终结果 首先数组是有序的,所以使用二分法很好上手,但是我们就仅仅使用上一道题…

C++的并发世界(七)——互斥锁

0.死锁的由来 假设有两个线程T1和T2,它们需要对两个互斥量mtx1和mtx2进行访问。而且需要按照以下顺序获取互斥量的所有权: -T1先获取mte1的所有权,再获取mt2的所有权。 -T2先获取 mtx2的所有权。再铁取 mtx1的所有权。 如果两个线程同时执行&#xff0c…

C++入门语法(命名空间缺省函数函数重载引用内联函数nullptr)

目录 前言 1. 什么是C 2. C关键字 3. 命名空间 3.1 命名空间的定义 3.2 命名空间的使用 4. C输入和输出 5. 缺省函数 5.1 概念 5.2 缺省参数分类 6. 函数重载 6.1 概念 6.2 为何C支持函数重载 7. 引用 7.1 概念 7.2 特性 7.3 常引用 7.4 引用与指针的区别 7…

Node.JS多线程PromisePool之promise-pool库实现

什么是Promise Pool Map-like, concurrent promise processing for Node.js. Promise-Pool是一个用于管理并发请求的JavaScript库,它可以限制同时进行的请求数量,以避免过多的请求导致服务器压力过大。使用Promise-Pool可以方便地实现对多个异步操作的并…

pandas用法-详解教程

pandas用法-详解教程 一、生成数据表二、数据表信息查看三、数据表清洗四、数据预处理五、数据提取六、数据筛选七、数据汇总八、数据统计九、数据输出 一、生成数据表 1、首先导入pandas库,一般都会用到numpy库,所以我们先导入备用: impor…

Vue3 项目实例(二)vite.config.ts的配置与axios安装

一、vite.config.ts的配置 1、对相对路径的处理() import { defineConfig } from vite import vue from vitejs/plugin-vue // vite 提供node核心对象path import path from path // https://vitejs.dev/config/ export default defineConfig({plugins…

计算机网络 实验指导 实验12

路由信息协议(RIP)实验 1.实验拓扑图 名称接口IP地址网关Switch AF0/1192.168.1.1/24F0/2172.1.1.1/24Switch BF0/1192.168.1.2/24F0/2172.2.2.1/24PC1172.1.1.2/24172.1.1.1PC2172.1.1.3/24172.1.1.1PC3172.2.2.2/24172.2.2.1PC4172.2.2.3/24172.2.2.1…

Linux——进程管理

1.gcc与g区别(补充了解) 比如有两个文件:main.c,mainc.cpp(分别用C语言和C语言写的)如果要用gcc编译呢? gcc -o mainc main.c gcc -o mainc mainc.cpp -lstdc 指明用c的标准库; 区别一: gcc默认只链接C库,并不会链接C的库;g会默认链接c标准库. 区别二: gcc编译.c文件,则按照C语…

NLP 在搜索引擎优化上做的工作

自然语言处理(NLP)在搜索引擎优化上的工作主要集中在提升搜索结果的相关性和准确性,以及改善用户的搜索体验。以下是NLP在搜索引擎优化中所做工作的详细介绍: 1. 理解用户查询意图【4】 NLP技术可以帮助搜索引擎更好地理解用户的…

Unity和Android的交互

Unity和Android的交互 一、前言二、Android导出jar/aar包到Unity2.1 版本说明2.2 拷贝Unity的classes.jar给Android工程2.2.1 classes.jar的位置2.2.2 Android Studio创建module2.2.3 拷贝classes.jar 到 Android工程并启用 2.3 编写Android工程代码2.3.1 创建 MainActivity2.…

开源 _ 新一代Android 性能监控框架Rabbit

最终扫描结果会展示如下: 点击右上角导出按钮可以把扫描结果以json的形式导出到SD卡中。 网络日志监控 rabbit可以记录网络请求日志并方便的查看返回的json数据: 卡顿日志监控 rabbit通过Choreographer来检测主线程的运行情况,并异步采集主线程堆栈来还原卡顿现场。 对于下…

自动驾驶汽车关键技术_感知

自动驾驶汽车关键技术|感知 附赠自动驾驶学习资料和量产经验:链接 两套标准 分别由美国交通部下属的国家高速路安全管理局(NationalHighwayTraffic Safety Administration ,NHSTA) 和国际汽车工程师协会(Societyof Automotive Engineers&am…