Python 如何在PyQt容器中运行视频?

Python 如何在PyQt容器中运行视频?,python,tensorflow,opencv,pyqt5,Python,Tensorflow,Opencv,Pyqt5,在PyQt上的QVideoWidget容器中,您需要从计算机启动一个视频,通过TensorFlow(openCV,cv2)在其中搜索对象。问题是,当按下按钮时,视频仅显示一帧,而没有显示其他帧。有什么问题吗?PyCharm制作,Python 3.7 from PyQt5 import QtCore, QtGui, QtWidgets, uiс import os import cv2 import numpy as np import sys from PyQt5 import QtCore,

在PyQt上的QVideoWidget容器中,您需要从计算机启动一个视频,通过TensorFlow(openCV,cv2)在其中搜索对象。问题是,当按下按钮时,视频仅显示一帧,而没有显示其他帧。有什么问题吗?PyCharm制作,Python 3.7

from PyQt5 import QtCore, QtGui, QtWidgets, uiс
import os
import cv2
import numpy as np
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QLabel, QVBoxLayout
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtGui import QImage, QPixmap

class ThreadOpenCV(QThread):
    changePixmap = pyqtSignal(QImage)

    def __init__(self, source):
        super().__init__()

    def run(self):

        # MODEL_NAME = 'inference_graph'
        VIDEO_NAME = '20201024161726.mp4'
        #
        # # Grab path to current working directory
        CWD_PATH = os.getcwd()
        PATH_TO_VIDEO = os.path.join(CWD_PATH, VIDEO_NAME)
        cap = cv2.VideoCapture(PATH_TO_VIDEO)
        while True:
            ret, frame = cap.read()

            if ret:
                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                frame_expanded = np.expand_dims(frame_rgb, axis=0)
                rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                h, w, ch = rgbImage.shape
                bytesPerLine = ch * w
                convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
                p = convertToQtFormat.scaled(640, 480, Qt.KeepAspectRatio)

                self.changePixmap.emit(p)

                if cv2.waitKey(1) == ord('q'):
                    break
            cap.release()
            cv2.destroyAllWindows()


class Widget(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        uic.loadUi('fire_detection.ui', self)
        self.show()

        self.label_video = QLabel()

        layout = QVBoxLayout()
        layout.addWidget(self.label_video)

        self.widget.setLayout(layout)

        self.thread = ThreadOpenCV('20201024161726.mp4')
        self.thread.changePixmap.connect(self.setImage)

        self.btn1.clicked.connect(self.playVideo)

    def playVideo(self):
        self.thread.start()

    def setImage(self, image):
        self.label_video.setPixmap(QPixmap.fromImage(image))

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)

    mw = Widget()
    mw.show()
    sys.exit(app.exec_())

所有的问题都是因为您有错误的缩进-并且您在
中运行
cap.release()
循环,所以它在第一帧之后释放流

   while True:
        ret, frame = cap.read()

        if ret:
            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            frame_expanded = np.expand_dims(frame_rgb, axis=0)

            rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            h, w, ch = rgbImage.shape
            bytesPerLine = ch * w
            convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
            p = convertToQtFormat.scaled(640, 480, Qt.KeepAspectRatio)

            self.changePixmap.emit(p)

   # --- after `while` ---

   cap.release()

您没有在
cv2
中创建窗口,因此您没有
cv2.destroyAllWindows()
。 和
cv2。waitKey(1)
也将无效,因为系统仅在显示窗口且该窗口处于活动状态(聚焦)时才会向
cv2
发送按键/鼠标事件


编辑:

完整的工作代码。它使用网络摄像头

它不需要
UI
文件

它有启动和停止流媒体的按钮

它也有按钮切换:RGB灰度,正常模糊

