Les programmes ci-dessous ne sont pas à réaliser le jour de la formation
(sauf s'il vous reste du temps bien évidemment). Ils sont là
pour vous donner d'autres idées d'exercices (ou vous entraîner si
besoin).
Module PIL - Exercices supplémentaires
Les programmes ci-dessous ne sont pas à réaliser le jour de la formation
(sauf s'il vous reste du temps bien évidemment). Ils sont là
pour vous donner d'autres idées d'exercices (ou vous entraîner si
besoin).
Le programme à concevoir doit faire en sorte que l'image obtenue soit l'image
d'origine en «négatif», comme le présentent les deux images ci-dessous.
L'image du logo ISN-IREM
est téléchargeable en cliquant
dessus.
Image d'origine au format .png |
Négatif de l'image |
---|---|
![]() |
![]() |
##----- Importation des Modules -----##
from PIL import Image # Ne pas oublier de l'importer pour un programme indépendant
##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM.jpg')
couleur = im.mode
l, h = im.size
##----- Conception de la nouvelle image -----##
im_nega = Image.new(couleur, (l, h)) # Symetrie horizontale
for x in range(l):
for y in range(h): # On parcourt chaque pixel de l'image analysée plus haut
r, v, b = im.getpixel((x, y)) # On récupère le triplet de couleur
im_nega.putpixel((x, y), (255-r, 255-v, 255-b))
im_nega.save('Logo_ISN-IREM_Negatif.jpg')
im_nega.show()
L'image ci-contre est constituée de sept carrés de couleur noir, rouge, vert, jaune, bleu, magenta et cyan.
carre()
qui permet
d'ajouter à une image un carré de 100
pixels
de côté et de couleur unie.
def carre(im, h, r, v, b):
""" Entrees : im est une image, h est une ordonnée, (r, v, b) est un triplet d'entiers entre 0 et 255
Sorties : Ajoute à une image im (à partir de l'ordonnée h) un carré de 100 pixels de côté et de
couleur ayant pour composantes (r, v, b)."""
for x in range(100) :
for y in range(h*100, (h+1)*100) :
im.putpixel((x, y), (r, v, b))
Voici une méthode qui « joue » sur les composantes RVB des couleurs primaires et secondaires :
##----- Importation des Modules -----##
from PIL import Image # Ne pas oublier de l'importer pour un programme indépendant
##------ Définition des Fonctions ------##
def carre(im, h, r, v, b):
"""Cette fonction ajoute à une image im un carré de 100 pixels
de côté et de couleur unie."""
for x in range(100) :
for y in range(h*100, (h+1)*100) :
im.putpixel((x, y), (r, v, b))
##------ Programme principal ------##
##----- Informations sur l'image -----##
largeur = 100 # largeur de l'image, en pixels
hauteur = 700 # hauteur de l'image, en pixels
couleur = 'RGB'
##----- Conception de la nouvelle image -----##
im = Image.new(couleur, (largeur, hauteur))
h = 0
for i in range(2):
for j in range(2):
for k in range(2):
if not(i == j == k ==1):
carre(im, h, 255*k, 255*j, 255*i)
h += 1
im.save('Carres_Empiles.jpg')
im.show()
256
x256
x256
couleursOn souhaite afficher la palette de toutes les couleurs possibles (certaines en double) au format RGB (ci-contre, sans les textes).
##----- Importation des Modules -----##
from PIL import Image # Ne pas oublier de l'importer pour un programme indépendant
##----- Informations sur l'image -----##
largeur = 511 # largeur de l'image, en pixels
hauteur = 511 # hauteur de l'image, en pixels
couleur = 'RGB'
##----- Conception de la nouvelle image -----##
im = Image.new(couleur, (largeur, hauteur))
for x in range(largeur):
# La figure est divisée en quatre carrés
# Première moitié des abscisses
if x < 256:
r = 255-x
b = 0
# Seconde moitié des abscisses
else:
r = 0
b = x-255
for y in range(hauteur):
# Le carré "blanc"
if x < 256 and y > 255:
r, v, b = 255, 255, 255
# Première moitié des ordonnées
elif y < 256:
v = 255-y
# Seconde moitié des ordonnées
else:
v = 0
r = y-255
im.putpixel((x, y), (r, v, b))
im.save('Palette.jpg')
im.show()
Cet exercice est un extrait et une adaptation du document ressource disponible sur le site eduscol.
Dans une image matricielle, chaque pixel a, au maximum, huit voisins.
On a représenté ci-contre le pixel de coordonnées (x, y)
avec ses voisins.
A partir d'une image en nuances de gris (au format
'L'
du module PIL
, c'est-à-dire
que la nuance de chaque pixel est définie par un unique entier compris entre
0
et 255
.),
programmer l'algorithme ci-dessous afin d'obtenir une «mise en relief»
de cette image :
(x, y)
et de niveau de gris
g
.g
à partir des niveaux de gris des
pixels voisins :
g = 128 + (-2*m-n-p+q+s+2*t) // 8
.voisins()
qui renvoie la liste des coordonnées des pixels voisins du pixel de coordonnées
(x, y)
.
Question supplémentaire : justifier que cette nouvelle valeur de g
est bien comprise entre 0
et
255
.
Image d'origine | Image en relief |
---|---|
![]() |
![]() |
voisins()
1
pixel
d'épaisseur pour avoir une fonction voisins()
plus facile à définir...
Première fonction possible : on a encadré l'image de bords noirs donc chaque pixel de l'image d'origine a huit voisins.
def voisins(x, y, l, h):
""" Entrees : x et y sont les coordonnées d'un pixel situé dans une image de largeur l et de hauteur h
Sorties : Renvoie la liste des coordonnées des pixels voisins de ce pixel."""
liste = [(x-1, y-1), # On considère que chaque pixel a 8 voisins
(x-1, y),
(x-1, y+1),
(x, y-1),
(x, y+1),
(x+1, y-1),
(x+1, y),
(x+1, y+1)]
return liste
Seconde fonction possible : on gère les pixels situés au bord et/ou dans les «coins» de l'image.
def voisins(x, y, l, h):
""" Entrees : x et y sont les coordonnées d'un pixel situé dans une image de largeur l et de hauteur h
Sorties : Renvoie la liste des coordonnées des pixels voisins de ce pixel."""
liste = [(x-1, y-1), # On considère que chaque pixel a 8 voisins
(x-1, y),
(x-1, y+1),
(x, y-1),
(x, y+1),
(x+1, y-1),
(x+1, y),
(x+1, y+1)]
for coor in reversed(liste): # On parcourt la liste renversée
if coor[0]<0 or coor[0]>l-1 or coor[1]<0 or coor[1]>h-1:
liste.remove(coor) # Lorsque les coordonnées sont hors-domaine, on les enlève de la liste
# (raison pour laquelle il faut parcourir la liste renversée)
return liste
Avec la première fonction voisins()
et la création d'une image comportant des bords :
##----- Importation des Modules -----##
from PIL import Image
##----- Définition des Fonctions -----##
def voisins(x, y, l, h):
""" Entrees : x et y sont les coordonnées d'un pixel situé dans une image de largeur l et de hauteur h
Sorties : Renvoie la liste des coordonnées des pixels voisins de ce pixel."""
liste = [(x-1, y-1), # On considère que chaque pixel a 8 voisins
(x-1, y),
(x-1, y+1),
(x, y-1),
(x, y+1),
(x+1, y-1),
(x+1, y),
(x+1, y+1)]
return liste
def compo(im, liste):
""" Entrees : im est une image, liste contient les coordonnées des voisins d'un pixel
Sorties : Renvoie la composante grise du pixel calculée à partir des composantes
de ses 6 voisines m, n, p, q, s et t dont les coordonnées se trouvent aux indices
0, 1, 3, 4, 6, 7 dans la liste."""
for i in range(8):
liste[i] = int(im.getpixel(liste[i]))
return 128 + (-2*liste[0]-liste[1]-liste[3]+liste[4]+liste[6]+2*liste[7])
##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM_Gris.jpg')
l, h = im.size
##----- Ajout de bords à cette image -----##
im_grande = Image.new('L', (l+2, h+2))
for x in range(l+2):
for y in range(h+2):
if x==0 or y==0 or x==l+1 or y==h+1:
im_grande.putpixel((x,y), 0)
else:
im_grande.putpixel((x,y), im.getpixel((x-1, y-1)))
im_grande.save('Logo_ISN-IREM_Bords.jpg')
im_grande.show()
##----- Conception de la nouvelle image -----##
im_grande = Image.open('Logo_ISN-IREM_Bords.jpg')
im_relief = Image.new('L', (l, h))
for x in range(l):
for y in range(h):
im_relief.putpixel((x,y), compo (im_grande, voisins(x+1, y+1, l, h)))
##-----Finalisation-----##
im_relief.save('Logo_ISN-IREM_Relief.jpg')
im_relief.show()
Avec la seconde fonction voisins()
,
davantage modifiée :
##----- Importation des Modules -----##
from PIL import Image
##----- Définition des Fonctions -----##
def voisins(im, x, y, l, h):
""" Entrees : x et y sont les coordonnées d'un pixel situé dans l'image im de largeur l et de hauteur h
Sorties : Renvoie la liste des coordonnées des pixels voisins de ce pixel."""
liste = [(x-1, y-1), # On considère les 6 voisins "intéressants"
(x-1, y),
(x, y-1),
(x, y+1),
(x+1, y),
(x+1, y+1)]
s = [] # Liste des composantes actualisées m, n, p, q, s et t
for coor in liste:
if coor[0]<0 or coor[0]>l-1 or coor[1]<0 or coor[1]>h-1:
s.append(255) # Si le pixel est "hors cadre", on lui attribue la couleur blanc
else:
s.append(im.getpixel(coor)) # Sinon on ajoute sa composante
g = 128 + (-2*s[0]-s[1]-s[2]+s[3]+s[4]+2*s[5])
return g
##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM_Gris.jpg')
l, h = im.size
##----- Conception de la nouvelle image -----##
im_relief = Image.new('L', (l, h))
for x in range(l):
for y in range(h):
im_relief.putpixel((x,y), voisins(im, x, y, l, h))
##-----Finalisation-----##
im_relief.save('Logo_ISN-IREM_Relief.jpg')
im_relief.show()
Pour localiser différents objets dans une image, il est nécessaire de réussir à localiser les contours de ces objets. Généralement, les nuances des pixels voisins seront très différentes les unes des autres.
Pour cela, on peut appliquer un algorithme de distance 1 (au sens
de «distance dans un repère orthonormé») qui va calculer pour le pixel de
coordonnées (x, y)
la distance entre les niveaux de gris de ses voisins :
\(d = \sqrt{\left(n-s\right)^2+\left(p-q \right)^2}\).
En comparant cette distance à un certain seuil (à définir), le pixel de
coordonnées (x, y)
sera affiché soit en noir, soit en blanc. Appliquer
le programme ainsi conçu au logo ISN-IREM Gris définit en nuances de gris.
Image d'origine | Image détourée |
---|---|
![]() |
![]() |
math
. Pour le reste,
c'est quasi-identique à la mise en relief.
Attention, l'image d'origine est en mode couleur 'L'
qui définit une image en nuances de gris.
##----- Importation des Modules -----##
from PIL import Image
from math import sqrt
##----- Définition des Fonctions -----##
def ecart(im, x, y, l, h):
""" Entrees : x et y sont les coordonnées d'un pixel situé dans une image de largeur l et de hauteur h
Sorties : calcule les variations de niveau de gris autour (distance 1) de ce pixel"""
liste = [(x, y-1), # On considère les 4 voisins "intéressants"
(x, y+1),
(x-1, y),
(x+1, y)]
compo = [] # Liste des composantes actualisées n, s, p et q
for coor in liste:
if coor[0]<0 or coor[0]>l-1 or coor[1]<0 or coor[1]>h-1:
compo.append(255) # Si le pixel est "hors cadre", on lui attribue la couleur blanc
else:
compo.append(im.getpixel(coor)) # Sinon on ajoute sa composante
d = int(sqrt((compo[0]-compo[1])**2+(compo[2]-compo[3])**2))
return d
##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM_Gris.jpg')
l, h = im.size
##----- Conception de la nouvelle image -----##
seuil = 25 # Seuil de "détourage"
im_detour = Image.new('L', (l, h))
for x in range(l):
for y in range(h):
if ecart(im, x, y, l, h) < seuil:
im_detour.putpixel((x,y), 255)
else:
im_detour.putpixel((x,y), 0)
##-----Finalisation-----##
im_detour.save('Logo_ISN-IREM_detoure.jpg')
im_detour.show()
Le logo ISN-IREM
est trop grand (1600*1000)
pour être utilisée en vraie grandeur dans certains des exercices précédents
L'image a été compressée (réduite) de manière automatique par le
logiciel d'affichage (ici le navigateur).
Le but de cet exercice est de programmer une compression de l'image en suivant l'algorithme ci-dessous :
k
le coefficient de réduction : la largeur et la hauteur
de l'image seront divisées par k
donc le nombre total de pixels
sera divisé par k²
.k
.k = 2
.k²
pixels par un unique pixel dont les composantes
(r, v, b)
sont les moyennes des composantes des k²
pixels de l'image d'origine.
On a appliqué le coefficient de réduction k = 4
:
##----- Importation des Modules -----##
from PIL import Image
##----- Coefficient de Réduction -----##
k = 4
##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM_Original.jpg')
l, h = im.size
##----- Conception de la nouvelle image -----##
largeur, hauteur = l//k, h//k # Nouvelles dimensions
im_red = Image.new('RGB', (largeur, hauteur)) # Image "compressée"
for x in range(0, largeur*k, k): # Saut de k en k en largeur
for y in range(0, hauteur*k, k): # Saut de k en k en hauteur
rouge, vert, bleu = 0, 0, 0 # Somme des composantes des k² pixels
for i in range(k):
for j in range(k):
r, v, b = im.getpixel((x+i, y+j))
rouge += r
vert += v
bleu += b
rouge = rouge//(k*k) # On divise les sommes par le nombre de pixels (moyennne)
vert = vert//(k*k)
bleu = bleu//(k*k)
# On place le pixel dans l'image réduite (attention aux coordonnées...)
im_red.putpixel((x//k, y//k), (rouge, vert, bleu))
##-----Finalisation-----##
im_red.save('Logo_ISN-IREM_Reduit.jpg') # Sauvegarde
im_red.show() # Affichage
Le programme précédent «détruit» dans l'image les lignes en bas et les colonnes à droite qui sont en trop. Avec un peu d'arithmétique, on peut «harmoniser» cette destruction entre les lignes du haut et du bas ainsi qu'entre les colonnes de gauche et de droite :
##----- Importation des Modules -----##
from PIL import Image
##----- Définition des Fonctions -----##
def moy(im, x, y, k):
""" Entrees : im est une image, x et y sont les coordonées du pixel étudié, k est le coef de réduction
Sorties : Renvoie le nouveu triplet de composantes (r, v, b) du pixel de coordonnées (x, y).
Ces composantes sont la moyenne des composantes d'un carré de pixels de côté k."""
rouge, vert, bleu = 0, 0, 0 # Somme des composantes des k² pixels
for i in range(k):
for j in range(k):
r, v, b = im.getpixel((x+i, y+j))
rouge += r
vert += v
bleu += b
rouge = rouge//(k*k) # On divise les sommes par le nombre de pixels (moyennne)
vert = vert//(k*k)
bleu = bleu//(k*k)
return (rouge, vert, bleu)
##----- Coefficient de Réduction -----##
k = 4
##----- Informations sur l'image d'origine -----##
im = Image.open('Logo_ISN-IREM_Original.jpg')
l, h = im.size
##----- Conception de la nouvelle image -----##
largeur, hauteur = l//k, h//k # Nouvelles dimensions
im_red = Image.new('RGB', (largeur, hauteur)) # Image "compressée"
espace_l = (l-k*largeur)//2 # nombre de pixels à enlever à gauche des lignes
espace_c = (h-k*hauteur)//2 # nombre de pixels à enlever en haut des colonnes
for x in range(espace_l, espace_l+largeur*k, k): # Saut de k en k en largeur
for y in range(espace_c, espace_c+hauteur*k, k): # Saut de k en k en hauteur
# On place le pixel dans l'image réduite (attention aux coordonnées...)
im_red.putpixel((x//k, y//k), moy(im, x, y, k))
##-----Finalisation-----##
im_red.save('Logo_ISN-IREM_Reduit.jpg') # Sauvegarde
im_red.show() # Affichage