Créer une image pixel par pixel
Une image est une grille de pixels, chacun avec ses coordonnées et sa couleur : un programme peut donc la fabriquer, pixel par pixel. Notre mot colorie existe en Python, presque tel quel. Et au passage, on apprend un geste nouveau : parcourir toute une grille avec une boucle dans une boucle.
Cours ici, exercices sur Capytale
Cette page est le cours. Les exercices sont sur Capytale.
Une image vide
Pour manipuler des images, on va chercher le modèle Image dans la boîte à outils PIL, comme on allait chercher Turtle dans turtle :
Image.new("RGB", (300, 200))crée une image de 300 pixels de large sur 200 de haut, en couleurs RVB, et on la range dans la variableimg. Tous ses pixels démarrent à(0, 0, 0): l'image est noire.- Sur Capytale, écrire
imgseul en fin de cellule affiche l'image.
Les coordonnées d'un pixel
Rien de neuf ici : c'est notre troisième façon de se repérer, celle de la dernière séance. Chaque pixel a une adresse (x, y) : x compte les colonnes vers la droite, y compte les lignes vers le bas, et le pixel (0, 0) est en haut à gauche.
Attention au sens de y : il descend. Et les coordonnées vont de 0 à largeur - 1 (ou hauteur - 1) : dans notre image de 300 sur 200, le pixel en bas à droite est (299, 199).
Colorier un pixel : colorie devient putpixel
Pour changer la couleur d'un pixel, on parle à l'image avec la notation pointée, comme on parlait à la tortue. Et le message, c'est la traduction directe de notre mot :
| Notre langage | Python |
|---|---|
colorie (150, 100) en (255, 0, 0) |
img.putpixel((150, 100), (255, 0, 0)) |
Ça se lit : « img, mets le pixel (150, 100) en rouge ». putpixel reçoit deux choses : les coordonnées du pixel, puis son nouveau triplet de couleur. Comme avec colorie, chaque instruction désigne sa case directement : pas de trajet, pas d'ordre imposé.
Un pixel seul, c'est un point minuscule. Pour dessiner quelque chose de visible, il faut en colorier beaucoup : autrement dit, boucler.
Une ligne de pixels
Pour tracer une ligne horizontale rouge, on fait varier x sur toutes les colonnes, à y fixé. C'est la boucle parcourir un intervalle de la dernière séance : deux bornes, et une variable de boucle nommée, parce qu'on s'en sert.
from PIL import Image
img = Image.new("RGB", (300, 200))
for x in range(0, 300):
img.putpixel((x, 100), (255, 0, 0))
img
for x in range(0, 300): donne à x les valeurs 0, puis 1, puis 2… jusqu'à 299 (la borne 300 n'est pas comprise : c'est bien la dernière colonne de l'image). À chaque tour, on colorie le pixel (x, 100) : la ligne 100 devient rouge d'un bord à l'autre.
Toute l'image : une boucle dans la boucle
Et pour colorier tous les pixels ? Pense à la façon dont tu lis un texte : tu lis la première ligne mot par mot, puis tu passes à la ligne suivante et tu recommences. Pour une image c'est pareil : pour chaque ligne, parcourir toutes les colonnes.
En Python, ça s'écrit avec une boucle à l'intérieur d'une autre. On dit que les boucles sont imbriquées :
from PIL import Image
img = Image.new("RGB", (300, 200))
for y in range(0, 200):
for x in range(0, 300):
img.putpixel((x, y), (0, 0, 255))
img
Lis-le comme du texte : pour chaque ligne y (de 0 à 199), on parcourt toutes les colonnes x (de 0 à 299) et on colorie le pixel (x, y). Ici, tout en bleu : 200 × 300 = 60 000 pixels coloriés par 5 lignes de programme.
L'indentation, toujours elle
La boucle sur x est indentée sous la boucle sur y : elle est refaite en entier à chaque ligne. Et le putpixel, indenté deux fois, est dans les deux boucles : il est exécuté 60 000 fois.
La couleur peut dépendre de la position
Tout l'intérêt d'avoir x et y sous la main, c'est que la couleur peut se calculer à partir d'eux. Regarde :
from PIL import Image
img = Image.new("RGB", (256, 100))
for y in range(0, 100):
for x in range(0, 256):
img.putpixel((x, y), (x, 0, 0))
img
Le rouge du pixel vaut x : 0 tout à gauche (noir), 255 tout à droite (rouge vif). Résultat : un dégradé du noir au rouge, sans écrire un seul triplet à la main. C'est la même idée que la spirale : une valeur qui change au fil de la boucle.
Ce qu'on retient
Image.new("RGB", (largeur, hauteur))crée une image ;img.putpixel((x, y), (r, v, b))est la traduction de notrecolorie(notation pointée : on parle à l'image).- Les coordonnées sont celles qu'on connaît : origine en haut à gauche,
xvers la droite,yvers le bas, de0àlargeur - 1ethauteur - 1. - Pour traiter toute l'image, on imbrique deux boucles : pour chaque ligne
y, parcourir toutes les colonnesx, comme on lit un texte. - La couleur peut se calculer à partir de
xety: c'est ce qui permet dégradés et motifs. - Le cours est ici ; on s'entraîne sur Capytale.
Et ensuite
Créer des images, c'est bien ; transformer une vraie photo, c'est mieux. À la prochaine séance, on lit les pixels d'une photo et on programme nos premiers filtres : noir et blanc, négatif.