Python 3.x opencv pyqt视频正常帧速率
我正在用Python3.6创建一个特殊用途的视频播放器,使用OpenCV3和ffmepg处理图像,并在Windows环境中使用PyQt5。我之所以选择这种软件包组合,是因为ffmpeg处理的编解码器比QT多媒体更广泛 我遇到了一个障碍。我的球员不是以正常速度打球,而是以正常速度的¾左右打球。我使用QTimer.timer以1/帧速率的速度循环显示引擎(nextFrameSlot) 关于如何让视频以正常速度播放有什么建议吗?下面是一组简短的代码,演示了我的问题Python 3.x opencv pyqt视频正常帧速率,python-3.x,pyqt5,opencv3.0,Python 3.x,Pyqt5,Opencv3.0,我正在用Python3.6创建一个特殊用途的视频播放器,使用OpenCV3和ffmepg处理图像,并在Windows环境中使用PyQt5。我之所以选择这种软件包组合,是因为ffmpeg处理的编解码器比QT多媒体更广泛 我遇到了一个障碍。我的球员不是以正常速度打球,而是以正常速度的¾左右打球。我使用QTimer.timer以1/帧速率的速度循环显示引擎(nextFrameSlot) 关于如何让视频以正常速度播放有什么建议吗?下面是一组简短的代码,演示了我的问题 import sys from Py
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QFormLayout, QPushButton, QMainWindow
from PyQt5.QtWidgets import QAction, QMessageBox, QApplication, QFileDialog
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import QTimer
import cv2
class VideoCapture(QWidget):
def __init__(self, filename, parent):
super(QWidget, self).__init__()
self.cap = cv2.VideoCapture(str(filename[0]))
self.length = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT))
self.frame_rate = self.cap.get(cv2.CAP_PROP_FPS)
#self.codec = self.cap.get(cv2.CAP_PROP_FOURCC)
self.video_frame = QLabel()
parent.layout.addWidget(self.video_frame)
def nextFrameSlot(self):
ret, frame = self.cap.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = QImage(frame, frame.shape[1], frame.shape[0], QImage.Format_RGB888)
pix = QPixmap.fromImage(img)
self.video_frame.setPixmap(pix)
def start(self):
self.timer = QTimer()
self.timer.timeout.connect(self.nextFrameSlot)
self.timer.start(1000.0/self.frame_rate)
def pause(self):
self.timer.stop()
def deleteLater(self):
self.cap.release()
super(QWidget, self).deleteLater()
class VideoDisplayWidget(QWidget):
def __init__(self,parent):
super(VideoDisplayWidget, self).__init__(parent)
self.layout = QFormLayout(self)
self.startButton = QPushButton('Start', parent)
self.startButton.clicked.connect(parent.startCapture)
self.startButton.setFixedWidth(50)
self.pauseButton = QPushButton('Pause', parent)
self.pauseButton.setFixedWidth(50)
self.layout.addRow(self.startButton, self.pauseButton)
self.setLayout(self.layout)
class ControlWindow(QMainWindow):
def __init__(self):
super(ControlWindow, self).__init__()
self.setGeometry(50, 50, 800, 600)
self.setWindowTitle("PyTrack")
self.capture = None
self.isVideoFileLoaded = False
self.quitAction = QAction("&Exit", self)
self.quitAction.setShortcut("Ctrl+Q")
self.quitAction.triggered.connect(self.closeApplication)
self.openVideoFile = QAction("&Open Video File", self)
self.openVideoFile.setShortcut("Ctrl+Shift+V")
self.openVideoFile.triggered.connect(self.loadVideoFile)
self.mainMenu = self.menuBar()
self.fileMenu = self.mainMenu.addMenu('&File')
self.fileMenu.addAction(self.openVideoFile)
self.fileMenu.addAction(self.quitAction)
self.videoDisplayWidget = VideoDisplayWidget(self)
self.setCentralWidget(self.videoDisplayWidget)
def startCapture(self):
if not self.capture and self.isVideoFileLoaded:
self.capture = VideoCapture(self.videoFileName, self.videoDisplayWidget)
self.videoDisplayWidget.pauseButton.clicked.connect(self.capture.pause)
self.capture.start()
def endCapture(self):
self.capture.deleteLater()
self.capture = None
def loadVideoFile(self):
try:
self.videoFileName = QFileDialog.getOpenFileName(self, 'Select a Video File')
self.isVideoFileLoaded = True
except:
print ("Please Select a Video File")
def closeApplication(self):
choice = QMessageBox.question(self, 'Message','Do you really want to exit?',QMessageBox.Yes | QMessageBox.No)
if choice == QMessageBox.Yes:
print("Closing....")
sys.exit()
else:
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
window = ControlWindow()
window.show()
sys.exit(app.exec_())
已解决-我需要在函数
start(self)
中的语句self.timer=QTimer()
之后指定self.timer.settimer类型(Qt.PreciseTimer)
。默认情况下,QTimer()使用粗略计时器。对于Windows,粗略时间间隔为15.6毫秒。您分析过运行nextFrameSlot()
需要多长时间吗?MP4文件,1280x720,avc1编解码器,29.97 fps:avg=12.6毫秒,stdev=9毫秒。AVI文件,640x480,XVID编解码器,30 fps:avg=3ms,stdev=2毫秒。更新:上面引用的那些avg和stdev编号仅用于下一帧插槽。当QTimer.timer所需的额外时间将整个循环时间增加到约47毫秒时,这超过了所需的33毫秒。除了QTimer.timer之外,还有没有更快的方法调用调用nextFrameSlot?我很惊讶计时器中有这么多开销。您可以尝试使用QCoreApplication.postEvent()
Solved将高优先级直接注入事件循环-我需要指定self.timer.setTimerType(Qt.PreciseTimer)
。默认情况下,QTimer()使用粗计时器。对于Windows,粗略时间间隔为15.6毫秒。