Multithreading PyQt4视频播放器在移动窗口时崩溃
我已经编写了一个简单的PyQt4 GUI,它可以播放OpenCVMultithreading PyQt4视频播放器在移动窗口时崩溃,multithreading,python-2.7,opencv,numpy,pyqt4,Multithreading,Python 2.7,Opencv,Numpy,Pyqt4,我已经编写了一个简单的PyQt4 GUI,它可以播放OpenCVVideoCapture。这需要将帧从numpy数组转换为QImages。我正在使用OpenCV,以便使用findCircles方法检测圆 但是,当我将帧传递给findCircles时,当窗口移动时,程序崩溃。如果不搜索圆,则不会出现此问题。我不明白为什么会发生这种情况,因为我的印象是工作是在不同于GUI的线程上完成的,因为我从QThread的run方法调用findCircles 请注意,我在控制台中没有收到正常的错误消息;Pyth
VideoCapture
。这需要将帧从numpy数组转换为QImages
。我正在使用OpenCV,以便使用findCircles
方法检测圆
但是,当我将帧传递给findCircles
时,当窗口移动时,程序崩溃。如果不搜索圆,则不会出现此问题。我不明白为什么会发生这种情况,因为我的印象是工作是在不同于GUI的线程上完成的,因为我从QThread
的run
方法调用findCircles
请注意,我在控制台中没有收到正常的错误消息;Python崩溃如下:
是我用来测试播放器的视频文件。我正在Windows8.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_())
导入系统
将cv2.cv导入为cv,cv2
从PyQt4.Qt导入*
导入时间
def numpyArrayToQImage(阵列):
如果数组!=无:
高度、宽度、bytesPerComponent=array.shape
bytesPerLine=bytesPerComponent*宽度;
cv2.CVT颜色(数组,cv.cv_BGR2RGB,数组)
返回QImage(array.data、宽度、高度、bytesPerLine、QImage.Format_RGB888)
一无所获
def findCircles(帧):
grayFrame=cv2.CVT颜色(frame,cv2.COLOR\u BGR2GRAY)
模糊帧=cv2.medianBlur(灰色帧,3)
圆=cv2。霍夫圆(模糊帧,cv.cv_霍夫_渐变,1,30,参数1=50,参数2=30,最小半径=30,最大半径=35)
如果圆不是无:
对于圆[0]中的i:
cv2.圆(帧,(i[0],i[1]),i[2],(255,0,0),1)#周长
cv2.圆(帧,(i[0],i[1]),3,(0,255,0),-1)#中心
类VideoThread(QThread):
frameProcessed=pyqtSignal(QImage)
定义初始化(自我、视频、视频标签):
QThread.\uuuu init\uuuu(self)
self.video=视频
self.fps=self.video.get(cv.cv\u CAP\u PROP\u fps)
self.frameCount=self.video.get(cv.cv\u CAP\u PROP\u FRAME\u COUNT)
self.startingSecond=0
self.videoLabel=videoLabel
def运行(自):
clockAtStart=time.clock()
尽管如此:
运行时=self.startingSecond+(time.clock()-clockAtStart)
currentFrame=int(运行时*self.fps)
如果currentFrameTraceback (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()
我在findCircles(frame)
函数中做了如下更改,即使在屏幕上移动窗口时,它也不会出错
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
是否尝试从函数findCircles返回帧?
findCircles
方法在帧顶部绘制找到的圆,从而改变帧对象。没有必要返回任何内容。你能提供一个示例视频来测试你的程序吗?我无法用当前的示例脚本重现这个问题。代码似乎能够在显示一些硬币的简单视频中找到圆圈,尽管这样做非常不一致。但是,在显示视频时不断移动窗口没有效果。这是在Linux上,使用Python2.7.9、qt 4.8.6和pyqt 4.11.3。尝试使用Python2.7.9可以发现,在创建问题的一个简短示例时,我引入了一个最初不在代码中的错误,这就是您发现的错误。我稍微编辑了我的代码。现在没有发现圆圈时没有错误,但是移动窗口仍然是一个问题。你能提供崩溃消息吗?你的跑步环境是什么?