Dessin sur image.
Le module PIL permet également de dessiner sur une image (image existante, par exemple une photo, ou image que vous créez).
Il faut pour cela utiliser les possibilités du module ImageDraw. Vous trouverez l'essentiel
des renseignements concernant ImageDraw sur cette page ou encore sur celle-ci.
Utiliser la méthode rectangle
de ce module pour créer à nouveau une image illustrant la règle 90 qui a été présentée dans les exercices sur les fichiers.
Dans cette version, le tracé d'un pixel sera remplacé par le tracé d'un carré (dont vous choisirez la longueur de côté)
obtenu avec la méthode rectangle
.
Un programme possible :
from PIL import Image, ImageDraw
nb=int(input('Entrez le nombre de lignes : '))
u=2 # unité (côté d'un carré)
largeur=nb*u
hauteur=nb*u
# t : liste de lignes
# t[0] : ligne 1, longueur nb+2 (on ajoute un blanc à gauche et un à droite)
# les cellules visibles de t[0] seront donc t[0][1], t[0][2], ..., t[0][nb].
# dernière ligne : t[nb-1]
t=[['0' for j in range(nb+2)] for k in range(nb)]
# on place un '1', c'est à dire un noir au centre de la première ligne
t[0][(nb+2)//2]='1'
# dictionnaire des transformations :
regle={'111' : '0', '110' : '1', '101' : '0',\
'100' : '1', '011' : '1', '010' : '0', '001' : '1', '000' : '0'}
for k in range(1,nb) :
# détermination de la ligne suivante et mise à jour de t :
for j in range(1,nb+1):
t[k][j]=regle[t[k-1][j-1]+t[k-1][j]+t[k-1][j+1]]
# création d'une nouvelle image
regle90=Image.new('RGB',(hauteur, largeur))
# creation d'un 'objet dessin' dans l'image
dessin= ImageDraw.Draw(regle90)
for l in range(nb) :
for c in range(1,nb+1) :
if t[l][c]=='1' :
dessin.rectangle([(c*u-u//2,l*u-u//2),(c*u+u//2,l*u+u//2)], fill='red')
regle90.save('image_resultat.jpg')
regle90.show()
A vous maintenant de modifier avec d'autres règles que la règle 90. Faites varier le nombre de lignes, le côté du carré...
Echiquier.
En utilisant la méthode rectangle vue dans l'exercice précédent, écrire un programme python permettant de créer une image (format png) d'un échiquier de taille d sur d (d = 8 est la taille usuelle).
Un programme possible :
from PIL import Image, ImageDraw
def CreeImageEchiquier(d = 8, u = 20) :
""" d : pour créer un échiquier de d lignes et d colonnes.
u : unité en pixel du côté d'une case de l'échiquier."""
# largeur et hauteur de l'image en pixels :
largeur = hauteur = d*u
# création d'une nouvelle image :
echiquier = Image.new('RGB',( largeur, hauteur ))
# creation d'un 'objet dessin' dans l'image :
dessin = ImageDraw.Draw(echiquier)
# boucle de création des dessins des cases :
for l in range(0,d) :
for c in range(0,d) :
if (l+c) % 2 == 0 : dessin.rectangle([(l*u, c*u),((l+1)*u,(c+1)*u)], fill='grey')
else : dessin.rectangle([(l*u, c*u),((l+1)*u,(c+1)*u)], fill='white')
echiquier.save("echiquier"+str(d)+".png")
return echiquier
if __name__ == "__main__" :
echiquier = CreeImageEchiquier()
echiquier.show()
Disque dans l'échiquier.
Reprendre l'échiquier de l'exercice précédent. Ajouter une fonction permettant de dessiner un disque dans la case (i,j) de l'échiquier (les lignes et colonnes de l'échiquier d*d étant numérotées de 1 à d).
On utilisera pour cela la commande ellipse du module ImageDraw.
Un programme possible :
from PIL import Image, ImageDraw
def CreeImageEchiquier(d = 8, u = 20) :
""" d : pour créer un échiquier de d lignes et d colonnes.
u : unité en pixel du côté d'une case de l'échiquier."""
# largeur et hauteur de l'image en pixels :
largeur = hauteur = d*u
# création d'une nouvelle image :
echiquier = Image.new('RGB',( largeur, hauteur ))
# creation d'un 'objet dessin' dans l'image :
dessin = ImageDraw.Draw(echiquier)
# boucle de création des dessins des cases :
for l in range(0,d) :
for c in range(0,d) :
if (l+c) % 2 == 0 : dessin.rectangle([(c*u, l*u),((c+1)*u,(l+1)*u)], fill='grey')
else : dessin.rectangle([(c*u, l*u),((c+1)*u,(l+1)*u)], fill='white')
echiquier.save("echiquier"+str(d)+".png")
return echiquier
def disqueDansCase(ligne,colonne,d = 8, u = 20) :
# on décale pour tenir compte d'une numérotation de 1 à d :
l, c = ligne-1, colonne-1
echiquier = CreeImageEchiquier(d,u)
dessin = ImageDraw.Draw(echiquier)
epsilon = 1/10
dessin.ellipse([( (c+epsilon) *u, (l+epsilon) *u ),( (c+1-epsilon)*u, (l+1-epsilon)*u )], fill='red')
echiquier.save("echiquier"+str(d)+".png")
return echiquier
if __name__ == "__main__" :
echiquier = disqueDansCase(ligne = 2, colonne = 3, d=8, u=30)
echiquier.show()
Couronne dans l'échiquier.
Dans l'exercice précédent, remplacer le disque par un dessin de couronne.
La couronne sera un simple polygone obtenu avec la méthode polygon du module ImageDraw.
Un programme possible :
from PIL import Image, ImageDraw
def CreeImageEchiquier(d = 8, u = 20) :
""" d : pour créer un échiquier de d lignes et d colonnes.
u : unité en pixel du côté d'une case de l'échiquier."""
# largeur et hauteur de l'image en pixels :
largeur = hauteur = d*u
# création d'une nouvelle image :
echiquier = Image.new('RGB',( largeur, hauteur ))
# creation d'un 'objet dessin' dans l'image :
dessin = ImageDraw.Draw(echiquier)
# boucle de création des dessins des cases :
for l in range(0,d) :
for c in range(0,d) :
if (l+c) % 2 == 0 : dessin.rectangle([(c*u, l*u),((c+1)*u,(l+1)*u)], fill='grey')
else : dessin.rectangle([(c*u, l*u),((c+1)*u,(l+1)*u)], fill='white')
echiquier.save("echiquier"+str(d)+".png")
return echiquier
def couronne(a,b,dx ,dy ) :
""" On définit chaque couple de sommets du polygone dessinant la couronne
par rapport au point de coordonnées (a,b) (translations à partir de ce point).
Le couple (a,b) est destiné à désigner
les coordonnées du centre d'une case de l'échiquier."""
# dans l'appel, on aura par exemple (a,b)=(2,3)
# c'est à dire couronne en ligne 2, colonne 3
# centrage sur la case :
a, b = a-0.5, b-0.5
# coeffs pour taille verticale
d, i, h = 0.5, -1.2, -1.8
# coeffs pour taille horizontale
l,dl = 1.5, 0.6
# coordonnées des sommets du polygone, 'centré' sur (a,b) :
coord = [ (a+l*dx, b+d*dy), (a+l*dx,b+h*dy), (a+dl*dx,b+i*dy),
(a,b+h*dy), (a-dl*dx, b+i*dy),
(a-l*dx, b+h*dy), (a-l*dx, b+d*dy)]
return coord
def dessinCouronne(ligne, colonne,dx=0.2 ,dy=0.2 , d=8, u=20) :
l,c = ligne, colonne
echiquier = CreeImageEchiquier(d,u)
dessin = ImageDraw.Draw(echiquier)
# les sommets du polygone délimitant la couronne :
coordpolygone = couronne(c,l, dx , dy )
# mise à l'échelle de la couronne :
for j, (a,b) in enumerate(coordpolygone) : coordpolygone[j]= (a*u, b*u)
# dessin de la couronne :
dessin.polygon(coordpolygone, fill='red')
echiquier.save("echiquier"+str(d)+".png")
return echiquier
if __name__ == "__main__" :
echiquier = dessinCouronne(ligne = 2, colonne = 3, d=8, u=40)
echiquier.show()
Huit reines.
Reprendre l'exemple précédent, placer maintenant une reine dans chaque colonne (au hasard dans la colonne).
Une reine qui n'est en prise avec aucune autre sera rouge. Une reine en prise avec au moins une autre sera orange.
Dans le programme ci-dessous, on a utilisé le principe de programmation POO.
from PIL import Image, ImageDraw
from random import randint
class Echiquier :
""" Représente un échiquier d*d avec une reine dans chaque colonne. """
def __init__(self, reine, unite=40 ):
""" reine = [l0, l1, l2, l3, ..., l(dimension-1)].
li : ligne de la reine de la colonne i (i entre 0 et dimension-1)
unite : unite pour la représentation graphique
"""
# unité pour la représentation graphique :
self.unite = unite
# dimension = nb de lignes = nb de colonnes :
self.dimension = len(reine)
# les lignes des reines des colonnes 0 à dimension-1 :
self.reine = reine
# la représentation est une image png :
u = self.unite
d1 = self.dimension + 1
self.representation = Image.new('RGB',( d1 * u , d1 * u ))
# détails de l'image :
self.represente()
self.placeReines()
def represente(self) :
""" image échiquier de dimension lignes et dimension colonnes.
unite : unité en pixel du côté d'une case de l'échiquier."""
u = self.unite
d = self.dimension
# creation d'un 'objet dessin' dans l'image de l'échiquier :
dessin = ImageDraw.Draw(self.representation)
# boucle de création des dessins des cases :
for l in range(0,d) :
for c in range(0,d) :
if (l+c) % 2 == 0 :
dessin.rectangle([(c*u, l*u),((c+1)*u,(l+1)*u)], fill='grey')
else :
dessin.rectangle([(c*u, l*u),((c+1)*u,(l+1)*u)], fill='white')
# numérotation des lignes et colonnes sur la figure :
for l in range(0,d) :
dessin.text(((d+0.5)*u,(l+0.5)*u), str(l+1), fill="white")
for c in range(0,d) :
dessin.text(((c+0.5)*u,(d+0.5)*u), str(c+1), fill="white")
def couronne(self, a, b) :
""" On définit chaque couple de sommets du polygone dessinant la couronne
par rapport au point de coordonnées (a,b) (translations à partir de ce point).
Le couple (a,b) est destiné à désigner
les coordonnées du centre d'une case de l'échiquier."""
# dans l'appel, on aura par exemple (a,b)=(2,3)
# c'est à dire couronne en ligne 2, colonne 3
# centrage sur la case :
a, b = a+0.5, b+0.5
# coeffs pour taille verticale
d, i, h = 0.5, -1.2, -1.8
# coeffs pour taille horizontale
l,dl = 1.5, 0.6
# pour dimension couronne :
dx, dy = 0.2, 0.2
# coordonnées des sommets du polygone, 'centré' sur (a,b) :
coord = [ (a+l*dx, b+d*dy), (a+l*dx,b+h*dy), (a+dl*dx,b+i*dy),
(a,b+h*dy), (a-dl*dx, b+i*dy),
(a-l*dx, b+h*dy), (a-l*dx, b+d*dy)]
return coord
def dessinCouronne(self, ligne, colonne, couleur='red') :
""" dessine une couronne en cellule de
coordonnées (ligne, colonne) """
u = self.unite
dessin = ImageDraw.Draw(self.representation)
# les sommets du polygone délimitant la couronne :
coordpolygone = self.couronne(colonne,ligne)
# mise à l'échelle de la couronne :
for j, (a,b) in enumerate(coordpolygone) : coordpolygone[j]= (a*u, b*u)
# dessin de la couronne :
dessin.polygon(coordpolygone, fill=couleur)
def prise(self, l1, c1, l2,c2):
"""retourne True si la reine en (l1,c1) et la reine
en (l2,c2) peuvent s'attaquer, c'est à dire
si elles sont sur une même ligne, ou colonne,
ou diagonale."""
if l1 == l2 : return True
if c1 == c2 : return True
if l1+c1 == l2+c2 : return True
if l1-c1 == l2-c2 : return True
return False
def reineEnPrise(self, col) :
""" retourne True si la reine en ligne = self.reine[col]
et colonne = col est en prise avec une autre des reines.
Retourne False sinon."""
for i in range(self.dimension) :
if i !=col :
if self.prise( self.reine[col], col, self.reine[i], i) :
return True
return False
def placeReines(self) :
""" complète le dessin de l'échiquier par celui des 8 reines.
Une reine non en prise avec une autre est rouge, sinon orange."""
for c in range(self.dimension) :
if self.reineEnPrise(c) :
self.dessinCouronne( self.reine[c] , c , couleur='orange')
else :
self.dessinCouronne( self.reine[c] , c , couleur='red')
def __str__(self) :
""" méthode appelée lorsqu'on demandera un print de l'objet.
(représentation texte de l'objet). """
ch = ''
for i in range(self.dimension) :
ch += 'La reine de la colonne {} est en ligne {}\n'.format(i+1, self.reine[i]+1)
return ch
def montre(self) :
self.representation.save("echiquier.png")
self.representation.show()
if __name__ == "__main__" :
L = []
for i in range(8) :
L.append(randint(0,7))
ech = Echiquier(L)
print(ech)
ech.montre()
Le module svgwrite permet de produire de façon similaire cette image au format svg :
import svgwrite
from run import run_file
class Echiquier :
""" Représente un échiquier d*d avec nb reines dans les nb premières colonnes. """
def __init__(self, nbreines, dimension, reines, unite=25 ):
""" reines = [l0, l1, l2, l3, ..., l(nbreines-1)].
li : ligne de la reine de la colonne i (i entre 0 et dimension-1)
unite : unite pour la représentation graphique
"""
# nombre de reines sur l'échiquier :
self.nbreines = nbreines
# unité pour la représentation :
self.unite = unite
# dimension de l'échiquier :
self.dimension = dimension
# les lignes de chaque reine :
self.reines = reines
# la représentation est une image svg :
self.representation = svgwrite.Drawing('echiquier.svg')
self.represente()
self.placeReines()
self.representation.save()
def represente(self) :
""" image échiquier de dimension lignes et dimension colonnes.
unite : unité en pixel du côté d'une case de l'échiquier."""
u = self.unite
d = self.dimension
# création d'une nouvelle image :
echiquier = self.representation
# boucle de création des dessins des cases :
for l in range(0,d) :
for c in range(0,d) :
if (l+c) % 2 == 0 :
self.representation.add(self.representation.rect(insert= (c*u, l*u), size= (u,u), fill='lightgrey', stroke='black'))
else :
self.representation.add(self.representation.rect(insert= (c*u, l*u), size= (u,u), fill='white', stroke='black'))
for l in range(0,d) :
self.representation.add(self.representation.text( str(l+1), insert= ( (d+0.5)*u, (l+0.5)*u) , fill="red"))
for c in range(0,d) :
self.representation.add(self.representation.text( str(c+1), insert= ( (c+0.5)*u, (d+0.5)*u) , fill="red"))
def couronne(self, a, b) :
""" On définit chaque couple de sommets du polygone dessinant la couronne
par rapport au point de coordonnées (a,b) (translations à partir de ce point).
Le couple (a,b) est destiné à désigner
les coordonnées du centre d'une case de l'échiquier."""
# dans l'appel, on aura par exemple (a,b)=(2,3)
# c'est à dire couronne en ligne 2, colonne 3
# centrage sur la case :
a, b = a+0.5, b+0.5
# coeffs pour taille verticale
d, i, h = 0.5, -1.2, -1.8
# coeffs pour taille horizontale
l,dl = 1.5, 0.6
# pour dimension couronne :
dx, dy = 0.2, 0.2
# coordonnées des sommets du polygone, 'centré' sur (a,b) :
coord = [ (a+l*dx, b+d*dy), (a+l*dx,b+h*dy), (a+dl*dx,b+i*dy),
(a,b+h*dy), (a-dl*dx, b+i*dy),
(a-l*dx, b+h*dy), (a-l*dx, b+d*dy)]
return coord
def dessinCouronne(self, ligne, colonne, couleur='red') :
u = self.unite
# les sommets du polygone délimitant la couronne :
coordpolygone = self.couronne(colonne,ligne)
# mise à l'échelle de la couronne :
for j, (a,b) in enumerate(coordpolygone) : coordpolygone[j]= (a*u, b*u)
# dessin de la couronne :
self.representation.add( self.representation.polygon(points=coordpolygone, fill=couleur) )
def prise(self, l1, c1, l2,c2):
"""retourne True si la reine en (l1,c1) et la reine
en (l2,c2) peuvent s'attaquer, c'est à dire
si elles sont sur une même ligne, ou colonne,
ou diagonale."""
if l1 == l2 : return True
if c1 == c2 : return True
if l1+c1 == l2+c2 : return True
if l1-c1 == l2-c2 : return True
return False
def reineEnPrise(self, col) :
for i in range(self.nbreines) :
if i==col : continue
if self.prise( self.reines[col], col, self.reines[i], i) :
return True
return False
def placeReines(self) :
for c in range(self.nbreines) :
if self.reineEnPrise(c) :
self.dessinCouronne( self.reines[c] , c , couleur='orange')
else :
self.dessinCouronne( self.reines[c] , c , couleur='red')
def __str__(self) :
""" méthode appelée lorsqu'on demandera un print de l'objet."""
ch = ''
for i in range(self.nbreines) :
ch += 'La reine de la colonne {} est en ligne {}\n'.format(i+1, self.reines[i]+1)
return ch
def montre(self) :
run_file('echiquier.svg')
if __name__ == "__main__" :
L = [6,4,1]
ech = Echiquier(nbreines=3,dimension=8,reines=L)
print(ech)
ech.montre()
Vous trouverez le module run utilisé ici (et son utilité) à cette page.