PyQt Lab est un outil puissant qui permet aux développeurs de créer des applications graphiques pour le système d’exploitation Windows. Une fonctionnalité intéressante de PyQt Lab est sa capacité à capturer des images à partir d’une webcam. Grâce à l’utilisation de GSVideo, cette fonctionnalité est très simple à mettre en œuvre et offre des résultats impressionnants : 30 images par seconde et un délai de 30 millisecondes, ce qui est identique à ce que propose OpenCV. Dans cet article, nous allons voir comment utiliser GSVideo pour capturer des images à partir d’une webcam avec PyQt Lab.
PyQt Lab’ : Capture Webcam avec GSVideo : capture simple avec GSVideo (résultat : 30 fps et délai 30 ms = idem OpenCV)
Par X. HINAULT – Juin 2013

Ce que l’on va faire ici
- Dans ce code PyQt, capture Webcam avec GSVideo : capture simple avec GSVideo (résultat : 30 fps et délai 30 ms = idem OpenCV)
Pré-requis
- python 2.7
- pyqt4.x
- modules :
- python-opencv
- pygst
- gst
Téléchargement :
- Ces codes sont disponibles ici :
Le fichier d’interface *.py
- Fichier obtenu automatiquement avec l’utilitaire pyuic4 à partir du fichier *.ui créé avec QtDesigner :
# Form implementation generated from reading ui file
#
# Created: Wed Jun 12 10:09:29 2013
# by: PyQt4 UI code generator 4.9.1
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8(« Form »))
Form.resize(341, 265)
self.labelImage = QtGui.QLabel(Form)
self.labelImage.setGeometry(QtCore.QRect(10, 15, 320, 240))
self.labelImage.setStyleSheet(_fromUtf8(« background-color: rgb(180, 180, 180); »))
self.labelImage.setText(_fromUtf8(« »))
self.labelImage.setObjectName(_fromUtf8(« labelImage »))
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate(« Form », « PyQt : dessin : qpixmap et qimage : numpy », None, QtGui.QApplication.UnicodeUTF8))
if __name__ == « __main__ »:
import sys
app = QtGui.QApplication(sys.argv)
Form = QtGui.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
Le fichier d’application *Main.py
# -*- coding: utf-8 -*-
# par X. HINAULT – Mai 2013 – Tous droits réservés
# GPLv3 – www.mon-club-elec.fr
# modules a importer
from PyQt4.QtGui import *
from PyQt4.QtCore import * # inclut QTimer..
import os,sys
import time # temps – pour micros
import pygst # gsvideo
pygst.require(‘0.10’)
import gst
import numpy as np
from tuto_pyqt_dessin_qpixmap_qimage_numpy_rgb_gsvideo import * # fichier obtenu à partir QtDesigner et pyuic4
# +/- variables et objets globaux
class myApp(QWidget, Ui_Form): # la classe reçoit le Qwidget principal ET la classe définie dans test.py obtenu avec pyuic4
def __init__(self, parent=None):
QWidget.__init__(self) # initialise le Qwidget principal
self.setupUi(parent) # Obligatoire
# — Variables de classe
# — Paramétrage des widgets de l’interface GUI si nécessaire —
# — Connexions entre signaux des widgets et fonctions
# connecte chaque signal utilisé des objets à l’appel de la fonction voulue
# — Code actif initial —
« » »
# GS Video :
self.player = gst.Pipeline(« player ») # # déclaration du pipeline
#– source
self.source = gst.element_factory_make(« v4l2src », « vsource »)
self.source.set_property(« device », « /dev/video0 »)
#self.scaler = gst.element_factory_make(« videoscale », « vscale »)
#– sortie
#self.sink = gst.element_factory_make(« autovideosink », « outsink »)
self.sink = gst.element_factory_make(« appsink », « outsink »)
self.sink.set_property(« emit-signals », « True »)
# initialisation du pipeline
#self.player.add(self.source, self.scaler, self.sink)
self.player.add(self.source, self.sink) # ajout des éléments aux pipeline
#gst.element_link_many(self.source,self.scaler, self.sink)
gst.element_link_many(self.source, self.sink) # construction du pipeline
« » »
# initialisation pipeline style « ligne de commande »
self.pipeline = gst.parse_launch(
»‘v4l2src device=/dev/video0 ! video/x-raw-rgb,width=320,height=240,framerate=30/1 ! appsink name=sink emit-signals=true’ »
)
#!xvimagesink »’)
#! appsink name=sink sync= False »’)
#! appsink name=sink sync=False »’ % (self.uri, caps))
# définition objets du pipeline pour accès code Python (si besoin)
self.sink = self.pipeline.get_by_name(‘sink’)
# lancement du pipeline
self.pipeline.set_state(gst.STATE_PLAYING)
# affichage de test
buf = self.sink.emit(‘pull-buffer’)
self.pixels = np.frombuffer(buf.data, dtype=np.uint8).reshape((320,240,3))
print type(self.pixels)
print self.pixels
print self.pixels.shape
# dessin : créer image à partir tableau numpy
# initialisation du tableau de pixels
#self.pixels=np.zeros((self.labelImage.height(),self.labelImage.width(),4),np.uint8,’C’) # tableau 320×240 x 4 canaux et 8U
# 4 canaux car image QImage est une une image ARGB… même si format RGB utilisé (qui est en fait ARGB avec A laissé à FF)
# initialisation des canaux
#self.pixels[:,:,1]=255 # canal G
#self.pixels[:,:,0]=127 # canal B
#self.pixels[:,:,2]=64 # canal R
# accès à un pixel unitaire…
#self.pixels[119,159,:]=[0,0,0,0] # accès à un pixel unitaire par pixels[y,x,:] (inversion x,y) et paramétrage de la couleur par (b,g,r,0)
# accès à une ligne entière de pixels
#self.pixels[50,:,:]=[0,0,255,0] # accès à une ligne par pixels[y,:,:] (inversion x,y) et paramétrage de la couleur par (b,g,r,0)
# accès à une colonne entière de pixels
#self.pixels[:,50,:]=[255,0,0,0] # accès à une colonne par pixels[:,x,:] (inversion x,y) et paramétrage de la couleur par (b,g,r,0)
#QImage(self,str data, int width, int height, Format format)
#self.image=QImage(self.pixels.tostring(), self.labelImage.width() , self.labelImage.height() ,QImage.Format_RGB32) # crée image RGB 32 bits même taille que label
self.image=QImage(self.pixels.tostring(), self.labelImage.width() , self.labelImage.height() ,QImage.Format_RGB888) # crée image RGB 32 bits même taille que label
#– affichage du QImage via QPixmap dans QLabel
self.pixmap=QPixmap.fromImage(self.image) # chargement qu QImage dans le QPixmap
self.labelImage.setPixmap(self.pixmap) # met à jour le qpixmap affiché dans le qlabel
#self.connect(self.sink,SIGNAL(« pull-buffer »), self.bufferReady) # ne semble pas fonctionner
#– initialisation du Timer pour lecture Buffer GStreamer
self.timerGStreamer=QTimer() # déclare un timer Qt
self.timerGStreamer.start(5) # lance le timer – durée en ms – délai doit être idem ou inf … framerate camera sinon, décalage..
self.connect(self.timerGStreamer, SIGNAL(« timeout() »), self.readBuffer) # connecte le signal timeOut de l’objet timer à l’appel de la fonction voulue
# — les fonctions appelées, utilisées par les signaux des widgets —
# — les fonctions appelées, utilisées par les signaux hors widgets —
# fonction micros : renvoie le nombre de microsecondes courant de l’horloge système
def micros(self):
return(int(round(time.time() * 1000000))) # microsecondes de l’horloge système
def bufferReady(self):
print (« Buffer ok »)
def readBuffer(self):
micros0=self.micros()
#print (str(self.micros()-micros0) + » us »)
# affichage de test
buf = self.sink.emit(‘pull-buffer’)
print (« signal pull-buffer »+str(self.micros()-micros0) + » us »)
micros0=self.micros()
self.pixels = np.frombuffer(buf.data, dtype=np.uint8)
print (« lecture data : » + str(self.micros()-micros0) + » us »)
self.pixels=self.pixels.reshape((320,240,3))
#print (str(self.micros()-micros0) + » us »)
micros0=self.micros()
self.pixelsOK=np.zeros((320, 240,3), np.uint8)
self.pixelsOK[:,:,0]=self.pixels[:,:,2] # inversion R et B
self.pixelsOK[:,:,1]=self.pixels[:,:,1] # G
self.pixelsOK[:,:,2]=self.pixels[:,:,0] # inversion R et B
# => 2,5ms
print (« conversion data : » +str(self.micros()-micros0) + » us »)
#print type(self.pixels)
#print self.pixels
#print self.pixels.shape
micros0=self.micros()
self.image=QImage(self.pixelsOK.tostring(), self.labelImage.width() , self.labelImage.height() ,QImage.Format_RGB888) # crée image RGB 32 bits même taille que label
#– affichage du QImage via QPixmap dans QLabel
#self.pixmap=QPixmap.fromImage(self.image) # chargement qu QImage dans le QPixmap – ne marche pas..
self.pixmap.convertFromImage(self.image) # recharge le QImage dans le QPixmap existant – met à jour le QPixmap
self.labelImage.setPixmap(self.pixmap) # met à jour le qpixmap affiché dans le qlabel
print (« affichage : « + str(self.micros()-micros0) + » us »)
# — fonctions de classes autres—
# — Autres Classes utiles —
# — Classe principale (lancement) —
def main(args):
a=QApplication(args) # crée l’objet application
f=QWidget() # crée le QWidget racine
c=myApp(f) # appelle la classe contenant le code de l’application
f.show() # affiche la fenêtre QWidget
r=a.exec_() # lance l’exécution de l’application
return r
if __name__==« __main__ »: # pour rendre le code exécutable
main(sys.argv) # appelle la fonction main
Utilisation
- Les 2 fichiers suivants sont à enregistrer dans un même répertoire, l’un en nom.py et l’autre en nomMain.py.
- Puis lancer l’application depuis Geany ou équivalent, en exécutant le fichier nomMain.py
- On obtient la fenêtre avec capture vidéo
Articles similaires:
- PyQt Lab’ : Capture Webcam avec GSVideo : capture avec utilisation du signal « pull-buffer » (résultat : jusqu’à 100 fps !)
- PyQt Lab’ : PyQt + OpenCV + pyqtcv + webcam : Capture simple d’un flux vidéo webcam avec GSVideo
- PyQt Lab’ : Capture Webcam avec OpenCV : évaluation du délai de capture (résultat : 30 fps max et délai capture = 30ms !)
- PyQt Lab’ : Dessin : Dessiner un simple cercle par accès direct aux pixels
- PyQt Lab’ : PyQt + OpenCV : Afficher un simple fichier image dans une fenêtre PyQt
Articles Liés
- Javascript : Graphique Dygraphs simple
Le Javascript est un langage de programmation très populaire et puissant qui permet aux développeurs…
- Javascript : Afficher 6 widgets graphiques fournis par une librairie graphique externe.
Le Javascript est un langage de programmation très populaire qui permet aux développeurs de créer…
- Javascript : Graphique Dygraphs : afficher date à partir unixtime
Le langage de programmation Javascript est très populaire et est utilisé pour créer des applications…