fbpixel
Étiquettes : , ,

Pour certaines applications, il vous sera peut-être utile d’embarquer OpenCV dans une interface PyQt. Nous allons voir dans ce tutoriel comment intégrer et gérer correctement une vidéo capturée par OpenCV dans une application PyQt.

N.B.: Nous utilisons Pyside mais la conversion vers PyQt se fait assez simplement.

Pré-requis:

  • Installation de Python
  • Installation OpenCV (pip install opencv-python)
  • PySide ou PyQt (pip install pyside6 ou pip install PyQt5)

Code pour capturer une vidéo avec OpenCV

Voici le code de base pour afficher la vidéo d’une webcam avec openCV

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import sys
import cv2
def main(args):
cap = cv2.VideoCapture(0) #default camera
while(True):
ret, frame = cap.read()
if ret:
frame=cv2.resize(frame, (800, 600))
cv2.imshow("Video",frame)
if cv2.waitKey(1) & 0xFF == ord('q'): #click q to stop capturing
break
cap.release()
cv2.destroyAllWindows()
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
import sys import cv2 def main(args): cap = cv2.VideoCapture(0) #default camera while(True): ret, frame = cap.read() if ret: frame=cv2.resize(frame, (800, 600)) cv2.imshow("Video",frame) if cv2.waitKey(1) & 0xFF == ord('q'): #click q to stop capturing break cap.release() cv2.destroyAllWindows() return 0 if __name__ == '__main__': sys.exit(main(sys.argv))
import sys
import cv2

def main(args):

	cap = cv2.VideoCapture(0) #default camera

	while(True):
		ret, frame = cap.read()
		if ret:
			frame=cv2.resize(frame, (800, 600)) 
			cv2.imshow("Video",frame)
			
		if cv2.waitKey(1) & 0xFF == ord('q'): #click q to stop capturing
			break

	cap.release()
	cv2.destroyAllWindows()
	return 0

if __name__ == '__main__':
    
    sys.exit(main(sys.argv))

Pour l’intégrer dans une application PyQt, nous allons créer un objet QThread qui sera chargé de lire la vidéo sans bloquer l’application.

  • La fonction run est la fonction contenant le code openCV qui va tourner en boucle à l’appel de la fonction QThread.start
  • La fonction stop permet d’arrêter proprement le thread
  • Le signal changePixmap permet de signaler à l’application qu’une nouvelle image est disponible
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class Thread(QThread):
changePixmap = pyqtSignal(QImage)
def run(self):
self.isRunning=True
cap = cv2.VideoCapture(0)
while self.isRunning:
ret, frame = cap.read()
if ret:
rgbImage = cv2.cvtColor(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)
def stop(self):
self.isRunning=False
self.quit()
self.terminate()
class Thread(QThread): changePixmap = pyqtSignal(QImage) def run(self): self.isRunning=True cap = cv2.VideoCapture(0) while self.isRunning: ret, frame = cap.read() if ret: rgbImage = cv2.cvtColor(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) def stop(self): self.isRunning=False self.quit() self.terminate()
class Thread(QThread):
	changePixmap = pyqtSignal(QImage)

	def run(self):
		self.isRunning=True
		cap = cv2.VideoCapture(0)
		while self.isRunning:
			ret, frame = cap.read()
			if ret:
				rgbImage = cv2.cvtColor(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)
				
	def stop(self):
		self.isRunning=False
		self.quit()
		self.terminate()

Création de l’application PyQt

