Manipulations de base sur les images
Objectif
L'objectif de ce TP est d'observer visuellement l'impact de certaines opérations, souvent destructrices d'information, sur des images.
Préambule
Pour effectuer les quelques exercices de ce TP, vous allez travailler dans l'environnement notebook d'IPython/Jupyter. Pour cela, créez un répertoire pour cette matière, déplacez-vous dans celui-ci et exécutez les commandes suivantes :
$> module load python/3.6.5 $> jupyter-notebook
Ceci va ouvrir votre navigateur sur un explorateur de fichier du répertoire dans lequel vous avez lancé la commande.
Si vous obtenez un message d'erreur comme quoi la commande module n'existe pas, exécutez la commande suivante :
$> source /usr/local/Modules/init/profile.sh
Créez un nouveau projet Python3, que vous nommerez tp4.
Au début, dans la première cellule, pour activer le remplissage de l'espace de nommage avec les modules Numpy et Matplotlib (et math), écrivez la commande suivante et exécutez la cellule avec la séquence de touche Ctrl-Enter ou Shift-Enter
%pylab inline
La quantification
La quantification est la projection de valeurs continues sur une échelle à granularité réduite, principalement discrète. Habituellement, on exprime l'échelle de quantification par le nombre de bits qui seront utilisés pour représenter l'information. Par exemple, une quantification sur 16 bits en entiers signés aura une plage de valeur de -32768 à 32767.
Une image couleur numérisée est généralement représentée sous la forme d'une séquence de triplet (Rouge, Vert, Bleu) correspondant aux pixels composants l'image. Le parcourt des pixels se fait ligne par ligne, de gauche à droite. Les valeurs R, V et B sont à valeurs entières sur la plage \([0; 255]\)
Une image numérisée en noir et blanc est généralement représentée sous la forme d'une séquence de valeurs correspondant aux pixels composants l'image, exprimées en niveau de gris. La dynamique d'une image en niveau de gris est souvent de 256 niveaux.
Dans ce TP, nous n'allons traiter que des images en niveau de gris.
- Définissez la fonction quantifie(img, nb_bits) qui va retourner une copie de l'image img mais quantifiée sur nb_bits au lieu des 256 de départ.
- La fonction ascent() du module scipy.misc fournit un exemple d'une image en niveau de gris. Quelle est la taille de cette image ? Quelles sont les valeurs minimale et maximale de l'image ?
- affichez cette image avec la fonction imshow(). Par dfault, imshow interprète la plage de valeur comme une échelle représentation l'intensité de l'information. Il faut donc lui indiquer d'interpréter les valeurs comme des niveaux de gris. Pour cela, soit vous ajoutez le paramètre cmap=cm.gray à la fonction imshow(), soit vous indiquez que globalement ce sont des images en niveau de gris en exécutant l'instruction gray() dans une cellule.
- Dans une figure contenant 9 sous-figures (3x3), affichez l'image après quantification sur 8 bits (original) jusqu'à 0 bits.
Sous-échantillonnage : diminution de résolution
La diminution de résolution revient à sous-échantillonner l'image de départ. Toutefois, cette image de départ étant déjà une version numérisée, on ne va utiliser que les valeurs à notre disposition.
- Définissez la fonction down_scale(img, facteur) qui retourne une image sous-échantillonnée d'un facteur donné en paramètre.
- Une image résultant de cette fonction aura-t-elle la même plage de niveau de gris ? Aura-t-elle la même taille ?
- Dans une figure contenant 4 sous-figures (2x2), affichez l'image après sous-échantillonnage des facteurs suivants: 1 (original), 3, 9 et 25.
- Définissez la fonction down_scale_mean qui retourne une image sous-échantillonnée d'un facteur donné en paramètre, mais cette fois, la valeur retenu pour un pixel considéré ne sera pas la valeur de ce pixel mais la moyenne des NxN pixels du carré centré sur ce pixel.
- Dans une figure contenant 4 sous-figures (2x2), affichez l'image après cette seconde méthode de sous-échantillonnage des facteurs suivants: 1 (original), 3, 9 et 25.
Sur-échantillonnage : augmentation de résolution
Dans cette section, nous allons augmenter la taille d'une image. La difficulté est de créer de l'information qui n'existe plus. En effet, dans le signal continu associé à l'image, l'information est présente, mais elle ne l'est plus dans version numérisée.
Un moyen simple d'augmenter artificiellement la taille d'un signal (audio ou image) est de dupliquer l'information. Ainsi, si on souhaite augmenter d'un facteur 3 la taille d'une image, on répétera la valeur de chaque pixel 3 fois dans chaque dimension.
- Écrivez la fonction up_scale_clone qui retourne une image dont la taille dans chaque dimension a été augmentée par un facteur donné en paramètre.
- Appliquez cette fonction sur les 4 images sous-échantillonnées précédentes afin de mieux voir l'effet de crénelage de la baisse de résolution.
Une autre méthode consiste à interpoler les valeurs inconnues entre deux valeurs connues.
- Écrivez la fonction up_scale_linear qui retourne une image dont la taille dans chaque dimension est augmentée d'un facteur donné en paramètre, mais cette fois en effectuant une interpolation linéaire entre les valeurs.
- Appliquez cette fonction sur les 4 images sous-échantillonnées afin de comparer avec la première version d'interpolation.
Le résultat de cette augmentation de résolution n'est pas toujours satisfaisant et il est intéressant d'y appliquer un lissage pour essayer d'estomper les transitions entre pixel.
- Écrivez une fonction lissage qui retourne une image de même dimension mais dont pour chaque pixel on remplace sa valeur par la moyenne sur son carré avoisinant. La taille d'un côté du carré sera donné en paramètre de cette fonction.
- Appliquez cette fonction de lissage sur les 4 images interpolées par la première méthode, puis sur les 4 images interpolées par la seconde méthode. Quelle méthode vous semble donner de meilleurs résultats.