4. Images matricielles

Qu'est-ce qu'une image matricielle ?

Images matricielles et vectorielles

Mario

Une image informatique est constituée d'un ensemble de points élémentaires, appelés pixels; la vision de ces pixels de plus ou moins loin permet à l’œil de reconstituer globalement l'image réelle.

Ces pixels étant organisés en "lignes" et en "colonnes", c'est à dire une matrice ( en anglais bitmap ), on parle d'image matricielle lorsque l'on décrit effectivement l'image pixel par pixel. ( il existe en effet un autre type d'images dites vectorielles, qui ne sont pas décrites point par point mais par des fonctions mathématiques : droites, cercles, courbes,...)

On comprend que ce principe est à l'origine des limitations liées aux images matricielles :

  • pour être la plus fidèle à la réalité, une image doit donc être composée de pixels les plus petits possibles : ils ne doivent même pas être discernables par l’œil. Si c'est le cas, on dit que l'image est pixelisée.
  • plus les pixels sont petits, plus leur nombre sera donc grand pour coder une image donnée; le fichier qui stockera les informations relatives à l'image sera donc d'autant plus gros. Selon la situation ( taille du support de stockage, lourdeur de l'envoi de l'image sur un réseau, ....), cette taille peut poser problème.

Un compromis est donc généralement à faire entre la finesse de l'image et la taille du fichier résultant; ce compromis dépend de la destination de l'image : affichage en petite ou grande taille, affichage ou impression, envoi ou pas sur un réseau,...

Les fichiers d'images vectorielles sont beaucoup plus "légers", mais par contre, ils ne permettent pas de représenter tous les détails d'une photo par exemple.

Image pixelisée
Image pixelisée
Image non pixelisée
Image non pixelisée

Quelques notions à savoir sur les images matricielles

  • Définition d'une image = nombre de pixels composant l'image; la définition est généralement donnée sous forme du produit du nombre de pixels horizontaux de l'image par le nombre de pixels verticaux : 640 x 480, 1900 x 1040,...
    Modifier la définition d'une image permet donc de la redimensionner, la déformer, de diminuer sa taille d'impression ou d'affichage à l'écran, etc...
  • Profondeur des couleurs : il s'agit de la manière dont la luminosité ou la couleur est codée dans l'image. Plusieurs modes de couleur existent :
    1. Monochrome: Avec ce mode, il est possible d'afficher uniquement des images en deux "couleurs" : noir ou blanc.
      Un pixel dont la valeur de luminosité est égale à 0 est considéré comme noir, 1 comme blanc.
    2. Niveaux de gris ( "Noir et blanc" ): il permet d'obtenir différentes valeurs de gris, afin d'afficher des images nuancées.
      Plus la valeur est grande, et plus la luminosité du pixel est claire.
      Image en noir et blanc
      Image en noir et blanc
      Image en niveaux de gris
      Image en niveaux de gris
      Le nombre de niveaux de gris utilisables est donné par le codage de chaque pixel, exprimée en bits :
      • 8 bits -> 256 niveaux de gris
      • 16 bits -> 65 536 niveaux de gris
      • ...
    3. Mode colorimétrique RVB : pour les images en couleur, on se base sur le principe de la synthèse additive des couleurs, selon lequel toute nuance de couleur peut être reproduite par le "mélange" d'une quantité variable de trois couleurs primaires, le Rouge, le Vert et le Bleu; le blanc correspond au mélange de la même "quantité" de chacune de ces 3 couleurs, le noir à l'absence de ces trois couleurs.
      L'information sur chaque couleur primaire est stockée séparément, et la couleur d'un pixel est donc donnée par un ensemble de trois chiffres indiquant la "quantité" de chaque couleur primaire dans la teinte globale du pixel.
      Cette "quantité" est codée par un nombre d'autant plus grand que la couleur primaire est présente dans la teinte finale du pixel; en mode 8 bits, ce nombre peut varier de 0 à 255, en mode 16 bits, de 0 à 65 535 : le nombre de nuances possibles est donc alors plus élevé...
      Synthèse additive des couleurs
      Synthèse additive des couleurs

      Pour coder par exemple un pixel rouge en mode 8 bits, les trois valeurs seront ainsi : (255,0,0); pour un bleu : (0,0,255); un jaune ( mélange de rouge et de vert ) : (255,255,0),etc...

Représentation d'une image matricielle en mémoire

On voit tout de suite le lien avec la notion de matrices pour représenter une image matricielle en mémoire d'un ordinateur :

Coordonnées d'un pixel
  • chaque pixel correspondra à une "case" d'une matrice, qui aura autant de "lignes" et de "colonnes" que nécessite la définition de l'image; les coordonnées de chaque pixel dans l'image correspondront aux index de l'élément correspondant dans la matrices ( [ligne][colonne] ).
  • l'information stockée dans chaque "case" correspondra à la valeur du pixel : un nombre codant la luminosité pour les images monochrome ou en niveaux de gris, et un ensemble de trois valeurs ( un tuple par exemple...) codant les 3 couleurs primaires dans le cas d'une image en couleur.

Les formats d'image

Toutes ces informations sur les pixels, il va bien falloir les stocker dans un fichier à un moment donné !

De nombreux formats de fichiers image existent, le plus connu et le plus utilisé de nos jours est le format JPEG (Join Photographic Expert Group); le problème est qu'il s'agit d'un format compressé assez délicat à manipuler.

Pour simplifier notre travail nous utiliserons deux formats d'image beaucoup plus simples et non compressés : le format PGM ( pour des images monochrome ou en niveaux de gris ) et PPM ( images en couleur ).

Travail avec les images matricielles

Le but étant de vous faire manipuler des matrices et pas de vous ennuyer avec des problèmes d'écriture de fichiers, vous trouverez ici un script contenant deux fonctions pour ouvrir et écrire des fichiers au format PGM ou PPM.

  • téléchargez et enregistrez ce script dans le même dossier que les scripts que vous allez écrire dans ce chapitre
  • importez le script au début de votre code :
    
    from images import *
    						
  • vous disposez alors de deux fonctions :
    • une fonction pour lire un fichier au format PGM ou PPM :
      
      data = lecture('nom_du_fichier.pgm/ppm')
      							
      Cette fonction renvoie la matrice contenant les valeurs des pixels de l'image, soit, selon l'extension du fichier, des valeurs uniques de niveaux de gris pour les fichiers PGM, ou des tuples de trois valeurs (R,V,B) pour les PPM ).
    • une fonction pour écrire un fichier PGM ou PPM :
      
      ecriture(data,'nom_du_fichier.pgm/ppm')
      							
      La fonction détecte l'extension du fichier : la matrice data devra donc contenir des valeurs en cohérence avec le format du fichier ( valeurs uniques de niveaux de gris pour les fichiers PGM, ou tuples de trois valeurs (R,V,B) pour les PPM ).
