Préambule

Ce TP utilise la bibliothèque Pillow : voir les instructions.

Avant de commencer, je vous suggère d’aller piocher une image de test pas trop grosse (disons au maximum 1024 pixels dans chaque dimension). À défaut en voilà deux, obtenues à partir d’une photo mise à disposition par Hans Stieglitz sur les Wikimedia commons, et soumise à la licence CC-BY-SA 3.0 :

tigre.jpg

tigrenb.png

Filtres d’image

Cette partie du TP concerne l’algorithmique de l’image. Plus précisément, on manipulera des images matricielles, c’est-à-dire représentées par des tableaux de pixels.

On utilise Pillow pour s’affranchir de la question des formats de fichiers.

Ouverture et enregistrement de fichiers d’image avec Pillow

Le bout de code suivant convertit le fichier tigre.jpg (au format JPEG) en tigre.png (au format PNG) :

import PIL.Image as Image
im = Image.open('tigre.jpg')
im.save('tigre.png')

Essayez chez vous.

Informations sur une image

Dans un interpréteur Python, essayez :

import PIL.Image as Image
im = Image.open('tigre.jpg')

puis essayez d’utiliser la documentation interne de python (par exemple via la commande help de l’interpréteur) pour explorer les informations fournies par l’objet image.

Essayez par exemple d’obtenir sa taille.

Représentation d’une image en mémoire

Si im est une image chargée avec PIL.Image.open, on accède à ses pixels via la fonction im.load() qui renvoie un tableau indexé par des couples d’entiers (et non pas une matrice au sens python du terme).

Par exemple,

pixels = im.load()
print(pixels[0,0])

renvoie la valeur du pixel en haut à gauche de l’image.

Affichez des pixels de l’image en couleurs, puis de l’image en noir et blanc. Que remarquez-vous ?

Modifier une image

Pour modifier un pixel, on change sa valeur dans le tableau des pixels. Essayez :

pixels[0,0] = 0
im.save('tigre_mod.png')

Est-ce que ça fonctionne avec l’image en noir et blanc ? Avec celle en couleurs ? Quel est l’effet produit.

Premiers filtres

Vous êtes parés pour écrire votre premier filtre : écrivez une fonction rev(im) qui remplace tous les pixels de l’image im par leur valeur en négatif. Traitez d’abord le cas en noir et blanc, puis celui en couleurs. Essayez de la modifier pour que ça fonctionne dans tous les cas.

Couleurs

Autre exercice basique : écrivez une fonction canaux(im) qui extrait les canaux d’une image couleur et les sauve dans des fichiers séparés comme des images en noir et blanc. Indice: il faut créer de nouvelles images en utilisant Image.new (voir help(Image.new) dans l’interpréteur).

Écrivez une fonction couleur_vers_gris(im) qui transforme une image en couleurs vers une image en niveaux de gris. Est-ce convaincant ? Comparez avec l’image en niveaux de gris proposée plus haut : comment expliquez-vous la différence ?

Dans la suite, on pourra se limiter au cas des images en noir et blanc.

Lissage et bruit

Développez une série de filtres :

Testez ensuite l’effet du filtre en moyenne et du filtre médian sur une image bruitée : qu’en pensez-vous ?

Filtrage linéaire

Implémentez le filtre de Sobel.

Plus généralement, écrivez un filtre paramétré par une matrice 3x3, qui calcule la valeur d’un pixel en appliquant le filtre à son voisinage de Moore. Testez quelques valeurs.

Interface en Tk

Tout à fait optionnel.

Si vous avez des restes de Tkinter, mettez les en œuvre pour écrire une interface graphique qui permette de :

Intégration au GIMP

Extrêmement optionnel.

Il est possible d’intégrer vos algorithmes de transformation d’image au GIMP. Il y a un côté satisfaisant à voir tourner son travail dans un programme standard. Il y a cependant deux difficultés :

Cette partie n’est donc proposée que pour les plus motivés et autonomes, en remplacement de la précédente.

Quelques indications pour commencer

Voilà les grandes lignes.

Il faut créer un programme Python 2, disons filtre.py, qui commence par importer le module gimpfu. Le fichier contenant ce programme doit être exécutable, et ranger dans un dossier où le GIMP cherche ses greffons (ça se règle dans les préférences).

Votre filtre doit être une fonction python filtre(image, drawable).

L’argument image est un objet complexe qui représente l’image et toute ses métadonnées (calques, etc.). L’argument drawable est la surface (calque ou canal) sur laquelle on dessine. La méthode la plus simple pour modifier l’image est de faire appel aux outils de GIMP.

Par exemple, la fonction suivante dessine un point au centre de l’image :

def centre(img,drawable):
  largeur = drawable.width
  hauteur = drawable.height
  xc = largeur//2
  yc = hauteur//2
  gimp.pdb.gimp_pencil(drawable,2,(xc,yc,xc,yc))
  return

On utilise ici l’outil « crayon » du GIMP. Pour connaître les méthodes disponibles, le GIMP fournit un « navigateur de procédures » dans le menu d’aide.

Ensuite, il faut enregistrer votre greffon dans la base de donnée, pour que le GIMP connaisse son existence. Ceci se fait avec la fonction register du module gimpfu :

register(
    "centre",
    "Rajoute un (gros) point au centre de l’image",
    "Rajoute un (gros) point au centre de l’image",
    "Lionel Vaux",
    "Lionel Vaux",
    "2013",
                "<Image>/Filters/Render/_Centre",
    "*",
    [],
    [],
    centre,
)

Après un redémarrage éventuel du GIMP, le filtre est diponible dans le menu « Filtres/Rendu ».

Youpi !

Et ensuite ?

Pour modifier directement les pixels d’une image de manière efficace, il faut utiliser les pixel regions : voir http://www.gimp.org/docs/python/. À ce point du TP, un peu de recherche autonome sur internet sera utile…

Une idée intéressante : écrire un filtre qui génère un nouveau calque affichant en transparence un diagramme de Voronoi.