视频流输入可以利用cv2包读取,读取获得的是ret和frame,ret是一个布尔值(bool),frame是视频流的某一帧,所以最大我的问题就是建造一个Qwidget,在里面放入一个容器用来显示frame。
首先使用Qwidget建造一个窗口,然后在里面放上一个QLabel,用cv2读取得到图片frame之后,将frame放在QLabel上面,并进行循环,就可以将图片连贯成视频。
Qwidget的生成可以用Qtdesigner,在terminal输入pyqt5-tools.exe designer即可使用;或者手动定义一个类,后者具有较强的可操作性,前者具有较强的可视性,我推荐小项目自己手敲,较为复杂的界面使用Qtdesigner。
cv2通过摄像头IP地址即可连接摄像头,笔记本电脑本地摄像头一般设为0,在读取之后会返回bool值和实时视频帧的信息,我们只需要将视频帧显示在QLabel上面即可。
所以可以分为三个阶段:窗口绘制阶段,图片获得阶段,图片显示阶段。
在窗口绘制阶段,使用initui方法,先将整体白板窗口放出来,再向上面添加布局,布局包括顶层的选项框、中间的按钮、以及两个空白label控件。
在图片获得阶段,点击开启摄像头会将本地摄像头打开,获取bool值和实时视频帧,传输到计算机当中。
在图片显示阶段,cv2读取的BGR格式的图片会被转码成RGB图片,并变成QImage的格式,再由Qt自带的QPixmap中的setPixmap对其进行绘制,显示在QLabel上面。后期会加入对关键帧的提取。
代码如下:
有问题可以私信问我,随时在线。
# -*- coding: utf-8 -*-
"""
@author:xiaoyangchicao2020
@time:2022-99-99
"""
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import cv2
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI() # 界面绘制交给InitUi方法
def initUI(self):
lb1 = QLabel(self)
lb1.setGeometry(0, 0, 1280, 800)
# lb1.setStyleSheet("border: 2px solid red")
# 设置窗口的位置和大小
self.setGeometry(300, 100, 700, 450)
# 设置窗口的标题
self.setWindowTitle('current window')
# 显示窗口
self.show()
class ListViewDemo(QMainWindow):
def __init__(self, parent=None):
super(ListViewDemo, self).__init__(parent)
self.imgName = []
self.resize(500, 300)
HLayout = QHBoxLayout()
VLayout = QVBoxLayout()
self.lab1 = QLabel()
self.lab2 = QLabel()
#self.lab1.setPixmap(QPixmap(r'C:\Users\MI\Desktop\CJ.png'))
HLayout.addWidget(self.lab1)
HLayout.addWidget(self.lab2)
self.listView = QListView()
self.listView.setContextMenuPolicy(Qt.CustomContextMenu) # 右键菜单
self.listView.customContextMenuRequested[QtCore.QPoint].connect(self.rightMenuShow)
self.btnOK = QPushButton("开启摄像头")
self.checkBox1.setChecked(False)
self.checkBox1.stateChanged.connect(lambda: self.btnstate(self.checkBox1))
VLayout.addWidget(self.btnOK)
VLayout.addWidget(self.selectbtn)
VLayout.addWidget(self.saveimagbtn)
#VLayout.addWidget(groupBox)
VLayout.addWidget(self.listView)
bar = self.menuBar()
file = bar.addMenu("Start")
edit = bar.addMenu("About")
file.addAction("Open")
file.addAction("Edit")
file.addAction("Quit")
self.listView.setContextMenuPolicy(Qt.CustomContextMenu)
self.listView.customContextMenuRequested[QtCore.QPoint].connect(self.rightMenuShow)
self.statusBar = QStatusBar()
self.setStatusBar(self.statusBar)
HLayout.addLayout(VLayout)
main_frame = QWidget()
main_frame.setLayout(HLayout)
self.setWindowTitle('监控运行')
self.selectbtn.clicked.connect(self.openimage)
self.listView.doubleClicked.connect(self.clicked)
self.listView.clicked.connect(self.clicked)
self.btnOK.clicked.connect(self.camera)
self.setCentralWidget(main_frame)
def rightMenuShow(self):
rightMenu = QtWidgets.QMenu(self.listView)
removeAction = QtWidgets.QAction(u"Delete", self,
triggered=self.removeimage) # triggered 为右键菜单点击后的激活事件。这里slef.close调用的是系统自带的关闭事件。
rightMenu.addAction(removeAction)
rightMenu.exec_(QtGui.QCursor.pos())
def processTrigger(self, q):
if (q.text() == "show"):
self.statusBar.showMessage(q.text() + " 菜单选项被点击了", 5000)
def btnstate(self, btn):
chk1Status = self.checkBox1.isChecked()
print(chk1Status)
if chk1Status:
QMessageBox.information(self, "Tips", "是", QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)
else:
QMessageBox.information(self, "Tips", "否")
def clicked(self, qModelIndex):
#QMessageBox.information(self, "QListView", "你选择了: "+ imgName[qModelIndex.row()])
global path
self.lab1.setPixmap(QPixmap(imgName[qModelIndex.row()]))
path = imgName[qModelIndex.row()]
def openimage(self):
global imgName
imgName, imgType = QtWidgets.QFileDialog.getOpenFileNames(self, "多文件选择", "/", "所有文件 (*);;文本文件 (*.txt)")
slm = QStringListModel()
slm.setStringList(imgName)
self.listView.setModel(slm)
def removeimage(self):
selected = self.listView.selectedIndexes()
itemmodel = self.listView.model()
for i in selected:
itemmodel.removeRow(i.row())
def processimage(self):
QMessageBox.information(self, "Tips", "Done!")
def camera(self):
# 打开USB摄像头
cap = cv2.VideoCapture(0)
#如果有其他摄像头的话
# 摄像头的IP地址,http://用户名:密码@IP地址:端口/
'''camera_url_ip = 'http://admin:admin@192.168.1.101:8081/'
# 创建一个VideoCapture
cap = cv2.VideoCapture(camera_url_ip)'''
print('IP摄像头是否开启: {}'.format(cap.isOpened()))
# 显示缓存数
print(cap.get(cv2.CAP_PROP_BUFFERSIZE))
# 设置缓存区的大小
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
# 调节摄像头分辨率
#cap.set(cv2.CAP_PROP_FRAME_WIDTH, w)
#cap.set(cv2.CAP_PROP_FRAME_HEIGHT, h)
print('width:', cap.get(cv2.CAP_PROP_FRAME_WIDTH))
print('height:', cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# 设置FPS
fps = 30
print('FPS值为:', cap.set(cv2.CAP_PROP_FPS, fps))
print(cap.get(cv2.CAP_PROP_FPS))
self.c=1
#framedata = 1
#ex=Example()
# codec = cv2.VideoWriter_fourcc(*'MJPG')
# out = cv2.VideoWriter
while (True):
ret, self.frame = cap.read()
cv2.waitKey(0)
# gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
self.frame = cv2.cvtColor(self.frame, cv2.COLOR_RGB2BGR)
self.img = QImage(self.frame.data, self.frame.shape[1], self.frame.shape[0], QImage.Format_RGB888)
self.lab2.setPixmap(QPixmap(self.img))
# 当一切结束后,释放VideoCapture对象
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
app = QApplication(sys.argv)
win = ListViewDemo()
win.show()
sys.exit(app.exec_())
最近学到了新的方法,不需要像我这样将部件一个个往上添加了,只需要先GUI编程托拉拽,再转码生成py文件,作为一个包直接导入,使用其中已经定义好的继承过来的新类即可。详细请看我的文章有写。