Visualisation des fichiers créés

Une fois écrits sur le disque, les fichiers images peuvent être ouverts en double-cliquant sur leur nom.

Création d'images matricielles simples (exercice_C40.py)

Vous allez écrire un unique script qui utilise des matrices pour créer automatiquement des images numériques et les enregistrer au format PGM ou PPM.

Pour chaque image, vous écrirez une fonction qui construira la matrice des valeurs de pixels, et qui renverra ensuite cette matrice au programme principal.
La matrice sera construite selon une méthode à votre choix : élément par élément, ou par compréhension.

Les différentes fonctions seront appelées à partir du programme principal, dans lequel vous écrirez également les instructions pour enregistrer les fichiers images correspondant.

Voila un exemple qui crée une image de 200 x 200 pixels tous noirs :


from images import *

def noir()->list:
	'''
		Fonction qui créé une matrice correspondant à une image de 200 x 200 pixels noirs

		Entrée :
			Aucune
		Sortie :
			la matrice des 200 x 200 valeurs des pixels
	'''

	m = [[0 for col in range(200)] for lin in range(200)]	# construction de la matrice contenant les valeurs des pixels ( 0 = noir )

	return m

'''PROGRAMME PRINCIPAL'''

data = noir() # appel de la fonction et récupération de la matrice qu'elle a construit

