记录: pyqt5+opencv实现rtsp/rtmp视频流播放

记录: pyqt5+opencv实现rtsp/rtmp视频流播放

最近有一个需求,要求写一个客户端实时展示多个摄像头的视频流。
界面大致设计如下:在这里插入图片描述
由于我是搞Java出生的,很想用java写客户端,但是java写的窗口程序,实在是太。。。
所以,最后还是选择python+qt来完成这个任务。

使用python 3.6
要调用摄像头,首先想到使用opencv的VideoCapture组件了(还有一种方式是使用vlc,暂时不研究了)
公司摄像头是rtsp协议的流,网络资源是rtmp协议的流(这里就用网络资源)

我的大致实现思路,比较简单:
1.窗口设计6个label
2.每个摄像头定义一个线程,需要启动6个子线程
3.每个线程里获取视频流每一帧,用label展示

第一步:
使用QtDesigner设计UI:
在这里插入图片描述
在PyCharm中使用qt的pyuic插件生成UI类:
在这里插入图片描述
在这里插入图片描述
第二步
编写主类:

# 作者:gc
# 日期:2020-04-09 14:06
# 描述:测试主类

import cv2, sys, os, threading, time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QImage, QPixmap
from form.TestCamera import Ui_Form


class TestCamera(QtWidgets.QWidget, Ui_Form):
    def __init__(self):
        super(TestCamera, self).__init__()
        self.setupUi(self)
        self.init_camera()

    def init_camera(self):
        """初始化摄像头监控"""
        print("进程pid:", os.getpid())
        threading.Thread(target=Camera('rtmp://58.200.131.2:1935/livetv/hunantv', self.Camera1).display).start()
        threading.Thread(target=Camera('rtmp://58.200.131.2:1935/livetv/gxtv', self.Camera2).display).start()
        threading.Thread(target=Camera('rtmp://58.200.131.2:1935/livetv/gdtv', self.Camera3).display).start()
        threading.Thread(target=Camera('rtmp://58.200.131.2:1935/livetv/dftv', self.Camera4).display).start()
        threading.Thread(target=Camera('rtmp://58.200.131.2:1935/livetv/gxtv', self.Camera5).display).start()
        threading.Thread(target=Camera('rtmp://58.200.131.2:1935/livetv/hunantv', self.Camera6).display).start()


class Camera:
    """摄像头对象"""

    def __init__(self, url, out_label):
        """初始化方法"""
        self.url = url
        self.outLabel = out_label

    def display(self):
        """显示"""
        cap = cv2.VideoCapture(self.url)
        start_time = time.time()
        while cap.isOpened():
            success, frame = cap.read()
            if success:
                if (time.time() - start_time) > 0.1:
                    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
                    img = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
                    self.outLabel.setPixmap(QPixmap.fromImage(img))
                    cv2.waitKey(1)
                    start_time = time.time()


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = TestCamera()
    mainWindow.show()
    sys.exit(app.exec())

说明一下为什么在display里面加入(time.time() - start_time) > 0.1条件:
最开始我是没有加这些条件的,但是程序会在运行时突然挂掉,原因是因为

frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
img = QImage(frame.data, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
self.outLabel.setPixmap(QPixmap.fromImage(img))

这部分代码很费cpu的资源,我电脑性能一般,4核16线程的,同时处理6个摄像头的视频流,有点吃不消(不知道是不是这个原因,但是我加了延迟,确实是减少了我cpu的开销),所以我加了一个延迟,0.1s。
说说我个人的理解吧,做这个客户端看使用场景,如果是单摄像头实时显示,那至少我这台电脑是能够保证流处理的速度,几乎不延迟和卡顿,如果是多摄像头显示,这个客户端是放在定制终端上使用,建议还是使用带GPU的终端好点,图片处理速度更快,毕竟是GPU,如果是要求随处安装的客户端,我不知道该怎么弄才能解决CPU开销大的问题。
第三步
看看实现效果吧:
在这里插入图片描述
我把UI类也贴出来吧:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'TestCamera.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.resize(797, 336)
        self.layoutWidget = QtWidgets.QWidget(Form)
        self.layoutWidget.setGeometry(QtCore.QRect(30, 20, 741, 292))
        self.layoutWidget.setObjectName("layoutWidget")
        self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setObjectName("gridLayout")
        self.Camera1 = QtWidgets.QLabel(self.layoutWidget)
        self.Camera1.setMinimumSize(QtCore.QSize(241, 141))
        self.Camera1.setMaximumSize(QtCore.QSize(241, 141))
        self.Camera1.setAutoFillBackground(True)
        self.Camera1.setText("")
        self.Camera1.setScaledContents(True)
        self.Camera1.setObjectName("Camera1")
        self.gridLayout.addWidget(self.Camera1, 0, 0, 1, 1)
        self.Camera2 = QtWidgets.QLabel(self.layoutWidget)
        self.Camera2.setMinimumSize(QtCore.QSize(241, 141))
        self.Camera2.setMaximumSize(QtCore.QSize(241, 141))
        self.Camera2.setAutoFillBackground(True)
        self.Camera2.setText("")
        self.Camera2.setScaledContents(True)
        self.Camera2.setObjectName("Camera2")
        self.gridLayout.addWidget(self.Camera2, 0, 1, 1, 1)
        self.Camera3 = QtWidgets.QLabel(self.layoutWidget)
        self.Camera3.setMinimumSize(QtCore.QSize(241, 141))
        self.Camera3.setMaximumSize(QtCore.QSize(241, 141))
        self.Camera3.setAutoFillBackground(True)
        self.Camera3.setText("")
        self.Camera3.setScaledContents(True)
        self.Camera3.setObjectName("Camera3")
        self.gridLayout.addWidget(self.Camera3, 0, 2, 1, 1)
        self.Camera4 = QtWidgets.QLabel(self.layoutWidget)
        self.Camera4.setMinimumSize(QtCore.QSize(241, 141))
        self.Camera4.setMaximumSize(QtCore.QSize(241, 141))
        self.Camera4.setAutoFillBackground(True)
        self.Camera4.setText("")
        self.Camera4.setScaledContents(True)
        self.Camera4.setObjectName("Camera4")
        self.gridLayout.addWidget(self.Camera4, 1, 0, 1, 1)
        self.Camera5 = QtWidgets.QLabel(self.layoutWidget)
        self.Camera5.setMinimumSize(QtCore.QSize(241, 141))
        self.Camera5.setMaximumSize(QtCore.QSize(241, 141))
        self.Camera5.setAutoFillBackground(True)
        self.Camera5.setText("")
        self.Camera5.setScaledContents(True)
        self.Camera5.setObjectName("Camera5")
        self.gridLayout.addWidget(self.Camera5, 1, 1, 1, 1)
        self.Camera6 = QtWidgets.QLabel(self.layoutWidget)
        self.Camera6.setMinimumSize(QtCore.QSize(241, 141))
        self.Camera6.setMaximumSize(QtCore.QSize(241, 141))
        self.Camera6.setAutoFillBackground(True)
        self.Camera6.setText("")
        self.Camera6.setScaledContents(True)
        self.Camera6.setObjectName("Camera6")
        self.gridLayout.addWidget(self.Camera6, 1, 2, 1, 1)

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Form"))

  • 8
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要使用 PyQt 结合 OpenCV 进行录制保存和播放视频,可以按照以下步骤进行: 1. 安装 PyQt 和 OpenCV 库: ``` pip install PyQt5 pip install opencv-python ``` 2. 创建一个 PyQt 窗口,用于显示视频: ```python import sys from PyQt5.QtWidgets import QApplication, QWidget, QLabel from PyQt5.QtGui import QImage, QPixmap class VideoPlayer(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.setGeometry(100, 100, 640, 480) self.show() ``` 3. 初始化 OpenCV摄像头,并将视频帧显示在 PyQt 窗口: ```python import cv2 class VideoPlayer(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.setGeometry(100, 100, 640, 480) self.show() self.cap = cv2.VideoCapture(0) self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(50) def update_frame(self): ret, frame = self.cap.read() if ret: image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = image.shape bytes_per_line = ch * w convert_to_QtFormat = QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) p = convert_to_QtFormat.scaled(640, 480, Qt.KeepAspectRatio) self.label.setPixmap(QPixmap.fromImage(p)) ``` 4. 添加录制和保存视频的功能: ```python class VideoPlayer(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.setGeometry(100, 100, 640, 480) self.show() self.cap = cv2.VideoCapture(0) self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(50) self.recording = False self.video_writer = None def update_frame(self): ret, frame = self.cap.read() if ret: if self.recording: if self.video_writer is None: fourcc = cv2.VideoWriter_fourcc(*'MJPG') self.video_writer = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480)) self.video_writer.write(frame) image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = image.shape bytes_per_line = ch * w convert_to_QtFormat = QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) p = convert_to_QtFormat.scaled(640, 480, Qt.KeepAspectRatio) self.label.setPixmap(QPixmap.fromImage(p)) def keyPressEvent(self, event): if event.key() == Qt.Key_Space: self.recording = not self.recording if not self.recording and self.video_writer is not None: self.video_writer.release() self.video_writer = None ``` 5. 添加播放已保存视频的功能: ```python class VideoPlayer(QWidget): def __init__(self): super().__init__() self.label = QLabel(self) self.setGeometry(100, 100, 640, 480) self.show() self.cap = cv2.VideoCapture(0) self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(50) self.recording = False self.video_writer = None self.playing = False self.video_capture = None def update_frame(self): ret, frame = self.cap.read() if ret: if self.recording: if self.video_writer is None: fourcc = cv2.VideoWriter_fourcc(*'MJPG') self.video_writer = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480)) self.video_writer.write(frame) image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = image.shape bytes_per_line = ch * w convert_to_QtFormat = QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) p = convert_to_QtFormat.scaled(640, 480, Qt.KeepAspectRatio) self.label.setPixmap(QPixmap.fromImage(p)) def keyPressEvent(self, event): if event.key() == Qt.Key_Space: self.recording = not self.recording if not self.recording and self.video_writer is not None: self.video_writer.release() self.video_writer = None elif event.key() == Qt.Key_P: self.playing = not self.playing if self.playing: self.video_capture = cv2.VideoCapture('output.avi') self.timer.stop() self.timer.timeout.connect(self.update_saved_frame) self.timer.start(1000//30) else: self.timer.stop() self.timer.timeout.connect(self.update_frame) self.timer.start(50) def update_saved_frame(self): ret, frame = self.video_capture.read() if ret: image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = image.shape bytes_per_line = ch * w convert_to_QtFormat = QImage(image.data, w, h, bytes_per_line, QImage.Format_RGB888) p = convert_to_QtFormat.scaled(640, 480, Qt.KeepAspectRatio) self.label.setPixmap(QPixmap.fromImage(p)) ``` 完整的代码如下:
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值