Pour l’application, nous allons créer un QLabel dans un simple QWidget qui va contenir l’image de la vidéo et instancier le QThread. La vidéo se mettra à jour automatiquement à l’aide de la fonction setImage qui est appelée à la réception du signal changePixmap.

  • fonction setImage
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@pyqtSlot(QImage)
def setImage(self, image):
#update image
self.label.setPixmap(QPixmap.fromImage(image))
@pyqtSlot(QImage) def setImage(self, image): #update image self.label.setPixmap(QPixmap.fromImage(image))
	@pyqtSlot(QImage)
	def setImage(self, image):
		#update image	
		self.label.setPixmap(QPixmap.fromImage(image))
  • signal changePixmap
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
self.th.changePixmap.connect(self.setImage)
self.th.changePixmap.connect(self.setImage)
		self.th.changePixmap.connect(self.setImage)
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class VideoContainer(QWidget):
def __init__(self):
super().__init__()
self.title = 'PySide Video'
self.left = 100
self.top = 100
self.fwidth = 640
self.fheight = 480
self.initUI()
@pyqtSlot(QImage)
def setImage(self, image):
#update image
self.label.setPixmap(QPixmap.fromImage(image))
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.fwidth, self.fheight)
self.resize(1200, 800)
# create a label
self.label = QLabel(self)
self.label.resize(640, 480)
self.th = Thread(self)
self.th.changePixmap.connect(self.setImage)
self.th.start()
self.show()
class VideoContainer(QWidget): def __init__(self): super().__init__() self.title = 'PySide Video' self.left = 100 self.top = 100 self.fwidth = 640 self.fheight = 480 self.initUI() @pyqtSlot(QImage) def setImage(self, image): #update image self.label.setPixmap(QPixmap.fromImage(image)) def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.fwidth, self.fheight) self.resize(1200, 800) # create a label self.label = QLabel(self) self.label.resize(640, 480) self.th = Thread(self) self.th.changePixmap.connect(self.setImage) self.th.start() self.show()
class VideoContainer(QWidget):
	def __init__(self):
		super().__init__()
		self.title = 'PySide Video'
		self.left = 100
		self.top = 100
		self.fwidth = 640
		self.fheight = 480
		self.initUI()

	@pyqtSlot(QImage)
	def setImage(self, image):
		#update image	
		self.label.setPixmap(QPixmap.fromImage(image)) 
	
	def initUI(self):
		self.setWindowTitle(self.title)
		self.setGeometry(self.left, self.top, self.fwidth, self.fheight)
		self.resize(1200, 800)
		
		# create a label
		self.label = QLabel(self)		
		self.label.resize(640, 480)
		self.th = Thread(self)
		self.th.changePixmap.connect(self.setImage)
		self.th.start()
		self.show()

Code complet pour afficher une vidéo dans une fenêtre PyQt

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import cv2
import sys
#from PyQt5.QtWidgets import QWidget, QLabel, QApplication
#from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot
#from PyQt5.QtGui import QImage, QPixmap
from PySide6.QtWidgets import QWidget, QLabel, QApplication
from PySide6.QtCore import QThread, Qt, Signal, Slot
from PySide6.QtGui import QImage, QPixmap
pyqtSignal = Signal
pyqtSlot = Slot
class Thread(QThread):
changePixmap = pyqtSignal(QImage)
def run(self):
self.isRunning=True
cap = cv2.VideoCapture(0)
while self.isRunning:
ret, frame = cap.read()
if ret:
# https://stackoverflow.com/a/55468544/6622587
rgbImage = cv2.cvtColor(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)
def stop(self):
self.isRunning=False
self.quit()
self.terminate()
class VideoContainer(QWidget):
def __init__(self):
super().__init__()
self.title = 'Video'
self.left = 100
self.top = 100
self.fwidth = 640
self.fheight = 480
self.initUI()
@pyqtSlot(QImage)
def setImage(self, image):
#update image
self.label.setPixmap(QPixmap.fromImage(image))
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.fwidth, self.fheight)
self.resize(1200, 800)
# create a label
self.label = QLabel(self)
self.label.resize(640, 480)
self.th = Thread(self)
self.th.changePixmap.connect(self.setImage)
self.th.start()
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = VideoContainer()
sys.exit(app.exec())
import cv2 import sys #from PyQt5.QtWidgets import QWidget, QLabel, QApplication #from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot #from PyQt5.QtGui import QImage, QPixmap from PySide6.QtWidgets import QWidget, QLabel, QApplication from PySide6.QtCore import QThread, Qt, Signal, Slot from PySide6.QtGui import QImage, QPixmap pyqtSignal = Signal pyqtSlot = Slot class Thread(QThread): changePixmap = pyqtSignal(QImage) def run(self): self.isRunning=True cap = cv2.VideoCapture(0) while self.isRunning: ret, frame = cap.read() if ret: # https://stackoverflow.com/a/55468544/6622587 rgbImage = cv2.cvtColor(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) def stop(self): self.isRunning=False self.quit() self.terminate() class VideoContainer(QWidget): def __init__(self): super().__init__() self.title = 'Video' self.left = 100 self.top = 100 self.fwidth = 640 self.fheight = 480 self.initUI() @pyqtSlot(QImage) def setImage(self, image): #update image self.label.setPixmap(QPixmap.fromImage(image)) def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.fwidth, self.fheight) self.resize(1200, 800) # create a label self.label = QLabel(self) self.label.resize(640, 480) self.th = Thread(self) self.th.changePixmap.connect(self.setImage) self.th.start() self.show() if __name__ == '__main__': app = QApplication(sys.argv) ex = VideoContainer() sys.exit(app.exec())
import cv2
import sys
#from PyQt5.QtWidgets import  QWidget, QLabel, QApplication
#from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot
#from PyQt5.QtGui import QImage, QPixmap

