Modifications entre les versions 5 et 28 (s'étendant sur 23 versions)
Version 5 à la date du 2013-04-01 21:39:03
Taille: 3201
Éditeur: roq13-2-78-235-210-46
Commentaire:
Version 28 à la date du 2016-01-25 14:11:53
Taille: 5799
Éditeur: LionelVaux
Commentaire:
Texte supprimé. Texte ajouté.
Ligne 1: Ligne 1:
## page was renamed from Filtres d’image_brouillon
Ligne 6: Ligne 7:

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 [[https://commons.wikimedia.org/wiki/File:Tiger-2.jpg?uselang=fr|photo]] mise à disposition par Hans Stieglitz sur les ''[[https://commons.wikimedia.org/wiki/Main_Page?uselang=fr|Wikimedia commons]]'', et soumise à la licence [[ http://creativecommons.org/licenses/by-sa/3.0/deed.fr|CC-BY-SA 3.0]] :
 * [[attachment:tigre.jpg]]
 * [[attachment:tigrenb.png]]
Ligne 17: Ligne 22:
Le bout de code suivant convertit le fichier `tigre.jpg` (au format JPEG) en `tigre.png` (au format PNG) :
{{{#!highlight python
import PIL.Image as Image
im = Image.open(r'tigre.jpg')
im.save(r'tigre.png')
}}}
Essayez chez vous.

=== Informations sur une image ===

Dans un interpréteur Python, essayez :
{{{#!highlight python
import PIL.Image as Image
im = Image.open(r'tigre.jpg')
}}}
puis essayez d’utiliser la documentation interne de python
(par exemple via la fonction `dir` de Python ou 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,
{{{#!highlight python
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 :
{{{#!highlight python
pixels[0,0] = 0
im.save(r'tigre_mod.png')
}}}
Est-ce que ça fonctionne avec l’image en noir et blanc ? Avec celle en couleurs ? Quel est l’effet produit.
Ligne 19: Ligne 69:
== Application en Tk == === Premiers filtres ===
Ligne 21: Ligne 71:
== Intégration au GIMP == 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.
Ligne 23: Ligne 75:
Il est possible d’intégrer vos algorithmes de transformation d’image au [[http://www.gimp.org/|GIMP]].
Il y a un côté satisfaisant à voir tourner son travail dans un programme standard.
Il y a cependant deux difficultés :
 * le GIMP est seulement compatible avec Python 2 ;
 * le modèle d’image en mémoire n’est pas le même que celui de Pillow, donc il faudra modifier un peu vos algorithmes pour les adapter.
=== Couleurs ===
Ligne 29: Ligne 77:
Cette partie n’est donc proposée que pour les plus motivés et autonomes. Autre exercice basique : écrivez une fonction `canaux(im)` qui prend en argument une image `im` en couleurs (mode `"RGB"`) et renvoie le triplet d’images en nivaux de gris (mode `"L"`) donnant les valeurs de chaque canal (rouge, vert, bleu).
''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 ===
Ligne 32: Ligne 88:
=== Quelques indications pour commencer === Développez une série de filtres :
 * filtre en moyenne (chaque pixel est remplacé par la moyenne de son voisinage de Moore, c’est-à-dire le pixel et ses 8 voisins)
 * filtre médian (la même chose mais avec la médiane)
 * filtre qui génère un bruit aléatoire (on réfléchira ensemble à ce que ça signifie)
Ligne 34: Ligne 93:
Voilà les grandes lignes. Testez ensuite l’effet du filtre en moyenne et du filtre médian sur une image bruitée : qu’en pensez-vous ?
Ligne 36: Ligne 95:
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).
=== Filtrage linéaire ===
Ligne 39: Ligne 97:
Votre filtre doit être une fonction python `filtre(image, drawable)`. Programmez le [[https://fr.wikipedia.org/wiki/Filtre_de_Sobel|filtre de Sobel]] comme une fonction `sobel(im)` : chaque pixel de l’image filtrée est une approximation de la norme du gradient de l’intensité.
Ligne 41: Ligne 99:
Pour réaliser cette étape, il sera utile de traiter d’abord le cas général du filtrage linéaire, qui consiste à calculer pour chaque pixel le [[http://docs.gimp.org/fr/plug-in-convmatrix.html|produit de convolution]]
de son voisinage de Moore avec une matrice 3x3 fixée (le noyau) : écrivez une fonction `filtre(im,noyau)` qui fait ce travail.
Ligne 42: Ligne 102:
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.
Vous pourrez alors tester cette méthode avec les deux matrices utilisées dans le filtre de Sobel (voir [[https://fr.wikipedia.org/wiki/Filtre_de_Sobel|la page Wikipédia]]),
qui génèrent une approximation des composantes horizontale et verticale du gradient.
Ligne 46: Ligne 105:
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.
/!\ À cause des limites de valeurs pour un pixel (de 0 à 255), on perd les valeurs négatives ou trop fortes des composantes du gradient : on ne distingue que le passage d’une partie foncée à une partie claire. Pour mieux comprendre, essayez avec les matrices opposées.
Ligne 58: Ligne 107:
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 ».
Le filtre de Sobel est alors obtenu en appliquant pour chaque pixel les deux matrices, en en prenant la norme du couple de valeurs obtenues (essayez avec les normes N_1, N_2 et N_inf).
Ligne 76: Ligne 109:
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.
/!\ Vue la remarque précédente, la méthode qui consisterait à générer deux filtrages linéaires avec les matrices pour le gradient horizontal et vertical, puis en calculant la norme point à point à partir des deux images obtenues fonctionne mal : on a tronqué les valeurs trop tôt.

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 :

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) :

   1 import PIL.Image as Image
   2 im = Image.open(r'tigre.jpg')
   3 im.save(r'tigre.png')

Essayez chez vous.

Informations sur une image

Dans un interpréteur Python, essayez :

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

puis essayez d’utiliser la documentation interne de python (par exemple via la fonction dir de Python ou 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,

   1 pixels = im.load()
   2 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 :

   1 pixels[0,0] = 0
   2 im.save(r'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 prend en argument une image im en couleurs (mode "RGB") et renvoie le triplet d’images en nivaux de gris (mode "L") donnant les valeurs de chaque canal (rouge, vert, bleu). 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 :

  • filtre en moyenne (chaque pixel est remplacé par la moyenne de son voisinage de Moore, c’est-à-dire le pixel et ses 8 voisins)
  • filtre médian (la même chose mais avec la médiane)
  • filtre qui génère un bruit aléatoire (on réfléchira ensemble à ce que ça signifie)

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

Programmez le filtre de Sobel comme une fonction sobel(im) : chaque pixel de l’image filtrée est une approximation de la norme du gradient de l’intensité.

Pour réaliser cette étape, il sera utile de traiter d’abord le cas général du filtrage linéaire, qui consiste à calculer pour chaque pixel le produit de convolution de son voisinage de Moore avec une matrice 3x3 fixée (le noyau) : écrivez une fonction filtre(im,noyau) qui fait ce travail.

Vous pourrez alors tester cette méthode avec les deux matrices utilisées dans le filtre de Sobel (voir la page Wikipédia), qui génèrent une approximation des composantes horizontale et verticale du gradient.

/!\ À cause des limites de valeurs pour un pixel (de 0 à 255), on perd les valeurs négatives ou trop fortes des composantes du gradient : on ne distingue que le passage d’une partie foncée à une partie claire. Pour mieux comprendre, essayez avec les matrices opposées.

Le filtre de Sobel est alors obtenu en appliquant pour chaque pixel les deux matrices, en en prenant la norme du couple de valeurs obtenues (essayez avec les normes N_1, N_2 et N_inf).

/!\ Vue la remarque précédente, la méthode qui consisterait à générer deux filtrages linéaires avec les matrices pour le gradient horizontal et vertical, puis en calculant la norme point à point à partir des deux images obtenues fonctionne mal : on a tronqué les valeurs trop tôt.

WikISN: Filtres d’image (dernière édition le 2016-01-25 14:11:53 par LionelVaux)