View  Edit  Attributes  History  Attach  Print  Search

PYQTLAB

PyQt Lab' : Appliquer une opération mathématique f(x,y) à tous les pixels d'une image en niveaux de gris

Par X. HINAULT - Juin 2013

Ce que l'on va faire ici

Pré-requis

  • python 2.7
  • pyqt4.x
  • modules :
    • numpy

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: 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


#!/usr/bin/python
# -*- 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 numpy as np

from tuto_pyqt_dessin_qpixmap_qimage_numpy_gray_fxy 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  ---

                # dessin : créer image à partir tableau numpy

                # initialisation du tableau de pixels
                self.pixels=np.fromfunction(self.f,(self.labelImage.height(),self.labelImage.width())) # tableau 320x240 x 1 canal et 8U - pixels calculés par fonction                

                #QImage(self,str data, int width, int height, Format format)
                self.image=QImage(self.pixels.tostring(), self.labelImage.width() , self.labelImage.height() ,QImage.Format_Indexed8) # crée image RGB 8 bits même taille que label

                print self.pixels # debug

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

        # --- les fonctions appelées, utilisées par les signaux des widgets ---                

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

        # --- fonctions de classes autres---    

        #-- fonctions math utiliser pour calculer la valeur des pixels
        def f(self,  yIn, xIn): # Attention - inversion xIn et yIn : pour calcul pixel (x,y) la fonction reçoit (y,x) !

                # calcul basé sur yIn+1 et xIn+1
                #x=xIn+1
                #y=yIn+1

                # +/- mapper x,y au besoin
                #x=(xIn+1)*255/self.labelImage.width() # réchelonne largeur sur 0-255... si on utilise directement x
                #y=(yIn+1)*255/self.labelImage.height() # réchelonne hauteur sur 0-255...  si on utilise directement y

                x=(xIn+1)*360/self.labelImage.width() # réchelonne largeur sur 0-360...  si degrés
                y=(yIn+1)*360/self.labelImage.height() # réchelonne hauteur sur 0-360...  si degrés

                # calcul de la valeur du pixel Xin,Yin
                #valeur=127*x/x # pour remplir tous les pixels... obligatoire de poser un calcul utilisant x ou y
                #valeur=y # pixel = valeur du x courant
                #valeur=y*x/255 # valeur progressive
                valeur=127+(127*np.sin(np.radians(x))*np.sin(np.radians(y))) # calcul basé sur Xin

                return np.uint8(valeur) # renvoie la valeur au format np.uint8

# -- 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
  • L'image obtenue doit s'afficher d'emblée... Une estimation du temps d'exécution donne 20 ms sur CPU x4 @ 2,33Ghz soit un fps théorique de 50 fps.