from PySide6.QtWidgets import  QWidget, QLabel, QApplication
from PySide6.QtCore import QThread, Qt, Signal, Slot
from PySide6.QtGui import QImage, QPixmap
pyqtSignal = Signal
pyqtSlot = Slot

class Thread(QThread):
	changePixmap = pyqtSignal(QImage)

	def run(self):
		self.isRunning=True
		cap = cv2.VideoCapture(0)
		while self.isRunning:
			ret, frame = cap.read()
			if ret:
				# https://stackoverflow.com/a/55468544/6622587
				rgbImage = cv2.cvtColor(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)
				
	def stop(self):
		self.isRunning=False
		self.quit()
		self.terminate()

class VideoContainer(QWidget):
	def __init__(self):
		super().__init__()
		self.title = 'Video'
		self.left = 100
		self.top = 100
		self.fwidth = 640
		self.fheight = 480
		self.initUI()

	@pyqtSlot(QImage)
	def setImage(self, image):
		#update image	
		self.label.setPixmap(QPixmap.fromImage(image)) 
	
	def initUI(self):
		self.setWindowTitle(self.title)
		self.setGeometry(self.left, self.top, self.fwidth, self.fheight)
		self.resize(1200, 800)
		
		# create a label
		self.label = QLabel(self)		
		self.label.resize(640, 480)
		self.th = Thread(self)
		self.th.changePixmap.connect(self.setImage)
		self.th.start()
		self.show()

if __name__ == '__main__':
	
		app = QApplication(sys.argv)
		ex = VideoContainer()
		sys.exit(app.exec())

Une fenêtre « Video » apparait contenant l’image provenant de la webcam.

pyqt-opencv-result Afficher une Image d'OpenCV dans une interface PyQt

Vous pouvez adapter ce code simple pour intégrer une vidéo à un interface graphique qui permet de modifier les option vidéo ou travailler avec des filtres, par exemple.

Bonus:amélioration de l’interface fermeture/dimension

Le code fonctionne bien et peut être suffisant mais quelques problèmes sont présents avec cette implémentation:

  • On ne peut pas fermer l’application avec Ctrl+C (KeyboardInterrupt)
  • Lorsqu’on ferme la fenêtre le Qthread ne s’arrête pas
  • Si on redimensionne la fenêtre la taille de la vidéo ne bouge pas

Pour fermer l’application avec Ctrl+C, il est possible d’utiliser le signal d’interruption pour cela il suffit de rajouter le code suivant avant l’appel de l’application (il existe des méthodes plus propres)

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import signal #close signal with Ctrl+C
signal.signal(signal.SIGINT, signal.SIG_DFL)
import signal #close signal with Ctrl+C signal.signal(signal.SIGINT, signal.SIG_DFL)
import signal #close signal with Ctrl+C
signal.signal(signal.SIGINT, signal.SIG_DFL)

Pour terminer le QThread à la fermeture de la fenêtre, on peut utiliser le signal aboutToQuit de l’application pour appeler la fonction stop du QThread

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
app.aboutToQuit.connect(ex.th.stop) #stop qthread when closing window
app.aboutToQuit.connect(ex.th.stop) #stop qthread when closing window
app.aboutToQuit.connect(ex.th.stop) #stop qthread when closing window

