Résolu sur le forum : Borne Wallbox Pulsar Plus 7,4 kW sur abonnement 6 kVA : quel délestage avant accord copro (urgent)Ma panne diagnostiquée — réponse sous 48 h29 €

PyQt Lab’ : Capture Webcam avec OpenCV : évaluation du délai de capture (résultat : 30 fps max et délai capture = 30ms !)

Électroniquemis à jour le 24 avril 2023

PyQt Lab est un outil puissant qui permet aux développeurs de créer des applications graphiques avec Python. Dans cet article, nous allons examiner l’utilisation de PyQt Lab pour capturer des images à partir d’une webcam avec OpenCV. Nous allons évaluer le délai de capture et les performances de cette méthode. Les résultats montrent que PyQt Lab peut capturer des images à une vitesse maximale de 30 images par seconde avec un délai de capture de 30 millisecondes.

PyQt Lab’ : Capture Webcam avec OpenCV : évaluation du délai de capture (résultat : 30 fps max et délai capture = 30ms !)

Par X. HINAULT – Juin 2013

Ce que l’on va faire ici

  • Dans ce code PyQt, capture Webcam avec GSVideo : capture avec utilisation du signal « pull-buffer » (résultat : jusqu’à 100 fps !)

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 :
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file
#
# Created: Sun Jun 16 07:40:43 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(331, 250)
        self.labelImage = QtGui.QLabel(Form)
        self.labelImage.setGeometry(QtCore.QRect(5, 5, 320, 240))
        self.labelImage.setFrameShape(QtGui.QFrame.Box)
        self.labelImage.setFrameShadow(QtGui.QFrame.Sunken)
        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+Opencv+webcam : Capture image », 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

#!/usr/bin/python
# -*- coding: utf-8 -*-

# Par X. HINAULT – Tous droits réservés – GPLv3
# Déc 2012 – www.mon-club-elec.fr

# — importation des modules utiles —
from PyQt4.QtGui import *
from PyQt4.QtCore import * # inclut QTimer..

import os,sys
import time # pour micros

AvecCommander un relais à l’aide d’un BP avec une carte Arduino

#from cv2 import * # importe module OpenCV qui contient sous-module cv
import cv2.cv as cv # importe sous-module cv du module OpenCV
# import cv2 # importe le module OpenCV

# — importation du fichier de description GUI —
from tuto_pyqt_opencv_webcam_capture_image import *

# — classe principale du programme pyQt contenant le code actif —
class myApp(QWidget, Ui_Form):
# la classe reçoit le Qwidget principal ET la classe Ui_Form définie dans *.py obtenu avec pyuic4

        # Note : ici self représente la classe

        def __init__(self, parent=None):
                QWidget.__init__(self) # initialise le Qwidget principal
                self.setupUi(parent) # Obligatoire

                #– variables utiles —

                #========= paramètres graphiques généraux ========
                self.framerate=60 # nombre d’image par secondes (rafraîchissement de l’affichage)              
                self.widthCapture=320 # largeur image capture en pixels
                self.heightCapture=240 # hauteur image capture en pixels
                # la résolution utilisée doit être supportée par la webcam – 320×240 est un bon compromis –            

                # — 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

                #======== config capture openCV ==========
                #– initialisation de la caméra
                self.indexCam=0 # index de la webcam à utiliser – voir ls /dev/video* – utiliser -1 si pas d’indice
                self.webcam=cv.CaptureFromCAM(self.indexCam) # déclare l’objet capture sans désigner la caméra – remplace CreateCameraCapture
                #print (self.webcam) # debug
                cv.SetCaptureProperty(self.webcam,cv.CV_CAP_PROP_FRAME_HEIGHT,240) # définit hauteur image capture
                cv.SetCaptureProperty(self.webcam,cv.CV_CAP_PROP_FRAME_WIDTH,320) # définit largeur image capture
                #cv.SetCaptureProperty(self.webcam,cv.CV_CAP_PROP_FPS,30) # fixe le framerate hardware- pas toujours supporté par webcam

                #self.iplImgSrc=cv.QueryFrame(self.webcam) # récupère un IplImage en provenance de la webcam # +/- premiere capture

        # — Activation d’un Timer pour affichage image – fixe le fps d’affichage en fait —
                self.timerRefresh=QTimer() # déclare un timer Qt
                self.connect(self.timerRefresh, SIGNAL(« timeout() »), self.timerRefreshEvent) # connecte le signal timeOut de l’objet timer à l’appel de la fonction voulue
                self.timerRefresh.start(int(1000/self.framerate)) # lance le timer – mettre délai assez court pour fps élevé           

        # les fonctions appelées, utilisées par les signaux
        #def pushButtonClicked(self):
                #print(« Bouton appuyé »)

        # — les fonctions appelées, utilisées par les signaux hors widgets —

        def timerRefreshEvent(self): # fonction appelée lors de la survenue d’un évènement Timer – nom fonction indiférrent
                print(« Capture Image webcam »)

                micros0=self.micros()

                #self.iplImgSrc=cv.QueryFrame(self.webcam) # récupère un IplImage en provenance de la webcam – Grab + retrieve

                if cv.GrabFrame(self.webcam) : # si une image est dispo
                        print (« frame dispo »)
                        self.iplImgSrc=cv.RetrieveFrame(self.webcam) # récupère un IplImage en provenance de la webcam

                print (« capture : » + str(self.micros()-micros0) +  » us »)               

                micros0=self.micros()

