【问题标题】:PyQt4 video player crashes when moving windowPyQt4 视频播放器在移动窗口时崩溃
【发布时间】:2015-04-23 16:17:57
【问题描述】:

我编写了一个简单的 PyQt4 GUI,可以播放 OpenCV VideoCapture。这需要将帧从 numpy 数组转换为 QImages。我正在使用 OpenCV,以便可以使用我的 findCircles 方法检测圆圈。

但是,当我将帧传递给findCircles 时,移动窗口时程序会崩溃。当我不搜索圈子时,不会出现此问题。我不明白为什么会发生这种情况,因为我的印象是工作是在与 GUI 不同的线程上完成的,因为我从 QThreadrun 方法调用 findCircles

请注意,我在控制台中没有收到正常的错误消息; Python 像这样崩溃:

Here 是我用来测试我的播放器的视频文件。我在 Windows 8.1 上运行 Python 2.7.6。

import sys
import cv2.cv as cv, cv2
from PyQt4.Qt import *
import time

def numpyArrayToQImage(array):
    if array != None:
        height, width, bytesPerComponent = array.shape
        bytesPerLine = bytesPerComponent * width;
        cv2.cvtColor(array, cv.CV_BGR2RGB, array)
        return QImage(array.data, width, height, bytesPerLine, QImage.Format_RGB888)
    return None

def findCircles(frame):
    grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    blurredFrame = cv2.medianBlur(grayFrame, 3)
    circles = cv2.HoughCircles(blurredFrame, cv.CV_HOUGH_GRADIENT, 1, 30, param1=50, param2=30, minRadius=30, maxRadius=35)

    if circles is not None: 
        for i in circles[0]:
            cv2.circle(frame, (i[0], i[1]), i[2], (255, 0, 0), 1) # Perimeter
            cv2.circle(frame, (i[0], i[1]), 3, (0, 255, 0), -1) # Center

class VideoThread(QThread):
    frameProcessed = pyqtSignal(QImage)

    def __init__(self, video, videoLabel):
        QThread.__init__(self)
        self.video = video
        self.fps = self.video.get(cv.CV_CAP_PROP_FPS)
        self.frameCount = self.video.get(cv.CV_CAP_PROP_FRAME_COUNT)
        self.startingSecond = 0
        self.videoLabel = videoLabel

    def run(self):
        clockAtStart = time.clock()

        while True:
            runtime = self.startingSecond + (time.clock() - clockAtStart)
            currentFrame = int(runtime * self.fps)

            if currentFrame < self.frameCount - 1:
                self.video.set(cv.CV_CAP_PROP_POS_FRAMES, currentFrame)
                frame = self.video.read()[1]
                findCircles(frame) # Removing this line removes the issue
                self.frameProcessed.emit(numpyArrayToQImage(frame))
                time.sleep(.02)
            else:
                break

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.initUI()

    @pyqtSlot(QImage)
    def updateVideoLabel (self, image):
        self.videoLabel.setPixmap(QPixmap.fromImage(image))
        self.videoLabel.update()

    def initUI(self):
        self.setGeometry(300, 300, 500, 375)
        self.setMinimumHeight(250)
        self.createWidgets()
        self.addWidgets()

    def startNewVideo(self):
        self.video = cv2.VideoCapture(unicode(QFileDialog.getOpenFileName(self, "Open video").toUtf8(), encoding="UTF-8"))
        self.videoThread = VideoThread(self.video, self.videoLabel)
        self.videoThread.frameProcessed.connect(self.updateVideoLabel)
        self.playVideoFrom(0)

    def playVideoFrom(self, frame):
        self.videoThread.startingSecond = frame / self.videoThread.fps
        self.videoThread.start()

    def createWidgets(self):
        self.populateMenuBar()
        self.videoLabel = QLabel()
        self.videoLabel.setStyleSheet('background-color : black;');

    def populateMenuBar(self):
        self.menuBar = self.menuBar()
        fileMenu = QMenu('File', self)
        openAction = QAction('Open video...', self)
        openAction.triggered.connect(self.startNewVideo)
        fileMenu.addAction(openAction)
        self.menuBar.addMenu(fileMenu)

    def addWidgets(self):
        mainLayout = QVBoxLayout()
        mainLayout.addWidget(self.videoLabel, 1)
        centralWidget = QWidget()
        self.setCentralWidget(centralWidget)
        centralWidget.setLayout(mainLayout)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    player = MainWindow()
    player.show()
    sys.exit(app.exec_())

【问题讨论】:

  • 您是否尝试从函数 findCircles 返回帧?
  • findCircles 方法在框架顶部绘制找到的圆圈,从而改变框架对象。无需退货。
  • C您能提供一个示例视频来测试您的程序吗?
  • 我无法重现当前示例脚本的问题。该代码似乎确实能够在显示一些硬币的简单视频中找到圆圈 - 尽管这样做非常不一致。但是,在显示视频的同时不断移动窗口没有效果。这是在 Linux 上,使用 python 2.7.9、qt 4.8.6 和 pyqt 4.11.3。
  • 用python 2.7.9试试

标签: multithreading python-2.7 opencv numpy pyqt4


【解决方案1】:

我已经测试了你的程序,当它没有找到错误消息中指示的圆圈时它会崩溃:

Traceback (most recent call last):
  File "test_opencv_tkinter.py", line 53, in run
    findCircles(frame) # Removing this line removes the issue
  File "test_opencv_tkinter.py", line 26, in findCircles
    if len(circles) > 0:
TypeError: object of type 'NoneType' has no len()

我对@9​​87654322@ 函数进行了一些更改,如下所示,即使我在屏幕上移动窗口,它也可以正常运行。

def findCircles(frame):
    grayFrame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    blurredFrame = cv2.medianBlur(grayFrame, 3)
    circles = cv2.HoughCircles(grayFrame,cv.CV_HOUGH_GRADIENT,1,20,
                            param1=50,param2=30,minRadius=0,maxRadius=0)
    if circles == None: 
        print "no circles found"
        return
    if len(circles) > 0:
        print "found circles ", len(circles[0])
        for i in circles[0]:
            cv2.circle(frame, (i[0], i[1]), i[2], (255, 0, 0), 1) # Perimeter
            cv2.circle(frame, (i[0], i[1]), 3, (0, 255, 0), -1) # Center

【讨论】:

  • 事实证明,在创建我的问题的简短示例时,我引入了一个最初不在我的代码中的错误,这就是您发现的。我稍微编辑了我的代码。现在没有找到圆圈时没有错误,但移动窗口仍然是一个问题。
  • 你能提供崩溃信息吗?你的运行环境是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 2019-04-01
  • 2014-10-24
相关资源
最近更新 更多