【发布时间】:2015-04-23 16:17:57
【问题描述】:
我编写了一个简单的 PyQt4 GUI,可以播放 OpenCV VideoCapture。这需要将帧从 numpy 数组转换为 QImages。我正在使用 OpenCV,以便可以使用我的 findCircles 方法检测圆圈。
但是,当我将帧传递给findCircles 时,移动窗口时程序会崩溃。当我不搜索圈子时,不会出现此问题。我不明白为什么会发生这种情况,因为我的印象是工作是在与 GUI 不同的线程上完成的,因为我从 QThread 的 run 方法调用 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