Formation I.S.N.

Module PIL - Exemple de projet de fin d'année

Plus tard ! Le programme ci-dessous n'est pas à réaliser le jour de la formation (sauf s'il vous reste du temps bien évidemment). Il est là pour vous montrer un exemple de projet réalisé par des élèves.

Des élèves en difficulté avec les notions abordées au cours de l'année ne savent pas toujours quel type de projet pourrait leur convenir. Un sujet sur l'image peut être un bon débouché pour eux.

Par exemple, on peut leur proposer de concevoir un programme créant une image animée :

Le script doit créer autant d'images (au format .gif) que nécessaire puis les nommer correctement. La concaténation des images en un .gif animé est effectuée à l'aide de l'outil ImageMagick.

Remarque importante

Lors de l'installation sous Windows, il faut cocher la case :

Install legacy utilities (e.g. convert).

Projet réalisé

Voici le code proposé par les élèves lors de leur épreuve de baccalauréat. Il est certes perfectible, mais il donne une bonne idée sur ce que peuvent obtenir des élèves en difficulté mais motivés.


##-----Importation des Modules-----##
from tkinter import *
from PIL import Image
import os


##----- Début de la fonction création de l'image-----##
def creationimage(im,largeur_bande,compteur,nom_image):
    largeur, hauteur = im.size
    im_nouvelle = Image.new('RGB', (largeur, hauteur))
    # position du début de la bande grise en pixel
    debut_bande=compteur*largeur_bande 

    for i in range(largeur):
        for j in range(hauteur):
            r, v, b = im.getpixel((i, j))
            
            # si la position du pixel est inférieur au debut de la bande
            if i<=debut_bande :
                im_nouvelle.putpixel((i,j), (r, v, b))

            # si la position du pixel est comprise entre le debut et la fin de bande
            elif  i>debut_bande and i<=debut_bande+largeur_bande:
                im_nouvelle.putpixel((i,j), (255-r, 255-v, 255-b))

            else : 
                im_nouvelle.putpixel((i,j), (r,v,b ))

    # Finalisation de la création de la nouvelle image
    im_nouvelle.save(nom_image)
      
##-------- Fin de la fonction création de l'image ----------##


def nom_image():
    """Insére le nom de l'image souhaité par l'utilisateur dans une zone de texte"""
    nom_image = saisie_texte.get()
    # Si l'utilisateur n'entre pas de nom d'image, c'est le logo qu'on utilise
    if nom_image=="":
         im =Image.open('Logo_ISN-IREM.jpg')
    else :
        im = Image.open(nom_image)
        
    largeur, hauteur = im.size
    # Largeur de la bande en pourcentage pour qu'elle s'adapte à toutes les images 
    largeur_bande = largeur*10/100 
    
    # On veut que le nombre d'images nécessaire pour que la bande grise arrive au bout de la
    # nouvelle image dépend de la largeur de l'image divisé par la largeur de la bande                                                 
    nombre_image_parcours = largeur//largeur_bande                               
    nombre_image_parcours=int(nombre_image_parcours)

    # Cette variable transforme le "nombre_image_parcours" en chaine de carractère
    chaine_nb_image=str(nombre_image_parcours)
    longueur_nb_image=len(chaine_nb_image)
    
    # Cette instruction définit à partir de quelle image on commence à enregistrer
    numero_image=1
    
    # Cette instruction permet de compter le nombre de zéro à mettre devant
    nb_image_crees=nombre_image_parcours*2-1
    nb_zero_debut=len(str(nb_image_crees))
    
    compteur=0

    ##-----Création de l'image à obtenir-----##
    for compteur in range(nombre_image_parcours+1):
        longueur_numero_image=len(str(numero_image))
        nb_zero=nb_zero_debut-int(longueur_numero_image)
        
        nom_image='image_'+nb_zero*"0"+str(numero_image)+'.gif'
        numero_image=numero_image+1

        creationimage(im,largeur_bande,compteur, nom_image ) 
    
    # Pour compteur allant de la dernière image jusqu'au début. On met -2 car la bande grise
    # est hors vision et elle depasse l'image. On met -1 pour que la bande grise disparaisse
    for compteur in range(nombre_image_parcours-2,-1,-1):
        longueur_numero_image=len(str(numero_image))
        nb_zero=nb_zero_debut-int(longueur_numero_image)
        
        nom_image='image_'+nb_zero*"0"+str(numero_image)+'.gif'
        numero_image=numero_image+1
        
        creationimage(im,largeur_bande,compteur, nom_image )
    




##-----Debut programme : Initialisation des fichiers image-----##
##-----Création de la fenêtre-----##
fen = Tk() 
fen.title("Scanner d'image")


##-----Création des boutons-----##
bouton_valider = Button(fen, text='Valider', command=nom_image)
bouton_valider.grid(row = 2, column = 0, padx=3, pady=3)

bouton_quitter = Button(fen, text='Quitter', command=fen.quit)
bouton_quitter.grid(row = 2, column = 1, padx=3, pady=3)


##-----Création des zones de texte-----##
texte_question = Label(fen, text="Entrez le nom de l'image :")
texte_question.grid(row = 0, column = 0, padx=3, pady=3)

texte_reponse = Label(fen, text='')
texte_reponse.grid(row = 1, column = 0, columnspan=2, padx=3, pady=3)


##-----Création des formulaires-----##
saisie_texte = Entry(fen, textvariable=StringVar())
saisie_texte.grid(row = 0, column = 1, padx=3, pady=3)


##-----Programme principal-----##
fen.mainloop()                              # Boucle d'attente des événements
fen.destroy() 


##-------Fin du programmee--------##

os.system('convert -delay 30 -loop 0 *.gif animation.gif') 
# convert : convertir
# -delay : temps en ms entre chaque image pour simuler animation
# loop 0 : en boucle
# *.gif : tous les fichiers qui finissent par .gif dans le dossier
# animation.gif : nom du fichier image à obtenir

os.system('del image_*.gif')
# destruction des fichiers temporaires
# del : detruire (utiliser rem sous Linux)
# tous les fichiers nommés sous la forme image_*.gif