Enfin, pour redimensionner la vidéo avec le fenêtre à chaque rafraichissement, nous utilisons la taille de la fenêtre pour calculer la taille de l’image et la position du label pour qu’il soit centré et que la vidéo garde ses proportions.

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
@pyqtSlot(QImage)
def setImage(self, image):
#resize image with window and center
imWidth=self.width()-2*self.padding
imHeight=self.height()-2*self.padding
image = image.scaled(imWidth, imHeight, Qt.KeepAspectRatio) # remove Qt.KeepAspectRatio if not needed
self.label.resize(image.width(), image.height()) #(640, 480)
self.label.move((self.width()-image.width())/2, (self.height()-image.height())/2)
#update image
self.label.setPixmap(QPixmap.fromImage(image))
@pyqtSlot(QImage) def setImage(self, image): #resize image with window and center imWidth=self.width()-2*self.padding imHeight=self.height()-2*self.padding image = image.scaled(imWidth, imHeight, Qt.KeepAspectRatio) # remove Qt.KeepAspectRatio if not needed self.label.resize(image.width(), image.height()) #(640, 480) self.label.move((self.width()-image.width())/2, (self.height()-image.height())/2) #update image self.label.setPixmap(QPixmap.fromImage(image))
	@pyqtSlot(QImage)
	def setImage(self, image):
		#resize image with window and center
		imWidth=self.width()-2*self.padding
		imHeight=self.height()-2*self.padding
		image = image.scaled(imWidth, imHeight, Qt.KeepAspectRatio) # remove Qt.KeepAspectRatio if not needed
		self.label.resize(image.width(), image.height()) #(640, 480)
		self.label.move((self.width()-image.width())/2, (self.height()-image.height())/2)
			
		#update image	
		self.label.setPixmap(QPixmap.fromImage(image)) 

Voici le code complet avec amélioration

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import cv2
import sys
#from PyQt5.QtWidgets import QWidget, QLabel, QApplication
#from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot
#from PyQt5.QtGui import QImage, QPixmap
from PySide6.QtWidgets import QWidget, QLabel, QApplication
from PySide6.QtCore import QThread, Qt, Signal, Slot
from PySide6.QtGui import QImage, QPixmap
pyqtSignal = Signal
pyqtSlot = Slot
class Thread(QThread):
changePixmap = pyqtSignal(QImage)
def run(self):
self.isRunning=True
cap = cv2.VideoCapture(0)
while self.isRunning:
ret, frame = cap.read()
if ret:
# https://stackoverflow.com/a/55468544/6622587
rgbImage = cv2.cvtColor(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)
def stop(self):
self.isRunning=False
self.quit()
self.terminate()
class VideoContainer(QWidget):
def __init__(self):
super().__init__()
self.title = 'PySide Video'
self.left = 100
self.top = 100
self.fwidth = 640
self.fheight = 480
self.padding = 10
self.initUI()
@pyqtSlot(QImage)
def setImage(self, image):
#resize image with window and center
imWidth=self.width()-2*self.padding
imHeight=self.height()-2*self.padding
image = image.scaled(imWidth, imHeight, Qt.KeepAspectRatio) # remove Qt.KeepAspectRatio if not needed
self.label.resize(image.width(), image.height()) #(640, 480)
self.label.move((self.width()-image.width())/2, (self.height()-image.height())/2)
#update image
self.label.setPixmap(QPixmap.fromImage(image))
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.fwidth, self.fheight)
self.resize(1200, 800)
# create a label
self.label = QLabel(self)
self.label.resize(self.width()-2*self.padding,self.height()-2*self.padding) #(640, 480)
self.th = Thread(self)
self.th.changePixmap.connect(self.setImage)
self.th.start()
self.show()
import signal #close signal with Ctrl+C
signal.signal(signal.SIGINT, signal.SIG_DFL)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = VideoContainer()
app.aboutToQuit.connect(ex.th.stop) #stop qthread when closing window
sys.exit(app.exec())
import cv2 import sys #from PyQt5.QtWidgets import QWidget, QLabel, QApplication #from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot #from PyQt5.QtGui import QImage, QPixmap from PySide6.QtWidgets import QWidget, QLabel, QApplication from PySide6.QtCore import QThread, Qt, Signal, Slot from PySide6.QtGui import QImage, QPixmap pyqtSignal = Signal pyqtSlot = Slot class Thread(QThread): changePixmap = pyqtSignal(QImage) def run(self): self.isRunning=True cap = cv2.VideoCapture(0) while self.isRunning: ret, frame = cap.read() if ret: # https://stackoverflow.com/a/55468544/6622587 rgbImage = cv2.cvtColor(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) def stop(self): self.isRunning=False self.quit() self.terminate() class VideoContainer(QWidget): def __init__(self): super().__init__() self.title = 'PySide Video' self.left = 100 self.top = 100 self.fwidth = 640 self.fheight = 480 self.padding = 10 self.initUI() @pyqtSlot(QImage) def setImage(self, image): #resize image with window and center imWidth=self.width()-2*self.padding imHeight=self.height()-2*self.padding image = image.scaled(imWidth, imHeight, Qt.KeepAspectRatio) # remove Qt.KeepAspectRatio if not needed self.label.resize(image.width(), image.height()) #(640, 480) self.label.move((self.width()-image.width())/2, (self.height()-image.height())/2) #update image self.label.setPixmap(QPixmap.fromImage(image)) def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.fwidth, self.fheight) self.resize(1200, 800) # create a label self.label = QLabel(self) self.label.resize(self.width()-2*self.padding,self.height()-2*self.padding) #(640, 480) self.th = Thread(self) self.th.changePixmap.connect(self.setImage) self.th.start() self.show() import signal #close signal with Ctrl+C signal.signal(signal.SIGINT, signal.SIG_DFL) if __name__ == '__main__': app = QApplication(sys.argv) ex = VideoContainer() app.aboutToQuit.connect(ex.th.stop) #stop qthread when closing window sys.exit(app.exec())
import cv2
import sys
#from PyQt5.QtWidgets import  QWidget, QLabel, QApplication
#from PyQt5.QtCore import QThread, Qt, pyqtSignal, pyqtSlot
#from PyQt5.QtGui import QImage, QPixmap