导入操作系统
导入系统
将numpy作为np导入
进口cv2
从PyQt5导入QtCore、QtGui、QtWidgets
从PyQt5.QtCore导入Qt、QThread、pyqtSignal
从PyQt5.qtwidts导入QLabel、QVBoxLayout、QPushButton、QWidget
从PyQt5.QtGui导入QImage、QPixmap
类ThreadOpenCV(QThread):
changePixmap=pyqtSignal(QImage)
定义初始化(自身,源):
super()。\uuuu init\uuuuu()
self.source=源
self.running=True
self.grayscale=False
self.blur=False
def运行(自):
打印('开始')
cap=cv2.VideoCapture(自源)
self.running=True
自运行时:
ret,frame=cap.read()
如果ret:
如果为self.grayscale:
frame=cv2.CVT颜色(frame,cv2.COLOR\u BGR2GRAY)
frame=cv2.CVT颜色(frame,cv2.COLOR_GRAY2RGB)
其他:
frame=cv2.CVT颜色(frame,cv2.COLOR_BGR2RGB)
如果self.blur:
帧=cv2。模糊(帧,(15,15))
h、 w,ch=框架形状
每行字节数=ch*w#PEP8:'lower_case_names'用于变量
image=QImage(frame.data,w,h,每行字节数,QImage.Format_RGB888)
image=image.scaled(640480,Qt.keepasspectratio)
self.changePixmap.emit(图像)
第1章释放()
打印('停止')
def停止(自):
self.running=False
类小部件(QtWidgets.QMainWindow):
定义初始化(自):
super()。\uuuu init\uuuuu()
#模型名称='推理图'
视频名称='20201024161726.mp4'
CWD_PATH=os.getcwd()
PATH\u TO\u VIDEO=os.PATH.join(CWD\u路径,VIDEO\u名称)
#网络摄像机
路径到视频=0
self.thread=ThreadOpenCV(路径到视频)
self.thread.changePixmap.connect(self.setImage)
layout=QVBoxLayout()
self.label_video=QLabel()
layout.addWidget(self.label\u视频)
self.btn1=QPushButton(“播放”)
self.btn1.clicked.connect(self.playVideo)
layout.addWidget(self.btn1)
self.btn_stop=QPushButton(“停止”)
self.btn\u停止。单击。连接(self.stopVideo)
layout.addWidget(self.btn\u-stop)
self.btn_gray=QPushButton(“RGB灰度”)
self.btn\u gray.clicked.connect(self.grayVideo)
layout.addWidget(self.btn_gray)
self.btn_blur=QPushButton(“正常模糊”)
self.btn\u blur.clicked.connect(self.blur视频)
layout.addWidget(self.btn\u blur)
self.widget=QWidget()
self.widget.setLayout(布局)
self.setCentralWidget(self.widget)
def播放视频(自我):
self.thread.start()
def停止视频(自):
self.thread.running=False
def灰色视频(自):
self.thread.grayscale=非self.thread.grayscale
视频(自我):
self.thread.blur=非self.thread.blur
def setImage(自我,图像):
self.label_video.setPixmap(QPixmap.fromImage(图像))
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
app=QtWidgets.QApplication([])
mw=Widget()
mw.show()
app.exec()
RGB,正常:

灰度,模糊:


waitKey
如果不显示cv2窗口,则它将无效。当您想要退出循环时,您应该在运行时使用
并设置
running=False
。您可能会遇到问题,因为您有错误的缩进,并且您运行
cap.release()
inside
while
while
-所以它会在第一帧后释放它。如果您没有使用
cv2.imshow
(或类似工具)创建窗口那么您就不需要
cv2.destroyAllWindows()
谢谢您的回答谢谢您的回答,它很有帮助)
import os
import sys
import numpy as np
import cv2

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtWidgets import QLabel, QVBoxLayout, QPushButton, QWidget
from PyQt5.QtGui import QImage, QPixmap

class ThreadOpenCV(QThread):
    
    changePixmap = pyqtSignal(QImage)

    def __init__(self, source):
        super().__init__()

        self.source = source

        self.running = True
        self.grayscale = False
        self.blur = False
        
    def run(self):
        print('start')

        cap = cv2.VideoCapture(self.source)

        self.running = True
        
        while self.running:
            ret, frame = cap.read()

            if ret:
                if self.grayscale:
                    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
                    frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2RGB)
                else:
                    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    
                if self.blur:
                    frame = cv2.blur(frame, (15, 15))

                h, w, ch = frame.shape
                bytes_per_line = ch * w   # PEP8: `lower_case_names` for variables
                
                image = QImage(frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
                image = image.scaled(640, 480, Qt.KeepAspectRatio)

                self.changePixmap.emit(image)
            
        cap.release()
        print('stop')
        
    def stop(self):
        self.running = False


class Widget(QtWidgets.QMainWindow):
    
    def __init__(self):
        super().__init__()

        # MODEL_NAME = 'inference_graph'
        VIDEO_NAME = '20201024161726.mp4'
        CWD_PATH = os.getcwd()
        PATH_TO_VIDEO = os.path.join(CWD_PATH, VIDEO_NAME)
       
        # webcam
        PATH_TO_VIDEO = 0

        self.thread = ThreadOpenCV(PATH_TO_VIDEO)
        self.thread.changePixmap.connect(self.setImage)

        layout = QVBoxLayout()

        self.label_video = QLabel()
        layout.addWidget(self.label_video)

        self.btn1 = QPushButton("PLAY")
        self.btn1.clicked.connect(self.playVideo)
        layout.addWidget(self.btn1)

        self.btn_stop = QPushButton("STOP")
        self.btn_stop.clicked.connect(self.stopVideo)
        layout.addWidget(self.btn_stop)
        
        self.btn_gray = QPushButton("RGB <-> GRAYSCALE")
        self.btn_gray.clicked.connect(self.grayVideo)
        layout.addWidget(self.btn_gray)

        self.btn_blur = QPushButton("NORMAL <-> BLURED")
        self.btn_blur.clicked.connect(self.blurVideo)
        layout.addWidget(self.btn_blur)

        self.widget = QWidget()
        self.widget.setLayout(layout)

        self.setCentralWidget(self.widget)
        
    def playVideo(self):
        self.thread.start()

    def stopVideo(self):
        self.thread.running = False

    def grayVideo(self):
        self.thread.grayscale = not self.thread.grayscale

    def blurVideo(self):
        self.thread.blur = not self.thread.blur

    def setImage(self, image):
        self.label_video.setPixmap(QPixmap.fromImage(image))

if __name__ == '__main__':
    
    app = QtWidgets.QApplication([])

    mw = Widget()
    mw.show()
    
    app.exec()