Python_14_GestionDes..

publicité
Python 14 Gestion des images
Gestion des images
1
Introduction
Problème : Un ordinateur traite de l’information sous forme numérique binaire.
Comment coder les images à l’aide de codes binaires ?
Il existe deux modes de codage d’une image numérique :
- Le mode matriciel (« bitmap ») : il repose sur le principe d’une grille de pixels,
- Le mode vectoriel (« vector ») : on décrit les propriétés mathématiques des formes
de l’image.
Une image vectorielle peut être zoomée sans que cela n’altère la qualité
du rendu. Ce mode est adapté aux formes et images qui ne sont pas
trop complexes : logos, typographie, plans, cartes, etc. Les formats de
fichiers vectoriels sont PostScript, PDF, SVG, etc.
Le nombre de pixels utilisés par unité de longueur donne un rendu plus
ou moins précis des formes de l’image. Un zoom trop important fait
apparaître la pixellisation de l’image. Les formats de fichiers matriciels
sont BMP, GIF, PNG, JPEG, etc.
On s’intéresse par la suite au codage des images par le mode matriciel.
2
Notions de colorimétrie
Problème : Comment coder les couleurs à l’aide de codes binaires ?
La synthèse additive est utilisée par les moniteurs et les projecteurs. Elle est constituée des trois lumières de
base qui sont le Rouge, le Vert et le Bleu (RVB). Les couleurs secondaires sont plus claires que les primaires,
c’est pour cela que leur synthèse est appelée additive.
La synthèse soustractive est utilisée dans l’imprimerie et par les imprimantes. Les couleurs primaires sont
le Cyan, le Magenta, le Jaune et le Noir (CMJN). Si on mélange deux couleurs primaires, le résultat sera une
couleur secondaire plus sombre qui absorbera donc plus de lumière, c’est pour cette raison que cette synthèse
est nommée soustractive.
Cours Info
- Jacques Delfaud -
Page 1 sur 11
Python 14 Gestion des images
Un modèle de colorimétrie est une manière de coder des couleurs avec des nombres.
Le modèle Lab caractérise une couleur avec :
- un paramètre d’intensité correspondant à la luminance : la combinaison L*
est la clarté, elle va de 0% (noir) à 100% (blanc),
- deux paramètres de chrominance qui décrivent la couleur : la composante a*
représente la gamme de l’axe du vert (-128) au rouge (+128). La composante
b* représente la gamme de l’axe du bleu (-128) au jaune (+128). Ce modèle
est proche de la vision humaine.
Le modèle RVB caractérise une couleur à l’aide de trois paramètres
(chacun sur un octet, soit un nombre de 0 à 255) correspondant aux
trois couleurs Rouge, Vert et Bleu.
00 00 00)(16) = (0,0,0) = noir
FF FF FF)(16) = (255,255,255) = blanc
FF 00 00)(16) = (255,0,0) = rouge
3
Palette
« Paint Shop »
Le mode matriciel « bitmap »
Une matrice de pixels (« picture elements ») est constituée d’un ensemble de points pour former une image. Le
pixel représente ainsi le plus petit élément constitutif d’une image numérique.
- Formats limités à 256 couleurs : GIF, PCX, PGM, etc.
- Formats acceptant différentes quantifications BMP, TIFF, TGA, PNG, etc.
- Formats limités à 16 millions de couleurs JPEG, etc.
Les images peuvent facilement être créées et stockées dans un tableau de pixels, la lecture et l’écriture d’un
pixel sont aisées.
Par contre, les fichiers peuvent être très gros (nécessité de compression).
De plus, il y a des problèmes de changement d’échelle (apparition d’effets de marches d’escalier ou de flou avec
interpolation). Enfin, les dimensions de l’image doivent être prévues pour la résolution de l’interface de sortie
(écran, imprimante).
La discrétisation d’une image se caractérise par sa définition, c’est-à-dire le nombre
de pixels utilisés.
La résolution de l’image établit un lien entre le nombre de pixels d’une image et sa
taille réelle. Elle se caractérise par un nombre de pixels par unité de longueur.
La quantification des couleurs est exprimée en bits par pixel (bpp) :
- 1 (deux couleurs : noir et blanc par exemple),
- 8 (niveaux de gris entre 0 et 255 par exemple, 256 couleurs),
- 16 bits, etc.
Cours Info
- Jacques Delfaud -
Page 2 sur 11
Python 14 Gestion des images
Exemple 1 :
- « 800 × 600 » signifie une largeur de 800 et une hauteur de 600 pixels.
- « 600 dpi » (« ppp » : point par pouce, « dpi » : dots per inch) signifie 600 pixels par pouce
(1 pouce = 25,4 mm).
En connaissant le nombre de pixels d’une image et la mémoire nécessaire à l’affichage d’un pixel, il est alors
possible de définir exactement la taille qu’occupe le fichier.
Une définition du type 800 × 600 avec un codage sur 24 bits (3 octets) des couleurs, donne un fichier image de
taille 1,44 Mo.
La couleur peut être codée directement dans le pixel, ou
dans une palette.
L’organisation d’un fichier bitmap est donnée ci-contre.
4
En-tête (« header »)
Identificateur du format
Largeur, hauteur, nombre de couleurs, etc.
Palette de couleur (éventuellement)
Données d’image
Suite de pixels éventuellement compressés
Le format BMP
Cours Info
- Jacques Delfaud -
Page 3 sur 11
Python 14 Gestion des images
Exemple en 24 bit :
Cours Info
- Jacques Delfaud -
Page 4 sur 11
Python 14 Gestion des images
Exemple en 8 bit :
Exemple 2 : Inversion des couleurs d’une image
Inverser les couleurs d’une image ayant deux couleurs « noir » et « blanc » revient à changer les pixels noirs
en blancs et inversement.
Pour le modèle RVB, cela revient à changer chaque « valeur initiale » R, V et B en « 255 – valeur initiale ».
Cours Info
- Jacques Delfaud -
Page 5 sur 11
Python 14 Gestion des images
Algorithme 1 Inversion des couleurs d’une image BMP codée en 24 bits
Données : T[1..n] : le tableau des n octets du fichier image
Résultat : le tableau T avec les couleurs de chaque pixel inversées
Pour i de 55 à n faire
T[i][j] ← 255 - T[i][j]
Fin Pour
// on démarre après les entêtes du fichier et du bitmap
Algorithme 2 Inversion au dessus de la diagonale des couleurs d’une image BMP codée en 24 bits
Données : T[1..n] : le tableau des n octets du fichier image
L, H : largeur et hauteur de l’image
Résultat : le tableau T avec les couleurs de chaque pixel situés au dessus de la diagonale inversées
Si L mod 4 <> 0 alors
x←L + 4 - L mod 4
// Chaque ligne comporte un nombre d’octets multiple de 4
Sinon
x←L
Fin Si
Pour i de 55 à n faire
// on démarre après les entêtes du fichier et du bitmap
y← ( i – 55 ) div 3
// y mod x est la colonne du pixel
Si (y mod x) < (y div x)*L/H alors
// y div x est la ligne du pixel
T[i][j] ← 255 – T[i][j]
Fin Si
Fin Pour
5
AImage 3×3
image inversée
image avec inversion au dessus de la diagonale
Image 1600 ×1200
image inversée
image avec inversion au dessus de la diagonale
La compression des images « bitmap »
Certains formats de fichiers « bitmap » autorisent la compression des données.
Celle-ci peut se faire sans pertes (compression RLE, LZW, Huffman) ou avec pertes (compression JPEG).
On définit le facteur de compression comme le rapport entre la taille du fichier initial et la taille du fichier
compressé.
Cours Info
- Jacques Delfaud -
Page 6 sur 11
Python 14 Gestion des images
Les méthodes RLE, LZW et Huffman, sont utilisées pour d’autres codages que celui des images.
Le format BMP autorise des compressions de type RLE, LZW ou JPEG.
Les formats TIFF, PNG et GIF utilise la compression LZW.
Méthode à base de redondances : la compression RLE (Run-lenght encoding)
Un encodage RLE consiste à indiquer pour chaque suite de pixels d’une même couleur, le nombre de pixels de
cette séquence. Le résultat comporte en général moins de caractères, bien que ça ne soit pas une obligation.
Le format BMP permet d’utiliser la compression RLE pour les images en 1, 4 et 8 bits/pixel.
Plus le nombre de couleurs est important, moins nombreuses sont les chances de redondance. La méthode est
donc particulièrement intéressante pour les images en deux couleurs (noir et blanc).
Par exemple, la liste « 0 0 0 0 F F 0 0 0 0 0 0 F F F F », peut-être encodée comme suit :
« 4 0 2 F 6 0 4 F ».
Si chaque caractère est codé sur 8 bits, la chaîne initiale fait 16×8=128 bits.
La chaîne encodée fait 8×8=64 bits.
Algorithme 3 Compression RLE
Données : T[1..n] : un tableau de n caractères
Résultat : le tableau L encodant la liste de caractères du tableau T selon la méthode RLE
Compression_RLE(T)
i←1
L←[]
Tant que i<=n faire
c←T[i]
k←1
Tant que i+k<=n ∧ T[i+k]==c faire
k←k+1
Fin Tant que
L←L + [k]
L←L + [c]
i← i + k
Fin Tant que
Retourner L
Méthode à base de dictionnaire : La compression LZW (Lempel Ziv Welch)
Le principe général est de :
- trouver des séquences de pixels qui se répètent,
- construire un dictionnaire associant un code unique à chaque séquence,
- remplacer la séquence de pixels par le code.
Plus le nombre de couleurs est important, moins il est probable que des séquences se répètent.
La méthode n’est donc pas appliquée lorsque le nombre de couleurs est élevé.
Initialement, le dictionnaire comprend tous les caractères de la table ASCII. Les index de 0 à 255 sont donc
occupés. Le dictionnaire est ensuite complété lorsque des suites nouvelles de caractères apparaissent.
Au fur et à mesure que la taille du dictionnaire augmente, il faut augmenter le nombre de bits nécessaires au
codage des éléments. Au delà du 255e , 511e indice, etc., il rajouter un bit.
Par contre, le dictionnaire est reconstruit à partir du fichier compressé, il n’est pas nécessaire de le joindre à ce
dernier.
NOTA : Dans l’algorithme en page suivante, le dictionnaire est une liste de chaînes de caractères. Les fonctions
Est_dans_dictionnaire() et Ajouter_dans_dictionnaire() ne sont pas détaillées.
Cours Info
- Jacques Delfaud -
Page 7 sur 11
Python 14 Gestion des images
Algorithme 4 Compression LZW
Données : T[1..n] : un tableau de n caractères
Résultat : le tableau L encodant la liste de caractères du tableau T selon la méthode LZW
Compression_LZW(T)
i←1
L←[ ]
x←" "
Tant que i<=n+1 faire
Si i<n alors
Si Est_dans_dictionnaire(x+T[i]) alors
x←x + T[i]
Sinon
Ajouter_dans_dictionnaire(x+T[i])
L← L + x
x←T[i]
Fin Si
Sinon
// i=n
L← L + x
Fin Si
i←i+1
Fin Tant que
Retourner L
Par exemple la chaîne « 0 0 0 0 F F 0 0 0 0 0 0 F F F F », peut-être encodée comme suit :
i
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
x
0
0
00
0
F
F
0
00
000
0
00
000
F
FF
F
FF
T[i]
0
0
0
0
F
F
0
0
0
0
0
0
F
F
F
F
x+T[i]
0
00
00
000
0F
FF
F0
00
000
0000
00
000
000F
FF
FFF
FF
Ajout dans L
Ajout dans dictionnaire
0
<256> = 00
<256>
0
F
F
<257> = 000
<258> = 0F
<259> = FF
<260> = F0
<257>
<261> = 0000
<257>
<262> = 000F
<259>
<263> = FFF
<259>
Chaîne encodée : « 0 <256> 0 F F <257> <257> <259> <259> ».
Chaque caractère de la chaîne encodée est codé sur 9 bits (il faut aller au delà de 256 valeurs distinctes).
Celle-ci fait donc 9×9=81 bits.
Méthode statistique : La méthode de Huffman
Exemple : Coder 4000 caractères de 6 valeurs différentes
En ASCII, cela nécessite 8×4000 = 32000 bits.
En limitant le codage à 3 bits/caractère, il faut 3×4000 = 12000 bits.
Facteur de compression : 2,6.
Peut-on faire encore mieux ?
Cours Info
- Jacques Delfaud -
Page 8 sur 11
Python 14 Gestion des images
Par exemple si la répartition des caractères est connue (voir tableau) :
Il faut alors 3×800+3×400+3×400+4×200+1×2000+4×200 = 8400 bits.
Facteur de compression : 3,8.
Caractère n◦
Fréquence (%)
Codage binaire de longueur fixe
Codage "préfixe" de longueur variable
1
20
000
111
2
10
001
101
3
10
010
100
4
5
011
1101
5
50
100
0
6
5
101
1100
Certaines couleurs de pixels reviennent plus souvent que d’autres.
L’idée est de réduire le nombre de bits utilisés pour le codage des pixels les plus fréquents et d’augmenter ce
nombre pour les pixels plus rares. On utilise alors un codage de taille variable.
Par contre, il faut utiliser un codage "préfixe", c’est à dire tel qu’un mot du code n’est pas le préfixe d’un
autre mot. On peut alors lire une séquence codée sans ambiguïtés.
Problème : Comment déterminer le codage de longueur variable optimal ?
Pour représenter un codage préfixe, on utilise un arbre :
- Les feuilles sont les caractères,
- Les branches sont "0" (fils gauche) ou "1" (fils droit),
- Chaque nœud interne contient la somme des poids de ses fils,
- Chaque mot de code est donc un chemin de la racine vers une feuille contenant le caractère codé.
Dans l’exemple de gauche, le caractère 1 est codé « 000 ». Dans l’exemple de droite, il est codé « 111 ».
Dans l’exemple de gauche, le caractère 5 est codé « 10 ». Dans l’exemple de droite, il est codé « 0 ».
L’algorithme de Huffman permet de construire l’arbre optimal, permettant d’obtenir l’encodage le plus efficace, c’est à dire minimisant la taille du fichier compressé.
Chaque nœud est un objet contenant :
- le fils gauche,
- le fils droit,
- la somme de la fréquence de ses fils.
Cours Info
Objet
« nœud »
- Jacques Delfaud -
Fils gauche (nœud)
Fils droit (nœud)
Fréquence (réel)
Page 9 sur 11
Python 14 Gestion des images
Soit un ensemble E de n caractères « c » dont la fréquence d’apparition est définie par f(c).
Les feuilles de l’arbre sont les caractères. Ils peuvent être modélisés comme des nœuds qui ont une fréquence,
mais pas de fils droit ou gauche (sous-arbres vides).
Le principe est alors le suivant :
- on construit l’arbre du bas vers le haut,
- on commence avec n feuilles et on effectue n-1 fusions.
La fusion s’effectue sur les objets les moins fréquents.
Algorithme 5 Algorithme de Huffman
Données : T : la liste des n caractères c (de type nœud)
Résultat : le nœud racine de l’arbre de Huffman avec tous ses fils ordonnés de façon optimale
Arbre_Huffman(E)
F ←T // F contient tous les caractères
Pour i de 1 à n-1 faire
z ← CreerNoeud()
// z est un objet de type « nœud »
z.gauche ← ExtraireMin(F)
// la fonction retourne le nœud de fréquence minimale
z.droit ← ExtraireMin(F)
// il est supprimé de la liste F (deux nœuds supprimés en tout)
z.frequence ← z.gauche.frequence + z.droit.frequence
Inserer(F,z)
// On insère le nouveau nœud dans la liste F
Fin Pour
// A chaque itération, la liste F perd un élément.
Retourner ExtraireMin(F)
// On retourne le seul nœud restant,
// c’est à dire le dernier créé (de fréquence 100)
NOTA : Les arbres sont implémentés par des listes chaînées (files)
Comme les compressions RLE et LZW, cette méthode est inefficace lorsque le nombre de couleurs devient trop
important. Toutes ces méthodes de compression sans pertes sont applicables pour des pixels, des chaînes de
caractères et autres données informatiques.
La compression avec pertes JPEG
Pour des nombres de couleurs important (supérieur à 256), on utilise des méthodes de compression avec pertes,
et notamment le format JPEG.
Ce dernier utilise plusieurs techniques de compression sans pertes, mais aussi des méthodes permettant de réduire la taille de l’image en utilisant des propriétés de la vision humaine.
Les étapes de la compression JPEG sont les suivantes :
- Ré-échantillonnage de la chrominance, car l’œil ne peut discerner de différences de chrominance au sein d’un
carré de 2×2 pixels,
- Découpage de l’image en blocs de 8×8 pixels, puis application de la fonction DCT (transformation discrète en
cosinus) qui décompose l’image en somme de fréquences,
- Quantification de chaque bloc, c’est-à-dire application d’un coefficient de perte (fonction du ratio taille/qualité)
qui annule ou diminue des valeurs de hautes fréquences, afin d’atténuer les détails en parcourant le bloc intelligemment avec un codage RLE (en zig-zag pour enlever un maximum de valeurs nulles).
- Encodage de l’image puis compression avec la méthode d’Huffman.
NOTA : On utilise aussi des méthodes de compression avec pertes dans les fichiers vidéo et audio.
Cours Info
- Jacques Delfaud -
Page 10 sur 11
Python 14 Gestion des images
6
Syntaxe Python
Exemple :
import imageio
im = imageio.imread("C :/Documents and Settings/Python/Gestion_Images/TestPython.bmp")
# La taille de l’image est accessible dans le triplet (largeur, hauteur, nb composantes) suivant :
print(im.shape)
# On peut alors connaître le triplet de couleur du pixel (0,0) (coin supérieur gauche)
print(im[0,0])
# On peut changer la couleur d’un point en donnant 3 composantes RGB :
im[0,0] = (255, 0, 0)
# On peut modifier simplement une composante :
im[0,1][0] = 0 # on enlève le rouge
# Puis on peut sauvegarder l’image résultante
imageio.imsave("C :/Documents and Settings/Python/Gestion_Images/TestPythonBis.bmp", im)
# Pour visualiser l’image obtenue :
import matplotlib.pyplot as plt
im = imageio.imread("C :/Documents and Settings/Python/Gestion_Images/TestPython.bmp")
plt.imshow(im)
plt.show()
Les deux print nous donnerons :
(392, 533, 3)
[255, 255, 255]
Et l’image suivante apparaitra :
Cours Info
- Jacques Delfaud -
Page 11 sur 11
Téléchargement