opencv pyqt video normal frame rate - python-3.x

I’m creating a special purpose video player in Python 3.6 using OpenCV3 and ffmepg for handling the images and using PyQt5 for the Windows environment. I chose this combination of packages because ffmpeg handles a wider variety of codecs than QtMultimedia.
I’ve run into one snag. My player does not play at regular speed – it plays at roughly ¾ of normal speed. I use QTimer.timer to loop my display engine (nextFrameSlot) at a speed of 1/framerate.
Any suggestions on how to get the video to play at regular speed? Here is an abbreviated set of code that demonstrates my problem.
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_())

Solved - I needed to specify self.timer.setTimerType(Qt.PreciseTimer) after the statement self.timer = QTimer() in the function start(self). By default, QTimer() uses a coarse timer. For Windows, the coarse time is 15.6 msec intervals.

Related

PyQt5 does not redrawing widget

Force repainting does not repaint PyQt5 widget (Qlabel, QTextEdit, even QProgressBar and etc)
Tested platforms: Linux, MacOS
PyQt5 version: 5.15.7
Installed from pip
As example I created simple app that updating text in QLabel widget in for loop. Force repainting doesnt working
import sys
from time import sleep
from PyQt5.QtWidgets import (QWidget, QApplication, QPushButton, QLabel)
class Example(QWidget):
def __init__(self):
super().__init__()
self.text = QLabel('Test', self)
self.text.move(10, 10)
self.text.resize(60,20)
self.button = QPushButton('Run', self)
self.button.move(17,40)
self.button.clicked.connect(self.some_activity)
self.setGeometry(300, 300, 100, 80)
self.show()
def some_activity(self):
for i in range(100):
text = f'i = {i}'
self.text.setText(text)
# self.text.update() -> Nothing happens (it shouldnt: https://doc.qt.io/qt-5/qwidget.html#update)
self.text.repaint() # -> Nothing happens
self.repaint() # -> Nothing happens
print(f'Text updated: {text}')
sleep(0.03)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Video demonstration: link
Just needed to use QThread to use for loop in my program
Thanks #musicamante for helping.
import sys
from time import sleep
from PyQt5 import QtCore
from PyQt5.QtWidgets import (QWidget, QApplication, QPushButton, QLabel)
class Thread(QtCore.QThread):
signal = QtCore.pyqtSignal(str)
def __init__(self, parent=None): QtCore.QThread.__init__(self, parent)
def run(self):
for i in range(100):
text = f'i = {i}'
print(f'Text updated: {text}')
self.signal.emit(text)
sleep(.3)
class Example(QWidget):
def __init__(self):
super().__init__()
self.text = QLabel('Test', self)
self.text.move(10, 10)
self.text.resize(60,20)
self.thread = Thread()
self.thread.signal.connect(self.signal, QtCore.Qt.QueuedConnection)
self.button = QPushButton('Run', self)
self.button.move(17,40)
self.button.clicked.connect(self.thread.start)
self.setGeometry(300, 300, 100, 80)
self.show()
def signal(self, text): self.text.setText(text)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

How to record the video from a webcam in a pyqt5 gui using OpenCV and QThread?