ecriture(data, 'noire.pgm')  # écriture du fichier image
			

Du noir et du blanc

Commençons pour simplifier par des images en niveaux de gris.

Une image grise
  1. Une image ne contenant que des pixels noirs, et dont la largeur et la hauteur sont passées comme arguments à la fonction.
  2. Modifier la fonction précédente pour qu'elle crée une image ne contenant que des pixels gris, et dont la largeur, la hauteur et le niveau de gris ( entre 0 et 255 ) sont passées comme arguments à la fonction.
    La fonction devra vérifier que le valeur du niveau de gris donnée par l'utilisateur est cohérente...
Une image aléatoire

Une image contenant des pixels de valeurs aléatoires ( entre 0 et 255 ), et dont la largeur, la hauteur sont passées comme arguments à la fonction.

Le quadrillage

Attention, plus délicat; si vous avez du mal avec la construction par compréhension, suivez ces deux étapes pour mener à bien votre codage :

  • dans la fonction, construisez d'abord une nouvelle matrice, de la même taille que l'image à créer, et ne contenant que des "pixels blancs" ( = valeur 255 )
  • parcourez ensuite tous les éléments de cette matrice de façon à modifier les pixels qui vous permettront d'obtenir le résultat recherché; il faudra sûrement utiliser des conditions...
  1. une image de 200 x 200 pixels avec 10 "lignes" verticales; même chose avec 10 "lignes" horizontales
  2. Modifier la fonction précédente pour obtenir une image de 200 x 200 pixels représentant un quadrillage régulier, ayant 10 "lignes" et 10 "colonnes"; même chose pour 20 "lignes" et 20 "colonnes"; pour 30 "lignes" et "colonnes" ?
Le dégradé de gris
  1. Une image de 256 x 256 pixels montrant un dégradé de gris horizontal, depuis la valeur 0 à gauche jusqu'à la valeur 255 à droite
  2. Modifier la fonction précédente pour que le dégradé soit vertical
Image noire
Image noire
Image grise
Image grise
Image aléatoire
Image aléatoire
Lignes verticales
Lignes verticales
Lignes horizontales
Lignes horizontales
Quadrillage
Quadrillage
Dégradé de gris
Dégradé

Lien vers les RÉPONSES

De la couleur

Et maintenant, un peu de couleur...Vous pourrez souvent vous inspirer des scripts précédents pour créer les images suivantes au format PPM.
Rappelez-vous que dans ce cas, la couleur d'un pixel est codée non pas par une valeur unique, mais par un tuple de 3 valeurs représentant, dans l'ordre, la composante Rouge, la Verte et la Bleue ( chaque composante variant entre 0 et 255 ).

Chaque "case" des matrices représentant l'image contiendra donc un tuple de 3 valeurs et non pas une valeur unique.

Voila un exemple qui crée une image de 200 x 200 pixels tous rouges :


from images import *

def rouge()->list:
	'''
		Fonction qui créé une matrice correspondant à une image de 200 x 200 pixels rouges

		Entrée :
			Aucune
		Sortie :
			la matrice des 200 x 200 valeurs des pixels
	'''

	m = [[(255,0,0) for col in range(200)] for lin in range(200)]	# construction de la matrice contenant les valeurs des pixels ( (255,0,0) = rouge )

	return m

'''PROGRAMME PRINCIPAL'''

data = rouge() # appel de la fonction et récupération de la matrice qu'elle a construit

ecriture(data, 'rouge.ppm')  # écriture du fichier image
			
Une image colorée aléatoire

Une image contenant des pixels ayant chacun une couleur aléatoire, et dont la largeur, la hauteur sont passées comme arguments à la fonction.

