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

标签 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, 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_())

最佳答案

所有问题都是因为您的缩进错误 - 并且您在 while 循环内运行 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 <-> 灰度、正常 <-> 模糊。

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()

RGB,正常:

enter image description here

灰度、模糊:

enter image description here

关于python - 如何在 PyQt 容器中运行视频?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67488022/

相关文章:

python - 我是在父级和子级 Django 模板中添加 Google Analytics 跟踪脚本,还是仅在 Django 网站上的父级模板中添加 Google Analytics 跟踪脚本?

python - 为什么 Keras Tokenizer 文本到序列对所有文本返回相同的值?

tensorflow - 使用 R-CNN 进行目标检测?

opencv - 使用cmake和opencv构建 "hollow world"错误: undefined reference to viz's moduls

Python 模拟 C++ 指向类成员的指针

python - 将数据框导出到图像中

python - 如何在 Django Admin 中添加额外字段?

tensorflow - 试图恢复模型,但 tf.train.import_meta_graph(meta_path) 引发错误

python - 使用 Homebrew 软件在 Mac OS X 10.9 中构建 OpenCV_Python

c++ - 如何从 OpenCV FileNode 映射中检索键值对?