Consignes

Vous devrez utiliser l'interface TPLab pour envoyer vos TP aux encadrants de TP.

La note ne valide pas seulement le résultat de votre programme, mais également son style :

Vérifiez ces points avant de demander à votre intervenant de valider votre code.

Attention : les points suivants ne rapportent rien, mais ne pas les respecter pourra retrancher jusqu'à 10 points sur la note finale :

Liens utiles

1. Les images

1.1. Préliminaire : formats Netpbm à la main

Il existe des bibliothèques pour manipuler des images complexes, mais pour ce TP, nous n'utiliserons que des images dans des formats très simples : Netpbm « plain ». Ces images sont stockées en ASCII, ce qui les rend lisibles sans aucun outils spécialisés.

Il y a trois formats différents :

Par exemple, voici une image noir et blanc contenant un petit carré blanc dans un grand carré noir :

P1
10 10
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 0 0 0 0 1 1 1
1 1 1 0 0 0 0 1 1 1
1 1 1 0 0 0 0 1 1 1
1 1 1 0 0 0 0 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1

Et voici l'image correspondante : "". (Remarque : les formats utilisés pour ce TP ne sont pas très standards, et les navigateurs web ne les affichent en général pas. J'ai donc convertit les images en un format plus courant : PNG.)

Pour les images en gris (extension .pgm), l'entête est de la forme

P2
nb_colonnes nb_lignes
256
... ...
... ...

où chaque pixel est représenté par un nombre entre 0 et 255.

Pour les images en couleur (extension .ppm), l'entête est de la forme

P3
nb_colonnes nb_lignes
256
... ...
... ...

où chaque pixel est représenté par trois nombres entre 0 et 255.

  1. Créez quelques images à la main (en couleurs / gris / noir et blanc) en vous basant sur l'exemple ci-dessus.
  2. Visualisez les images pour faire le lien entre le contenu du fichier et l'image affichée.
  3. Modifiez le contenu du fichier avant de le réafficher.

Que pensez-vous de ces formats d'images (plain PBM, plain PGM et plain PPM) ? Comment pourrait-on les améliorer ?

Attention : les formats d'image utilisés dans ce TP (plain PBM, plain PGM et plain PPM) ne sont pas reconnus nativement par Windows XP. Pour visualiser vos images sous Windows, vous pouvez installer de petit utilitaire IrfanView téléchargeable ici.

Si vous utilisez Linux les images devraient être reconnues automatiquement.

1.2. Les images avec la bibliothèque fournie

Téléchargez le fichier squelette et modifiez la valeur de la variable nom tout en haut du fichier...

À partir de maintenant, vous devrez modifier ce fichier squelette...

Écrivez une petite fonction "creer_carre" :

def creer_carre(taille,fichier):
    """Crée une image PBM contenant un carré noir, avec les diagonales en blanc."""

Par exemple,

>>> creer_carre(50,"image1")

va créer le fichier image1.pbm :

Les fonctions et méthodes pour manipuler les fichiers sont :

  • open pour ouvrir un fichier,
  • f.write pour écrire dans un fichier,
  • f.close pour fermer le fichier.

1.3. Mini bibliothèque fournie

Téléchargez la bibliothèque images.py et sauvegardez là dans le même répertoire que votre fichier principal.

La petite bibliothèque images.py permet de créer, ouvrir, modifier et sauver des images simples aux format "PBM", "PGM" ou "PPM". Vous devez télécharger le fichier images.py et le mettre dans le même répertoire que votre propre fichier. Voici par exemple un morceau de programme Python qui déclare une image, dessine un point gris au milieu et sauve l'image dans "test.pgm":

from images import *