AvecPrincipes d’utilisation des alimentations avec une carte Arduino et des servomoteurs

                # affichage de l’image webcam
                self.qImage = IplQImage(self.iplImgSrc) # récupère le IplImage dans un QImage
                self.qPixmap=QPixmap.fromImage(self.qImage) # récupère le QImage dans QPixmap
                self.labelImage.setPixmap(self.qPixmap) # affiche le QPixmap dans le QLabel

                print (« affichage : «  + str(self.micros()-micros0) +  » us »)            

        # autres fonctions actives

        # 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

# — classes utiles —

# — classe de conversion d’une iplImage en QImage
class IplQImage(QImage): # fonction qui étend la classe QImage
# IplQImage est une classe qui transforme un iplImage (OpenCV) en un QImage (Qt)
    «  » »
http://matthewshotton.wordpress.com/2011/03/31/python-opencv-iplimage-to-pyqt-qimage/
A class for converting iplimages to qimages
«  » »

    def __init__(self,iplimage):
        # Rough-n-ready but it works dammit
        alpha = cv.CreateMat(iplimage.height,iplimage.width, cv.CV_8UC1)
        cv.Rectangle(alpha, (0, 0), (iplimage.width,iplimage.height), cv.ScalarAll(255) ,-1)
        rgba = cv.CreateMat(iplimage.height, iplimage.width, cv.CV_8UC4)
        cv.Set(rgba, (1, 2, 3, 4))
        cv.MixChannels([iplimage, alpha],[rgba], [
        (0, 0), # rgba[0] -> bgr[2]
        (1, 1), # rgba[1] -> bgr[1]
        (2, 2), # rgba[2] -> bgr[0]
        (3, 3) # rgba[3] -> alpha[0]
        ])
        self.__imagedata = rgba.tostring()
        super(IplQImage,self).__init__(self.__imagedata, iplimage.width, iplimage.height, QImage.Format_RGB32)

# — fin class IplQImage

# fonction principale exécutant l’application Qt                       
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

# pour rendre le fichier *.py exécutable
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

Donnez votre avis

Soyez le 1er à noter cet article
ou bien laissez un avis détaillé


Partagez cet article maintenant !


Ça ne règle pas votre cas ?

Décrivez la panne sur le forum, avec une photo si vous pouvez : les membres qui ont eu la même répondent, et le sujet reste pour les suivants.

Avatar photoAvatar photoAvatar photoAvatar photoAvatar photoRejoindre les 54 membres — gratuit, 44 pannes résolues

Dans le même tiroir

Réagissez à cet article

La lettre du club

Une lettre par mois, accrochée au panneau

Les sujets du forum résolus dans le mois, un guide, un chiffre qu’on peut vérifier chez soi. Rien d’autre, jamais plus souvent — et on se désabonne d’un clic.

Ce qu’il y a dedans

Votre adresse

Une lettre par mois. Désabonnement en un clic.

Partagez votre réaction