PyQt转换显示Python-OpenCV图像实现图形化界面的视频播放

☞ ░ 前往老猿Python博文目录

一、引言

在Python-OpenCV中显示图像时调用的是一个单独的窗口,有时我们需要将这些图像显示在PyQt的图形化界面上,这样就可以将整个图像显示与PyQt图形化界面进行整合。但OpenCV格式的图像和PyQt格式的图像并不同,这就需要进行转换。

二、背景知识

  1. Python-OpenCV的图像是BGR格式的,而PyQt图像格式是RGB格式的,二者需要转换;
  2. 为了快速转换,图像必须基于内存进行操作;
  3. PyQt的QImage类可以从内存数组构建;
  4. OpenCV可以读取视频图像,使用waitKey可以实现休眠特定时长而不影响系统消息处理。

关于PyQt和OpenCV之间的图像转换请参考《Python-OpenCV中图像颜色空间转换》。

三、案例

下面的案例读取一个视频文件的图像进行显示,如果再叠加一个音频播放的功能,就实现了一个视频播放器。

3.1、设计图形化界面

在这里插入图片描述
该图形界面非常简单,包含了一个仅有“ShowImg”的菜单和对应工具栏,一个名为ImgDisp的标签对象用于显示图像(蓝色标记部分)。使用PyUIC生成的界面对象代码如下:

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(625, 430)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.ImgDisp = QtWidgets.QLabel(self.centralwidget)
        self.ImgDisp.setGeometry(QtCore.QRect(0, 0, 54, 12))
        self.ImgDisp.setObjectName("ImgDisp")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 625, 17))
        self.menubar.setObjectName("menubar")
        self.menushowImg = QtWidgets.QMenu(self.menubar)
        self.menushowImg.setObjectName("menushowImg")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.toolBar = QtWidgets.QToolBar(MainWindow)
        self.toolBar.setObjectName("toolBar")
        MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
        self.actionshowImg = QtWidgets.QAction(MainWindow)
        self.actionshowImg.setObjectName("actionshowImg")
        self.menushowImg.addAction(self.actionshowImg)
        self.menubar.addAction(self.menushowImg.menuAction())
        self.toolBar.addAction(self.actionshowImg)

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

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.ImgDisp.setText(_translate("MainWindow", "."))
        self.menushowImg.setTitle(_translate("MainWindow", "menu"))
        self.toolBar.setWindowTitle(_translate("MainWindow", "toolBar"))
        self.actionshowImg.setText(_translate("MainWindow", "showImg"))

3.2、主程序

import cv2,sys
from PyQt5 import QtGui,QtWidgets,QtCore
import mainWin

def cvImgtoQtImg(cvImg): #定义opencv图像转PyQt图像的函数
    QtImgBuf = cv2.cvtColor(cvImg,  cv2.COLOR_BGR2BGRA)

    QtImg = QtGui.QImage(QtImgBuf.data, QtImgBuf.shape[1], QtImgBuf.shape[0], QtGui.QImage.Format_RGB32)
    
    return QtImg



class mainwin(QtWidgets.QMainWindow,mainWin.Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.bClose = False

        self.actionshowImg.triggered.connect(self.playVideoFile) #建立菜单点击的信号与方法playVideoFile连接

    def playVideoFile(self): #播放影片
        cap = cv2.VideoCapture(r'f:\video\mydream.mp4') #打开影片
        fps = 24
        if not cap.isOpened():
            print("Cannot open Video File")
            exit()

        while not self.bClose:
            ret, frame = cap.read() #逐帧读取影片
            if not ret:
                if frame is None:
                    print("The video has end.")
                else:
                    print("Read video error!")
                break

            QtImg = cvImgtoQtImg(frame)  #将帧数据转换为PyQt图像格式
            self.ImgDisp.setPixmap(QtGui.QPixmap.fromImage(QtImg)) #在ImgDisp显示图像
            size = QtImg.size() 
            self.ImgDisp.resize(size)#根据帧大小调整标签大小
            self.ImgDisp.show() #刷新界面
            cv2.waitKey(int(1000/fps)) #休眠一会,确保每秒播放fps帧

        # 完成所有操作后,释放捕获器
        cap.release()


if __name__=='__main__':
    app = QtWidgets.QApplication(sys.argv)
    w = mainwin()
    w.show()
    sys.exit(app.exec_())

注意:

本文的实现方法存在不足,相关完善方案请见《OpenCV-Python图像转换为PyQt图像的变形及花屏问题研究》。

3.3、运行程序

初始界面

在这里插入图片描述

点击showImg,开始播放视频:
在这里插入图片描述

关于PyQt的使用请参考付费专栏《使用PyQt开发图形界面Python应用》,专栏文件目录《使用PyQt开发图形界面Python应用专栏目录》。

也可以参考免费专栏《PyQt入门知识》,专栏文件目录《使用PyQt进行Python图形界面程序开发文章目录》。

关于老猿的付费专栏

老猿的付费专栏《使用PyQt开发图形界面Python应用》专门介绍基于Python的PyQt图形界面开发基础教程,付费专栏《moviepy音视频开发专栏》详细介绍moviepy音视频剪辑合成处理的类相关方法及使用相关方法进行相关剪辑合成场景的处理,两个专栏加起来只需要19.9元,都适合有一定Python基础但无相关专利知识的小白读者学习。这2个收费专栏都有对应免费专栏,只是收费专栏的文章介绍更具体、内容更深入、案例更多。

收费专栏文章目录:《moviepy音视频开发专栏文章目录》、《使用PyQt开发图形界面Python应用专栏目录》。

对于缺乏Python基础的同仁,可以通过老猿的免费专栏《专栏:Python基础教程目录》从零开始学习Python。

如果有兴趣也愿意支持老猿的读者,欢迎购买付费专栏。

跟老猿学Python、学5G!

☞ ░ 前往老猿Python博文目录

猜你喜欢

转载自blog.csdn.net/LaoYuanPython/article/details/108210491