image = Image("PGM", 7, 11)
image.change_pixel( image.largeur//2, image.hauteur//2, 127)
image.sauve("test")

Voici, avec des détails, ce qu'il se passe :

  1. image = Image("PGM",7,11) : on initialise une image image. Les 3 arguments obligatoires sont :
    • le type d'image : "PBM", "PGM" ou "PPM",
    • les dimensions largeur et hauteur,
    On peut également donner un troisième argument pour la couleur de fond de l'image. (blanc par défaut)
  2. image.largeur est la largeur de l'image (ici, 7) et image.hauteur est la hauteur de l'image (ici, 11),
  3. image.change_pixel(x,y,couleur) est une méthode de l'objet image : cela permet de changer la couleur d'un pixel. Ici, la couleur est 127, c'est à dire gris.
  4. image.sauve("test") : on sauve l'image finale dans le fichier mon_image.pgm.

Remarques :

2. Rectangles et dégradés

2.1. Rectangles et carrés

Écrivez le corps de la procédure suivante :

def rectangle(image, x0, y0, largeur, hauteur, couleur):
    """Dessine un rectangle dans l'image "image".
Les arguments "x0" et "y0" désignent le point en haut à gauche du rectangle,
l'argument "largeur" sa largeur, l'argument "hauteur" sa hauteur et l'argument
"couleur" sa couleur.
Attention, si le rectangle ne tient pas dans "image", il ne faudra dessiner
qu'un bout du rectangle..."""

Vérifiez que vous faites ce qu'il faut en :

Attention : cette procédure modifie une image existante qui lui est passé en paramètre. La procédure rectangle ne crée pas une nouvelle image et n'utilise donc ni la fonction "Image(...)" ni la méthode "save". C'est la procédure de test qui le fait...

Pour tester votre procédure (et les suivantes) vous pouvez utiliser la procédure de test "tp1()" définie dans le fichier squelette...

2.2. Dégradés (Bonus)

Le but est maintenant de dessiner un rectangle contenant un dégradé vertical.

Le cas le plus simple est un dégradé de gris qui va du noir au blanc dans un rectangle de hauteur 256 : le rectangle ressemble à

...
... 0 0 0 0 0 0 0 0 0 0 0 ...
... 1 1 1 1 1 1 1 1 1 1 1 ...
... 2 2 2 2 2 2 2 2 2 2 2 ...
... 3 3 3 3 3 3 3 3 3 3 3 ...
... ...
... ...
... 254 254 254 254 254 254 254 254 254 254 254 ...
... 255 255 255 255 255 255 255 255 255 255 255 ...
...

Autrement dit, la ligne i du rectangle à le niveau de gris i.

Lorsque la hauteur est plus petite, il faut « sauter des lignes ». Par exemple, dans le cas d'une hauteur de 128 :

...
... 0 0 0 0 0 0 0 0 0 0 0 ...
... 2 2 2 2 2 2 2 2 2 2 2 ...
... 4 4 4 4 4 4 4 4 4 4 4 ...
... ...
... ...
... 252 252 252 252 252 252 252 252 252 252 252 ...
... 254 254 254 254 254 254 254 254 254 254 254 ...
...

Autrement dit, la ligne i du rectangle à la couleur 2i.

Lorsque la hauteur est plus grande, il faut répéter des lignes. Par exemple, dans le cas d'une hauteur de 512 :

...
... 0 0 0 0 0 0 0 0 0 0 0 ...
... 0 0 0 0 0 0 0 0 0 0 0 ...
... 1 1 1 1 1 1 1 1 1 1 1 ...
... 1 1 1 1 1 1 1 1 1 1 1 ...
... ...
... ...
... 255 255 255 255 255 255 255 255 255 255 255 ...
... 255 255 255 255 255 255 255 255 255 255 255 ...
...

Autrement dit, la ligne i du rectangle à la couleur i/2.

Lorsqu'on doit créer un dégradé entre deux couleurs arbitraire, il y a plusieurs difficultés supplémentaires :

BONUS

Écrivez la procédure :

def rectangle_degrade(image, x0, y0, largeur, hauteur, couleur_haut, couleur_bas):
    """Dessine un rectangle dans l'image "image" qui est forcément au format
"PPM" (couleurs RGB).
Les coordonnées du point haut/gauche du rectangle sont "x0" et "y0" ; et ses
dimensions sont "largeur" et "hauteur".
Le rectangle contient un dégradé de couleurs : de "couleur_haut" en haut du
rectangle, jusqu'à "couleur_bas" en bas du rectangle.
"""

Consignes : expliquez (en commentaires) comment vous faites pour calculer la couleur d'un point du rectangle.

Voici un exemple de résultat :

im = Image("PPM", 100,100, (0,0,0))
rectangle_degrade(im, 25,30, 45, 70, (0,200,0), (0,20,127))
im.sauve("image2")

3. Disques et cercles

Réfléchissez à une méthode pour dessiner un disque plein sur une image. Programmez ensuite la procédure :

def disque(image, x0, y0, rayon, couleur):
    """Dessine un disque dans l'image "image".
Les arguments "x0" et "y0" désignent le centre, l'argument "rayon" le rayon
et "couleur" sa couleur."""

Rappel : le disque de centre (x0,y0) et de rayon r est constitué de l'ensemble des points de coordonnées (x,y) qui vérifient (x-x0)2 + (y-y0)2 ≤ r2.

Essayez maintenant de dessiner un cercle sur une image :

def cercle(image, x0, y0, rayon, couleur):
    """Dessine un disque dans l'image "image".
Les arguments "x0" et "y0" désignent le centre, l'argument "rayon" le rayon
et "couleur" sa couleur."""

Rappel : le disque de centre (x0,y0) et de rayon r est constitué de l'ensemble des points de coordonnées (x,y) qui vérifient (x-x0)2 + (y-y0)2 = r2.

Testez votre fonction et commentez ce que vous voyez.

4. Segments (BONUS)

BONUS

Programmez la procédure

def segment(image, x1, y1, x2, y2, couleur):
    """Dessine un segment dans l'image "image".
Les arguments "x1", "y1" et "x2","y2" désignent les coordonnées des extrémités
du segment, l'argument "rayon" le rayon et "couleur" sa couleur."""

Par exemple :

>>> im = Image("PBM", 50, 50, 1)
>>> segment(im, 0,0 , 49,13 , 0)
>>> im.sauve("image3")

donne :

5. Art moderne ??

En utilisant le module Random, écrivez une fonction art_moderne qui génère une image aléatoire contenant des disques et des rectangles. Choisissez des arguments pertinents pour pouvoir choisir les paramètres de votre image finale.

Voici un exemple de ce que vous pourriez obtenir :

Attention : cette fonction doit créer une nouvelle image. Elle doit donc faire un "im = Image(...)" et un "im.save(...)".