使用Pyqt5 制作一个界面,并连接摄像头
前言承接上回,我们把环境装好啦,那么接下来就要开始我们的UI啦,预计完成连接摄像的内容
项目要求——自己想的
主要用python语言开发能够显示摄像头的内容能够显示识别内容的列表能够进行计价那我们就开始新的记录吧
第一步 设计UI界面我就随手画了一个
第二步 python连接摄像头因为我的是虚拟机,所以我首先要把我的摄像头连接到虚拟机上,因为我的是usb摄像头,所以要把对应的服务打开,如下图
然后我们来连一下
安装一下我们需要的OpenCV库
#激活虚拟环境conda activate yolo#更新pippython3 -m pip install --upgrade pip#安装opencv库 该版本是适用于我的pyqt5的pip3 install opencv-python==4.3.0.36
这样我们需要的库就安装完成了(我这里出现了问题:我安装好后,我的vscode没有检测到,后来我重启vscode后,就检测到了,所以如果遇到同样的问题,我建议重启一下软件,但是首先要看看自己到底有没有安装成功)
重启后,引用库就是蓝绿色的,说明vscode检测到了这几个库
然后我们来测试一下,摄像头到底有没有连上
我复制黏贴了该博客的代码,进行的测试
python3+pyqt5+pycharm 打开摄像头显示_ZJE-CSDN博客_pyqt5 打开摄像头
from PyQt5 import QtCore,QtGui,QtWidgetsimport sysimport cv2import numpy as np class Ui_MainWindow(QtWidgets.QWidget): def __init__(self,parent=None): super().__init__(parent) #父类的构造函数 self.timer_camera = QtCore.QTimer() #定义定时器,用于控制显示视频的帧率 self.cap = cv2.VideoCapture() #视频流 self.CAM_NUM = 0 #为0时表示视频流来自笔记本内置摄像头 self.set_ui() #初始化程序界面 self.slot_init() #初始化槽函数 '''程序界面布局''' def set_ui(self): self.__layout_main = QtWidgets.QHBoxLayout() #总布局 self.__layout_fun_button = QtWidgets.QVBoxLayout() #按键布局 self.__layout_data_show = QtWidgets.QVBoxLayout() #数据(视频)显示布局 self.button_open_camera = QtWidgets.QPushButton('打开相机') #建立用于打开摄像头的按键 self.button_close = QtWidgets.QPushButton('退出') #建立用于退出程序的按键 self.button_open_camera.setMinimumHeight(50) #设置按键大小 self.button_close.setMinimumHeight(50) self.button_close.move(10,100) #移动按键 '''信息显示''' self.label_show_camera = QtWidgets.QLabel() #定义显示视频的Label self.label_show_camera.setFixedSize(641,481) #给显示视频的Label设置大小为641x481 '''把按键加入到按键布局中''' self.__layout_fun_button.addWidget(self.button_open_camera) #把打开摄像头的按键放到按键布局中 self.__layout_fun_button.addWidget(self.button_close) #把退出程序的按键放到按键布局中 '''把某些控件加入到总布局中''' self.__layout_main.addLayout(self.__layout_fun_button) #把按键布局加入到总布局中 self.__layout_main.addWidget(self.label_show_camera) #把用于显示视频的Label加入到总布局中 '''总布局布置好后就可以把总布局作为参数传入下面函数''' self.setLayout(self.__layout_main) #到这步才会显示所有控件 '''初始化所有槽函数''' def slot_init(self): self.button_open_camera.clicked.connect(self.button_open_camera_clicked) #若该按键被点击,则调用button_open_camera_clicked() self.timer_camera.timeout.connect(self.show_camera) #若定时器结束,则调用show_camera() self.button_close.clicked.connect(self.close)#若该按键被点击,则调用close(),注意这个close是父类QtWidgets.QWidget自带的,会关闭程序 '''槽函数之一''' def button_open_camera_clicked(self): if self.timer_camera.isActive() == False: #若定时器未启动 flag = self.cap.open(self.CAM_NUM) #参数是0,表示打开笔记本的内置摄像头,参数是视频文件路径则打开视频 if flag == False: #flag表示open()成不成功 msg = QtWidgets.QMessageBox.warning(self,'warning',"请检查相机于电脑是否连接正确",buttons=QtWidgets.QMessageBox.Ok) else: self.timer_camera.start(30) #定时器开始计时30ms,结果是每过30ms从摄像头中取一帧显示 self.button_open_camera.setText('关闭相机') else: self.timer_camera.stop() #关闭定时器 self.cap.release() #释放视频流 self.label_show_camera.clear() #清空视频显示区域 self.button_open_camera.setText('打开相机') def show_camera(self): flag,self.image = self.cap.read() #从视频流中读取 show = cv2.resize(self.image,(640,480)) #把读到的帧的大小重新设置为 640x480 show = cv2.cvtColor(show,cv2.COLOR_BGR2RGB) #视频色彩转换回RGB,这样才是现实的颜色 showImage = QtGui.QImage(show.data,show.shape[1],show.shape[0],QtGui.QImage.Format_RGB888) #把读取到的视频数据变成QImage形式 self.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage)) #往显示视频的Label里 显示QImageif __name__ =='__main__': app = QtWidgets.QApplication(sys.argv) #固定的,表示程序应用 ui = Ui_MainWindow() #实例化Ui_MainWindow ui.show() #调用ui的show()以显示。同样show()是源于父类QtWidgets.QWidget的 sys.exit(app.exec_()) #不加这句,程序界面会一闪而过
然后就成功啦,还是很开心哒( * ▽ *)
问题
点击启动,发现有报错,提示已放弃(核心已转储),我就参考了这篇博客,将opencv降版本,如果该版本还是报错,那就再把版本降低
(38条消息) Uuntu20.04出现“qt.qpa.plugin: Could not load the Qt platform plugin “xcb“ in…已放弃 (核心已转储)”问题解决记录_消灭BUG鸭的博客-CSDN博客
还有一个问题是,我第一次运行的时候,上面的这个界面是很卡,而且打开相机发现直接无响应。我以为有错误,但是我第二遍运行的时候,就成功了,所以第一次不成功的话,就看看运行第二次有没有问题,有问题再看报错。
同时这个需要检测你的摄像头,如果打开摄像头,提示找不到摄像头,就需要你去修改一下你的摄像头的编号。就是下面注释的地方。至于这个编号怎么改,可以一个一个试,也可以去搜一下如何查看摄像头编号(我默认的这个0是可以的)(可以自己搜一下如何查看摄像头编号)
第三步 设计界面 完成功能首先,我们把上面复制的代码自己学习解读一下,好方便我们接下来自己做一个类似的,看代码方面就不多做赘述了。
参考的文章有下面这几个
(38条消息) PyQt5高级界面控件之QTimer(十一)_jia666666的博客-CSDN博客_pyqt5 qtimer
槽函数是什么 - 搜索 (bing.com)
利用设计工具画图里面用到了布局的组件
左边是一张表,右边就是视频,下面是对应的按钮
完成视频暂停的功能简单来说,释放掉视频流时,我不清空视频显示区域,这样显示的图片就停在最后一张,就像是截取了一样
(因为我的项目与物体识别有关,所以我的设想是点击确认后,视频暂停,用户确认表中信息与图片中的信息是否有误,无误,再点击成交,所以我的设想中需要这一功能,但到后期,还需要修改,改为处理后的显示图片)
代码如下
这里我将函数名称也修改了,变量名称也修改了注意一下(就微改了改了几行代码)
我将打开摄像头放在了初始化上,一运行摄像头就是打开状态修改了定义按钮的名称,同时将清空视频显示区域代码删除,完成截图效果from PyQt5 import QtCore,QtGui,QtWidgetsimport sysimport cv2import numpy as np class Ui_MainWindow(QtWidgets.QWidget): def __init__(self,parent=None): super().__init__(parent) #父类的构造函数 self.timer_camera = QtCore.QTimer() #定义定时器,用于控制显示视频的帧率 self.cap = cv2.VideoCapture() #视频流 self.CAM_NUM = 0 #为0时表示视频流来自笔记本内置摄像头 self.set_ui() #初始化程序界面 ''' Check whether the camera is connected and started''' self.open_camera() self.slot_init() #初始化槽函数 '''程序界面布局''' def set_ui(self): self.__layout_main = QtWidgets.QHBoxLayout() #总布局 self.__layout_fun_button = QtWidgets.QVBoxLayout() #按键布局 self.__layout_data_show = QtWidgets.QVBoxLayout() #数据(视频)显示布局 self.button_confirm = QtWidgets.QPushButton('重新确认') #建立用于打开摄像头的按键 self.button_close = QtWidgets.QPushButton('退出') #建立用于退出程序的按键 self.button_/confirm/i.setMinimumHeight(50) #设置按键大小 self.button_close.setMinimumHeight(50) self.button_close.move(10,100) #移动按键 这句话去掉好像也没关系 '''信息显示''' self.label_show_camera = QtWidgets.QLabel() #定义显示视频的Label self.label_show_camera.setFixedSize(641,481) #给显示视频的Label设置大小为641x481 '''把按键加入到按键布局中''' self.__layout_fun_button.addWidget(self.button_/confirm/i) #把打开摄像头的按键放到按键布局中 self.__layout_fun_button.addWidget(self.button_close) #把退出程序的按键放到按键布局中 '''把某些控件加入到总布局中''' self.__layout_main.addLayout(self.__layout_fun_button) #把按键布局加入到总布局中 self.__layout_main.addWidget(self.label_show_camera) #把用于显示视频的Label加入到总布局中 '''总布局布置好后就可以把总布局作为参数传入下面函数''' self.setLayout(self.__layout_main) #到这步才会显示所有控件 '''初始化所有槽函数''' def slot_init(self): self.button_/confirm/i.clicked.connect(self.open_camera) #若该按键被点击,则调用button_confirm() self.timer_camera.timeout.connect(self.show_camera) #若定时器结束,则调用show_camera() self.button_close.clicked.connect(self.close) #若该按键被点击,则调用close(),注意这个close是父类QtWidgets.QWidget自带的,会关闭程序 '''槽函数之一''' def open_camera(self): if self.timer_camera.isActive() == False: #若定时器未启动 flag = self.cap.open(self.CAM_NUM) #参数是0,表示打开笔记本的内置摄像头,参数是视频文件路径则打开视频 if flag == False: #flag表示open()成不成功 msg = QtWidgets.QMessageBox.warning(self,'warning',"请检查相机于电脑是否连接正确",buttons=QtWidgets.QMessageBox.Ok) else: self.timer_camera.start(30) #定时器开始计时30ms,结果是每过30ms从摄像头中取一帧显示 self.button_/confirm/i.setText('确定') else: self.timer_camera.stop() #关闭定时器 self.cap.release() #释放视频流 # self.label_show_camera.clear() #清空视频显示区域 self.button_/confirm/i.setText('重新确认') def show_camera(self): flag,self.image = self.cap.read() #从视频流中读取 show = cv2.resize(self.image,(640,480)) #把读到的帧的大小重新设置为 640x480 show = cv2.cvtColor(show,cv2.COLOR_BGR2RGB) #视频色彩转换回RGB,这样才是现实的颜色 showImage = QtGui.QImage(show.data,show.shape[1],show.shape[0],QtGui.QImage.Format_RGB888) #把读取到的视频数据变成QImage形式 self.label_show_camera.setPixmap(QtGui.QPixmap.fromImage(showImage)) #往显示视频的Label里 显示QImage if __name__ =='__main__': app = QtWidgets.QApplication(sys.argv) #固定的,表示程序应用 ui = Ui_MainWindow() #实例化Ui_MainWindow ui.show() #调用ui的show()以显示。同样show()是源于父类QtWidgets.QWidget的 sys.exit(app.exec_()) #不加这句,程序界面会一闪而过
添加显示表格功能参考的文章有下面面几篇
python GUI库图形界面开发之PyQt5控件QTableWidget详细使用方法与属性 - 云+社区 - 腾讯云 (tencent.com)
在这里我重新修改了我的代码,使其成为为上面设计的图纸。同时我将表格的内容设为不可编辑
代码如下
关于摄像头的代码没有修改,所以就没有黏贴上来
修改的内容有:
将总布局改为栅格布局添加了表格布局又增加了一个按键布局将表格改为不可编辑删除了退出按钮设置了label的大小
from PyQt5 import QtCore,QtGui,QtWidgetsfrom PyQt5.QtWidgets import QHeaderView from PyQt5.QtWidgets import QAbstractItemViewimport sysimport cv2import numpy as np class Ui_MainWindow(QtWidgets.QWidget): def __init__(self,parent=None): super().__init__(parent) #父类的构造函数 self.timer_camera = QtCore.QTimer() #定义定时器,用于控制显示视频的帧率 self.cap = cv2.VideoCapture() #视频流 self.CAM_NUM = 0 #为0时表示视频流来自笔记本内置摄像头 self.set_ui() #初始化程序界面 ''' Check whether the camera is connected and started''' self.open_camera() self.slot_init() #初始化槽函数 '''程序界面布局''' def set_ui(self): self.__layout_main = QtWidgets.QGridLayout() #总布局 self.__layout_fun_button1 = QtWidgets.QHBoxLayout() #按键布局1 self.__layout_fun_button2 = QtWidgets.QHBoxLayout() #按键布局2 self.__layout_data_show = QtWidgets.QVBoxLayout() #数据(视频)显示布局 self.__layout_list_show = QtWidgets.QVBoxLayout() #表格布局 self.button_confirm = QtWidgets.QPushButton('重新确认') #建立用于打开摄像头的按键 # self.button_close = QtWidgets.QPushButton('退出') #建立用于退出程序的按键 self.button_settle_accounts = QtWidgets.QPushButton('结账') #建立结账的按钮 self.list_show = QtWidgets.QTableWidget(6,3) #建立表格 self.label_account = QtWidgets.QLabel("总价") #建立label '''set butten size ''' self.button_/confirm/i.setMinimumHeight(50) #设置按键大小 # self.button_close.setMinimumHeight(50) self.button_settle_accounts.setMinimumHeight(50) self.label_account.setMinimumHeight(50) # self.button_close.move(10,100) #移动按键 这句话去掉好像也没关系 '''set label font''' font = QtGui.QFont() font.setPixelSize(18) self.label_account.setFont(font) '''set list''' self.list_show.setHorizontalHeaderLabels(["名称","数量","单价"]) self.list_show.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)# adaptive size self.list_show.setEditTriggers(QAbstractItemView.EditTrigger(False)) #将表格的内容设为不可编辑 '''信息显示''' self.label_show_camera = QtWidgets.QLabel() #定义显示视频的Label self.label_show_camera.setFixedSize(641,481) #给显示视频的Label设置大小为641x481 '''把按键加入到按键布局中''' self.__layout_fun_button1.addWidget(self.button_/confirm/i) #把重新确认的按键放到按键布局中 # self.__layout_fun_button1.addWidget(self.button_close) #把退出程序的按键放到按键布局中 self.__layout_fun_button2.addWidget(self.button_settle_accounts) #把结账的按键放到按键布局中 '''把表格加入到表格布局中''' self.__layout_list_show.addWidget(self.list_show) #将表格添加到表格布局中 self.__layout_list_show.addWidget(self.label_account) #将总价label添加到表格布局中 '''把某些控件加入到总布局中''' self.__layout_main.addLayout(self.__layout_list_show,0,0) #将表格布局添加到总布局中 self.__layout_main.addLayout(self.__layout_fun_button1,1,1) #把按键布局加入到总布局中 self.__layout_main.addLayout(self.__layout_fun_button2,1,0) #把按键布局加入到总布局中 self.__layout_main.addWidget(self.label_show_camera,0,1) #把用于显示视频的Label加入到总布局中 '''总布局布置好后就可以把总布局作为参数传入下面函数''' self.setLayout(self.__layout_main) #到这步才会显示所有控件 '''初始化所有槽函数''' def slot_init(self): self.button_/confirm/i.clicked.connect(self.open_camera) #若该按键被点击,则调用button_confirm() self.timer_camera.timeout.connect(self.show_camera) #若定时器结束,则调用show_camera()
整体的效果看下图,它是可以自由放大缩小的
可能遇到的问题,就是找了很长时间才找到如何让表格禁止编辑。
还有就是需要稍稍会一些界面的布局的东西。
ok,这第二集的日记就结束啦。下一章,我们就要尝试连接yolo,让yolov5处理后,在显示画面。
最后总结一下:真的是什么都不会,就做完这些东西我花了两个上午的时间。有很多查的东西也看不懂,也是到了最后,才慢慢摸到了我想要的功能。真不知道,以后真的坐上了开发,这个英文开发文档看不懂会怎么办(>_<)。真的是一看到这些全英文的东西脑袋就大。
不过还是做出来了我想要的效果,还是要鼓励一下自己的嘛。
那么我们就开始我们第三章日记的记录吧。