Le dégradé coloré
  1. Une image de 256 x 256 pixels montrant un dégradé progressif entre deux couleurs quelconques.
  2. Modifier la fonction pour que le dégradé soit vertical
Le drapeau
  1. Une image de taille quelconque, représentant le drapeau français
  2. Une image de taille quelconque, représentant le drapeau allemand
  3. Une image de taille quelconque représentant le drapeau anglais ( non, c'est une blague... )
Couleurs aléatoires
Couleurs aléatoires
Dégradé coloré
Dégradé coloré
Drapeau français
Drapeau français
Drapeau allemand
Drapeau allemand

Lien vers les RÉPONSES

Manipulation d'images plus poussées (exercice_C41.py)

Il va s'agir maintenant d'utiliser de "vraies" images ( des photos, quoi...), pour les manipuler comme on le ferait avec un logiciel de retouche d'images.

Voila deux images au format PGM et PPM sur lesquels vous allez pouvoir travailler :

Vous écrirez les fonctions qui permettront de transformer la matrice des valeurs de pixels pour obtenir l'effet recherché.

Le programme principal de votre script devra :

  • ouvrir le ficher de l'image à transformer et récupérer la matrice des valeurs de pixels
  • appeler la fonction que vous avez écrite en lui passant la matrice comme argument, puis en récupérant la matrice transformée
  • écrire le nouveau fichier image ( modifiez son nom ! ) avec la matrice transformée

La fonction devra au préalable faire une copie de la matrice des pixels d'origine, et ne travailler ensuite que sur cette copie.


from images import *

def ma_fonction(matrice)->list:
	'''
		Fonction qui modifie une matrice de pixels pour obtenir un certain effet

		Entrée :
			la matrice des valeurs de pixels de l'image
			d'autres paramètres si besoin...
		Sortie :
			une matrice des valeurs de pixels modifiées
	'''

	...... copie de la matrice d'origine
	....... modification de la matrice des valeurs de pixels

	return matrice_modifiee

'''PROGRAMME PRINCIPAL'''

data = lecture('fichier_exemple.pgm') # lecture du fichier image d'origine et récupération de la tableau des valeurs de ses pixels

data2 = ma_fonction( data ) # appel de la fonction et récupération de la matrice modifiée

ecriture(data2, 'fichier_exemple MODIF.pgm')  # écriture du fichier image modifié
			

Le négatif

Effet très populaire dans les années 70 et 80 : les pixels blancs de l'image sont transformés en pixels noirs, et vice et versa; de manière générale, toutes les valeurs de pixels sont remplacées par leur complément à 255 :

  • 0 devient 255
  • 255 devient 0
  • donc, de manière générale, une valeur quelconque est remplacée par 255 - valeur
Chat normal
Chat normal
Chat inversé
Chat inversé

Le seuil

Effet qui revient à transformer une image en niveaux de gris en une image monochrome : tous les pixels en dessous d'une certaine valeur ( appelée "seuil" ) sont transformés en pixels noirs ( valeur = 0 ), et tous les pixels de valeur supérieure au seuil sont transformés en pixels blancs ( valeur = 255 ). Il n'y a donc effectivement plus que deux "couleurs" dans l'image.
Selon la valeur du seuil ( que l'on passera en argument à la fonction ), on obtient des effets différents :

Chat normal
Chat normal
Chat seuil 50
Seuil à 50
Chat seuil 150
Seuil à 150
Chat seuil 200
Seuil à 200

L'image retournée

Ou comment faire pivoter l'image de 180° ?

Chat normal
Chat normal
Chat renversé
Chat renversé

Indication : vous pouvez vous inspirer de la manière dont vous avez inversé une chaîne de caractères...

Noir et blanc

Comment transformer une image en couleur en image en niveaux de gris ?

Singe en couleurs
Singe en couleurs
Singe monochrome
Singe gris

Indication : il faut remplacer chaque tuple de valeurs (R,V,B) par un nombre égal à la moyenne de ces trois valeurs.

Lien vers les RÉPONSES