I'm trying to make pyqt5 Gui that shows a webcam live feed, records the feed at the same time, and saves it locally when closed. I managed to acheieve this using Timer(QTimer) in pyqt gui but When I try to implement it using Qthread (Which I really require) only the live feed is working.
Whenever I add Code required for recording video and run the program it says Python has Stopped Working and closes. Here is my Code:
import cv2
import sys
from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QVBoxLayout
from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QImage, QPixmap
class Thread(QThread):
changePixmap = pyqtSignal(QImage)
def run(self):
self.cap = cv2.VideoCapture(0)
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.codec = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D')
self.writer = cv2.VideoWriter('output.avi', self.codec, 30.0, (self.width, self.height))
while self.cap.isOpened():
ret, self.frame = self.cap.read()
if ret:
self.frame = cv2.flip(self.frame, 1)
rgbimage = cv2.cvtColor(self.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)
class MyApp(QWidget):
def __init__(self):
super(MyApp, self).__init__()
self.title = 'Camera'
self.initUI()
def initUI(self):
self.label = QLabel(self)
lay = QVBoxLayout()
lay.addWidget(self.label)
self.setLayout(lay)
self.th = Thread()
self.th.changePixmap.connect(self.setImage)
self.th.start()
self.show()
#pyqtSlot(QImage)
def setImage(self, image):
self.label.setPixmap(QPixmap.fromImage(image))
self.th.writer.write(image)
def main():
app = QApplication(sys.argv)
ex = MyApp()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I tried placing the .write() inside the run() of Thread class as well which is showing the same error. Can you guys point out What I'm doing wrong and how to make it work. I'm new to python and pyqt.
Thanks in Advance.
You need to separate threads. First thread is for signal, second is for the record and the main thread is for GUI. Try the following code. There is a button to start/stop the record.
import sys
import cv2
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QVBoxLayout
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, pyqtSlot
from PyQt5 import QtWidgets, QtCore, QtGui
#https://ru.stackoverflow.com/a/1150993/396441
class Thread1(QThread):
changePixmap = pyqtSignal(QImage)
def __init__(self, *args, **kwargs):
super().__init__()
def run(self):
self.cap1 = cv2.VideoCapture(0, cv2.CAP_DSHOW)
self.cap1.set(3,480)
self.cap1.set(4,640)
self.cap1.set(5,30)
while True:
ret1, image1 = self.cap1.read()
if ret1:
im1 = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)
height1, width1, channel1 = im1.shape
step1 = channel1 * width1
qImg1 = QImage(im1.data, width1, height1, step1, QImage.Format_RGB888)
self.changePixmap.emit(qImg1)
class Thread2(QThread):
def __init__(self, *args, **kwargs):
super().__init__()
self.active = True
def run(self):
if self.active:
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
self.out1 = cv2.VideoWriter('output.avi', self.fourcc, 30, (640,480))
self.cap1 = cv2.VideoCapture(0, cv2.CAP_DSHOW)
self.cap1.set(3, 480)
self.cap1.set(4, 640)
self.cap1.set(5, 30)
while self.active:
ret1, image1 = self.cap1.read()
if ret1:
self.out1.write(image1)
self.msleep(10)
def stop(self):
self.out1.release()
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.resize(660, 520)
self.control_bt = QPushButton('START')
self.control_bt.clicked.connect(self.controlTimer)
self.image_label = QLabel()
self.saveTimer = QTimer()
self.th1 = Thread1(self)
self.th1.changePixmap.connect(self.setImage)
self.th1.start()
vlayout = QVBoxLayout(self)
vlayout.addWidget(self.image_label)
vlayout.addWidget(self.control_bt)
#QtCore.pyqtSlot(QImage)
def setImage(self, qImg1):
self.image_label.setPixmap(QPixmap.fromImage(qImg1))
def controlTimer(self):
if not self.saveTimer.isActive():
# write video
self.saveTimer.start()
self.th2 = Thread2(self)
self.th2.active = True
self.th2.start()
# update control_bt text
self.control_bt.setText("STOP")
else:
# stop writing
self.saveTimer.stop()
self.th2.active = False
self.th2.stop()
self.th2.terminate()
# update control_bt text
self.control_bt.setText("START")
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
you placed the .write() inside the run() of Thread class is right way.
like:
...
while self.cap.isOpened():
ret, self.frame = self.cap.read()
if ret:
self.frame = cv2.flip(self.frame, 1)
rgbimage = cv2.cvtColor(self.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)
# put your writer() here, make sure your param is frame
# not converted to QtImage format
self.writer.write(rgbimage)
self.changePixmap.emit(p)
...

PyQt5 add second function to thread but not work

