Consignes
La note ne valide pas seulement le résultat de votre programme, mais également son style :
-
choix approprié des noms de variables,
-
présence de documentation pour les fonctions importantes,
-
commentaires pertinents: la paraphrase de code, par exemple:
y = x * 2 # y est le double de x
n'apporte rien,
-
découpage des fonctions / procédures complexes en sous-fonctions / sous-procédures lorsque nécessaire...
Vérifiez ces points avant de demander à votre intervenant de valider votre code.
Liens utiles
-
email des enseignants : pierre.hyvernat@univ-smb.fr, jacques-olivier.lachaud@univ-smb.fr, tom.hirschowitz@univ-smb.fr, daniel.martins-antunes@univ-smb.fr, florent.lorne@univ-savoie.fr
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 localement ici.
Si vous utilisez Linux les images devraient être reconnues automatiquement.
1. Préliminaires
Nous allons utiliser une petite bibliothèque afin de manipuler des images (au format .ppm) comme des tableaux de pixels. N'oubliez pas de commencer par télécharger
-
le fichier à compléter tp1-rantanplan.py (n'oubliez pas de renommer le fichier),
-
les images utilisés pour les tests (n'oubliez pas de d'extraire l'archive dans le répertoire contenant les autres fichiers).
Le code pour cette question (fonction
jeDecouvreLaBibliothequeImage
) est fourni.
-
Décommentez les lignes progressivement et exécutez le code. Le but est de comprendre les fonctionalités de la bibliothèque image.py.
-
Utilisez un éditeur de texte pour ouvrir le fichier question-1.ppm généré par la fonction de test, et vérifiez que les 2 premiers pixels de l'image sont corrects.
Pour tester votre code, il suffit de lancer votre programme avec Python (menu Run puis Run Module dans Idle, ou touche F5).
Par défaut, la fonction de test pour la question 1 sera lancée. Pour tester les autres questions, il faudra décommenter les lignes pertinentes à la fin du ficher...
2. Passage en noir et blanc
Le plus simple pour passer une image en noir et blanc est passer les pixels clairs en blanc, et les pixels foncés en noir. On prend la convention qu'un pixel est
-
clair si la somme de ses canaux rouge, vert et bleu est supérieure ou égale à 382
-
foncé si la somme de ses canaux rouge, vert et bleu est inférieure ou égale à 381
Complétez la fonction imageBinaire
qui transforme une image
couleur en une image en noir ou blanc. C'est-à-dire que chaque pixel devient
soit noir, soit blanc.
Si vous utilisez la fonction de test, vous devriez obtenir le résultat suivant :
image originale | image en noir et blanc |
3. Passage en niveaux de gris
Les images uniquement en noir et blanc sont très "pixélisées". Il est beaucoup mieux d'utiliser plusieurs niveaux de gris (blanc, gris, noir) pour obtenir un meilleur résultat.
Par analogie à la distance euclidienne dans l'espace, on définit la distance entre deux couleurs (r1 , g1 , b1) et (r2 , g2 , b2) comme la racine carrée de (r1 - r2)2 + (g1 - g2)2 + (b1 - b2)2.
Complétez la fonction couleurDiff
qui renvoie un entier
indiquant à quel point deux couleurs sont différentes.
Une distance de 0 indique que les deux couleurs sont identiques ; et plus la valeur retournée est grande, plus les couleurs sont différentes. (Cette différence est simplement le carré de la distance entre les deux couleurs...)
Par exemple :
>>> couleurDiff( (0,0,0), (255,255,255) )
195075
>>> couleurDiff( (0,123,57), (22,45,58) )
6569
Complétez la fonction troisNuancesDeGris
qui transforme une
image couleur en une image en noir / gris / blanc.
Chaque pixel devient soit noir, soit gris, soit blanc.
Conseil : pour chaque pixel, calculez d'abord sa distance aux trois couleurs noir, gris et blanc, et choisissez la plus proche (c'est à dire la moins différente)...
Après exécution de la fonction de test, vous devriez obtenir le résultat suivant :
image originale | image en noir, gris et blanc |
4. Simplifier les couleurs
On peut augmenter le nombre de niveaux de gris, ou choisir d'autre couleurs pour limiter la palette utilisée. Il faut pour ceci choisir, pour chaque pixel, la couleur la plus proche parmi celles autorisées.
Complétez la fonction plusSemblable
qui détermine, parmi une
liste de couleurs, laquelle ressemble le plus à une couleur donnée.
Complétez la fonction repeindre
qui transforme une image en une
image où chaque pixel est remplacé par la couleur qui lui ressemble le plus
parmi la liste de couleurs donnée en argument.
Attention : cette fois-ci, le premier paramètre de la fonction
repeindre
est une variable de type Image
et non une
chaine de caractère indiquant le nom du fichier.
Par exemple, la fonction de test utilise la fonction repeindre
avec la liste [ (0,0,0) , (127,127,127), (255,255,255) ]
, qui
doit donc produire le même résultat que la fonction
troisNuancesDeGris
. L'autre liste utilisée doit fournir le
résultat suivant :
image originale |
[blanc, noir, rouge, vert, bleu, jaune, gris, vertpomme]
|
Pour obtenir une image ne contenant que du gris, il faut utiliser une liste de gris d'intensités croissante.
Écrivez la fonction genKGris
qui permet de générer une liste de
k
teintes de gris. Par exemple
>>> genKgris(2)
[(0, 0, 0), (255, 255, 255)]
>>> genKgris(3)
[(0, 0, 0), (127, 127, 127), (255, 255, 255)]
>>> genKgris(4)
[(0, 0, 0), (85, 85, 85), (170, 170, 170), (255, 255, 255)]
La fonction de test utilisera la fonction repeindre
pour
transformer l'image de départ avec 16 niveaux de gris. Vous devriez obtenir
image originale | 16 niveaux de gris |
5. Effets : repeindre des morceaux d'image
Un prédicat est une fonction qui teste si un objet possède une propriété.
Dans le cadre de ce TP, on appellera prédicat une fonction qui prend en
entrée deux coordonnées x
et y
et retourne un
booléen indiquant si le pixel (x,y)
satisfait un certain critère.
Le but de cet exercice est de reprendre le code de la fonction
repeindre
pour qu'il ne traite que les pixels satisfaisant un
prédicat. On pourra ainsi repeindre seulement un dique au milieu de l'image.
Le prédicat sera passé en argument à la fonction repeindreSi
dont vous devez écrire le code.
En Python, il est possible de donner des fonctions comme arguments d'autre fonctions :
def afficheResultat( x, fct ) :
y = fct(x)
print("le résultat de la fonction sur", x, "est", y)
def f( x ) :
return 2*x
def g( x ) :
return -x
donnera
>>> afficheResultat(1, f)
le résultat de la fonction sur 1 est 2
>>> afficheResultat(1, g)
le résultat de la fonction sur 1 est -1
>>> afficheResultat(12, f)
le résultat de la fonction sur 12 est 24
>>> afficheResultat(123, g)
le résultat de la fonction sur 123 est -123
-
Complétez la fonction dansCercle qui teste si un point est dans un cercle.
-
Complétez la fonction dansRectangle qui teste si un point est dans un rectangle.
-
Complétez la fonction repeindreSi qui repeint une image mais en modifiant que les pixels satisfaisant un prédicat.
Voici les images générées par la fonction de test :
question-8a.jpg | question-8b.jpg |
Complétez la fonction faireNBandes
qui utilise les fonctions
précédentes pour tranformer une image en n
bandes verticales
telles que :
-
La 1ère bande ne contient que du noir et du blanc.
-
La 2ème bande ne contient que du noir, du gris et du blanc.
-
La 3ème bande ne contient que 4 niveaux de gris.
-
La 4ème bande ne contient que 5 niveaux de gris.
-
...
La fonction de test devrait produire les images suivantes :
image originale |
3 bandes |
10 bandes |