from PySide6.QtWidgets import  QWidget, QLabel, QApplication
from PySide6.QtCore import QThread, Qt, Signal, Slot
from PySide6.QtGui import QImage, QPixmap
pyqtSignal = Signal
pyqtSlot = Slot

class Thread(QThread):
	changePixmap = pyqtSignal(QImage)

	def run(self):
		self.isRunning=True
		cap = cv2.VideoCapture(0)
		while self.isRunning:
			ret, frame = cap.read()
			if ret:
				# https://stackoverflow.com/a/55468544/6622587
				rgbImage = cv2.cvtColor(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)
				
	def stop(self):
		self.isRunning=False
		self.quit()
		self.terminate()

class VideoContainer(QWidget):
	def __init__(self):
		super().__init__()
		self.title = 'PySide Video'
		self.left = 100
		self.top = 100
		self.fwidth = 640
		self.fheight = 480
		self.padding = 10
		self.initUI()

	@pyqtSlot(QImage)
	def setImage(self, image):
		#resize image with window and center
		imWidth=self.width()-2*self.padding
		imHeight=self.height()-2*self.padding
		image = image.scaled(imWidth, imHeight, Qt.KeepAspectRatio) # remove Qt.KeepAspectRatio if not needed
		self.label.resize(image.width(), image.height()) #(640, 480)
		self.label.move((self.width()-image.width())/2, (self.height()-image.height())/2)
			
		#update image	
		self.label.setPixmap(QPixmap.fromImage(image)) 
		
	def initUI(self):
		self.setWindowTitle(self.title)
		self.setGeometry(self.left, self.top, self.fwidth, self.fheight)
		self.resize(1200, 800)
		
		# create a label
		self.label = QLabel(self)		
		self.label.resize(self.width()-2*self.padding,self.height()-2*self.padding) #(640, 480)
		self.th = Thread(self)
		self.th.changePixmap.connect(self.setImage)
		self.th.start()
		self.show()

import signal #close signal with Ctrl+C
signal.signal(signal.SIGINT, signal.SIG_DFL)

if __name__ == '__main__':
	
		app = QApplication(sys.argv)
		ex = VideoContainer()
		app.aboutToQuit.connect(ex.th.stop) #stop qthread when closing window
		
		sys.exit(app.exec())
pyqt-opencv-result-better Afficher une Image d'OpenCV dans une interface PyQt

Sources