Previously I have tried to use Flask for doing the followings simultaneously:
Display live video streaming
Display real-time data streaming
Control the robot car
As the above is just for demonstration, with the video streaming performance not good enough, I decided to change the whole application to PyQt5 for further development and production. Now I can create the GUI for displaying live video streaming well, while the real-time data streaming cannot be done well. The error is
QObject::startTimer: Timers can only be used with threads started with QThread
The following is the whole program. Please help to see what's wrong in the adding thread issue. Thanks!
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
import cv2
from vidgear.gears import CamGear
from random import random
data_list=[]
fps=60
options_cam={"CAP_PROP_FRAME_WIDTH":640,"CAP_PROP_FRAME_HEIGHT":480,"CAP_PROP_FPS":fps}
stream=CamGear(source=0,logging=False,**options_cam).start()
class MainWindow(QtWidgets.QWidget):
def __init__(self,*args):
super(MainWindow, self).__init__()
self.setWindowTitle('Vehicle control')
self.grid_layout=QtWidgets.QGridLayout()
self.video_label = QtWidgets.QLabel('Video streaming',self)
self.video_frame = QtWidgets.QLabel(self)
self.grid_layout.addWidget(self.video_label,0,0)
self.grid_layout.addWidget(self.video_frame,1,0)
self.data_label = QtWidgets.QLabel('Data streaming',self)
self.data_frame = QtWidgets.QListWidget(self)
self.grid_layout.addWidget(self.data_label,0,1)
self.grid_layout.addWidget(self.data_frame,1,1)
self.setLayout(self.grid_layout)
#self.thread=QtCore.QThread()
#self.thread.started.connect(self.nextFrameSlot)
#self.thread.start()
self.timer=QtCore.QTimer()
self.timer.timeout.connect(self.video_stream)
self.timer.start(0)
self.thread=QtCore.QThread()
self.thread.start()
self.timer2=QtCore.QTimer()
self.timer2.moveToThread(self.thread)
self.timer2.timeout.connect(self.data_stream)
self.timer2.start(0)
def video_stream(self):
frame = stream.read()
# My webcam yields frames in BGR format
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = QtGui.QImage(frame, frame.shape[1], frame.shape[0], QtGui.QImage.Format_RGB888)
pix = QtGui.QPixmap.fromImage(img)
self.video_frame.setPixmap(pix)
QtCore.QThread.sleep(0)
def data_stream(self):
print("data stream")
stream_data=round(random()*10,3)
data_list.insert(0,str(stream_data)+'\n')
if len(data_list)>10:
del data_list[-1]
for i in range(len(data_list)):
self.data_frame.addItem(data_list[i])
self.data_frame.show()
QtCore.QThread.sleep(1000)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Edit:
Thanks #musicamante's answer. I have updated the code as follows but still have the error "segmentation fault" for the video streaming, while if I run for data stream only, the updated list can be shown. So what's wrong with the setPixmap function? Thanks again!
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
import cv2
from vidgear.gears import CamGear
from random import random
fps=60
options_cam={"CAP_PROP_FRAME_WIDTH":480,"CAP_PROP_FRAME_HEIGHT":480,"CAP_PROP_FPS":fps}
stream=CamGear(source=0,logging=False,**options_cam).start()
class CamGrabber(QtCore.QThread):
frame = QtCore.pyqtSignal(QtGui.QImage)
def run(self):
while True:
new_frame = stream.read()
new_frame = cv2.cvtColor(new_frame, cv2.COLOR_BGR2RGB)
img = QtGui.QImage(new_frame, new_frame.shape[1], new_frame.shape[0], QtGui.QImage.Format_RGB888)
self.frame.emit(img)
class DataProvider(QtCore.QThread):
data = QtCore.pyqtSignal(object)
def run(self):
while True:
newData = round(random()*10,3)
self.data.emit(newData)
QtCore.QThread.sleep(1)
class MainWindow(QtWidgets.QWidget):
def __init__(self,*args):
super(MainWindow, self).__init__()
self.setWindowTitle('Vehicle control')
self.grid_layout=QtWidgets.QGridLayout()
self.video_label = QtWidgets.QLabel('Video streaming',self)
self.video_frame = QtWidgets.QLabel(self)
self.grid_layout.addWidget(self.video_label,0,0)
self.grid_layout.addWidget(self.video_frame,1,0)
self.data_label = QtWidgets.QLabel('Data streaming',self)
self.data_frame = QtWidgets.QListWidget(self)
self.grid_layout.addWidget(self.data_label,0,1)
self.grid_layout.addWidget(self.data_frame,1,1)
self.setLayout(self.grid_layout)
self.camObject = CamGrabber()
self.camObject.frame.connect(self.newFrame)
self.camObject.start()
self.dataProvider = DataProvider()
self.dataProvider.data.connect(self.newData)
self.dataProvider.start()
def newFrame(self, img):
self.video_frame.setPixmap(QtGui.QPixmap.fromImage(img))
def newData(self, data):
self.data_frame.insertItem(0,str(data))
if self.data_frame.count() > 10:
self.data_frame.takeItem(9)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())```
The QTimer error basically means that the a QTimer can only be started from the thread it exists.
Besides that, GUI element should always be directly accessed or modified from the main thread, not from another one.
In order to accomplish that, you'll need to create a separate "worker" thread, and communicate with the main one by taking advantage of the signal/slot mechanism.
class CamGrabber(QtCore.QThread):
frame = QtCore.pyqtSignal(QtGui.QImage)
def run(self):
while True:
frame = stream.read()
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
img = QtGui.QImage(frame, frame.shape[1], frame.shape[0], QtGui.QImage.Format_RGB888)
self.frame.emit(img)
class DataProvider(QtCore.QThread):
data = QtCore.pyqtSignal(object)
def run(self):
while True:
newData = round(random()*10,3)
self.data.emit(newData)
# note that QThread.sleep unit is seconds, not milliseconds
QtCore.QThread.sleep(1)
class MainWindow(QtWidgets.QWidget):
def __init__(self,*args):
super(MainWindow, self).__init__()
self.setWindowTitle('Vehicle control')
self.grid_layout=QtWidgets.QGridLayout()
self.video_label = QtWidgets.QLabel('Video streaming',self)
self.video_frame = QtWidgets.QLabel(self)
self.grid_layout.addWidget(self.video_label,0,0)
self.grid_layout.addWidget(self.video_frame,1,0)
self.data_label = QtWidgets.QLabel('Data streaming',self)
self.data_frame = QtWidgets.QListWidget(self)
self.grid_layout.addWidget(self.data_label,0,1)
self.grid_layout.addWidget(self.data_frame,1,1)
self.setLayout(self.grid_layout)
self.camObject = CamGrabber()
self.camObject.frame.connect(self.newFrame)
self.camObject.start()
self.dataProvider = DataProvider()
self.dataProvider.data.connect(self.newData)
self.dataProvider.start()
def newFrame(self, img):
self.video_frame.setPixmap(QtGui.QPixmap.fromImage(img))
def newData(self, data):
self.data_frame.addItem(str(data))
if self.data_frame.count() > 10:
self.data_frame.takeItem(0)
If, for any reason, you want to control the data fetching from the main thread via a QTimer, you could use a Queue:
from queue import Queue
class DataProvider(QtCore.QObject):
data = QtCore.pyqtSignal(object)
def __init__(self):
super().__init__()
self.queue = Queue()
def run(self):
while True:
multi = self.queue.get()
# simulate a time consuming process
QtCore.QThread.sleep(5)
newData = round(multi * 10, 3)
self.data.emit(newData)
def pushData(self, data):
self.queue.put(data)
class MainWindow(QtWidgets.QWidget):
def __init__(self,*args):
# ...
self.requestTimer = QtCore.QTimer()
self.requestTimer.setInterval(1000)
self.requestTimer.timeout.connect(self.requestData)
# this will cause the timer to be executed only once after each time
# start() is called, so no new requests will overlap
self.requestTimer.setSingleShot(True)
self.requestTimer.start()
def requestData(self):
value = random()
print('requesting data with value {}'.format(value))
self.dataProvider.pushData(value)
print('waiting for result')
def newFrame(self, img):
self.video_frame.setPixmap(QtGui.QPixmap.fromImage(img))
def newData(self, data):
print('data received')
self.data_frame.addItem(str(data))
if self.data_frame.count() > 10:
self.data_frame.takeItem(0)
# restart the timer
self.requestTimer.start()

PyQt change picture with keyboard button

this is my first post here and I haven't seen it anywhere so hopefully it is ok. I am trying to change the displayed image with a keyboard click (think slideshow). This is my code so far:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
import os
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Document Analysis'
self.left = 30
self.top = 30
self.width = 640
self.height = 480
self.imagenumber=0
self.initUI()
def keyPressEvent(self, event):
key=event.key()
if key==Qt.Key_Right:
self.imagenumber=self.imagenumber+1
self.showimage(self.imagenumber)
self.show()
else:
super(self).keyPressEvent(event)
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.showimage(0)
self.show()
def showimage(self,imagenumber):
label = QLabel(self)
directory = "C:\\Desktop\\Pictures"
imagelist = os.listdir(directory)
pixmap = QPixmap(directory + '\\' + imagelist[imagenumber])
label.setPixmap(pixmap)
self.resize(pixmap.width() + 500, pixmap.height())
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
It seems to be sort of getting somewhere, the first image displays just fine, and I know imagenumber does change, and when I stopped it from showing at first it resized the window but still didn't show the image. Any suggestions on what I am doing wrong?
This is part of a larger project which is the reason for the extra space on the side of the picture, but help would be appreciated.
You're close. Try the following...
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
import os
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Document Analysis'
self.left = 30
self.top = 30
self.width = 640
self.height = 480
self.imagenumber=0
self.initUI()
def keyPressEvent(self, event):
key=event.key()
if key==Qt.Key_Right:
self.imagenumber=self.imagenumber+1
self.showimage(self.imagenumber)
# self.show()
else:
super(self).keyPressEvent(event)
def initUI(self):
layout = QVBoxLayout()
self.setLayout(layout)
self.label = QLabel(self)
layout.addWidget(self.label)
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.showimage(0)
self.show()
def showimage(self,imagenumber):
# label = QLabel(self)
directory = "C:\\Desktop\\Pictures"
imagelist = os.listdir(directory)
pixmap = QPixmap(directory + '\\' + imagelist[imagenumber])
# label.setPixmap(pixmap)
self.label.setPixmap(pixmap)
self.resize(pixmap.width() + 500, pixmap.height())
# self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Mainly, you need a persistent label. You also only need to call show() once.

Video Speed is too first in PyQt5, Opencv

When i run this code the video speed is very fast. Maybe it is happening because of the frame rate(because different frame rate is used for HD and FHD). How can i solve the issue and fixed the frame rate.i use cap.set(15,-.8) to slow down the frame rate but it doesn't work.The video size is 1080p(full HD).
import sys
import cv2
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtWidgets import QApplication, QWidget, QLabel
import datetime
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'PyQt5 Video'
self.left = 100
self.top = 100
self.width = 640
self.height = 480
self.initUI()
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
self.resize(1800, 1200)
# create a label
# create a label
label = QLabel(self)
label.move(280, 120)
label.resize(640, 480)
label1 = QLabel(self)
label1.move(580, 620)
self.th = Thread(self)
self.th.changePixmap.connect(label.setPixmap)
self.th.changeLabel.connect(label1.setText)
self.th.start()
def closeEvent(self, event):
self.th.stop()
QWidget.closeEvent(self, event)
class Thread(QThread):
changePixmap = pyqtSignal(QPixmap)
changeLabel = pyqtSignal(str)
def __init__(self, parent=None):
QThread.__init__(self, parent=parent)
self.isRunning = True
def run(self):
cap = cv2.VideoCapture('a.mp4')
while self.isRunning:
ret, frame = cap.read()
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
convertToQtFormat = QImage(rgbImage.data, rgbImage.shape[1], rgbImage.shape[0], QImage.Format_RGB888)
convertToQtFormat = QPixmap.fromImage(convertToQtFormat)
p = convertToQtFormat.scaled(640, 400, Qt.KeepAspectRatio)
self.changePixmap.emit(p)
now = datetime.datetime.now()
sec = now.second
self.changeLabel.emit(str(sec))
def stop(self):
self.isRunning = False
self.quit()
self.wait()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
ex.show()
sys.exit(app.exec_())

Resources