Un image numérique est stocké dans l'ordinateur sous forme d'un tableau (matrice), les
éléments de ce
tableau sont appelés
Si $T$ est le tableau représentant l'image numérique, on note $Nl$ le nombre de lignes dans ce
tableau et $Nc$ le
nombre de colonnes, alors le tableau contient $Nl\times Nc$ pixels. On parle alors de la
Pour les image en niveau de gris, chaque pixel de l'image est un entier entre $0$ et $255$, ce qui
fait $256$
possibilités pour un pixel.
La valeur 0 correspond au noir, et la valeur 255 correspond au blanc.
Les valeurs intermédiaires correspondent à des niveaux de gris allant du noir au blanc.
Calculer l'espace nécessaire sur le disque dure de l'ordinateur pour stocker une image de taille $Nc\times Nl$ pixels.
Chacune de ces trois images s'appelle un canal. Cette représentation en rouge, vert et bleu mime le
fonctionnement du système visuel
humain.
Chaque pixel de l'image couleur contient ainsi trois nombres (r,v,b), chacun étant un nombre entier
entre 0 et 255. Si le pixel est
égal à (255,0,0), il ne contient que de l'information rouge,
et est affiché comme du rouge. De façon similaire, les pixels valant (0,255,0) et (0,0,255) sont
respectivement affichés vert et bleu.
On peut afficher à l'écran une image couleur à partir de ses trois canaux en utilisant les règles
de la synthèse additive des couleurs. La figure ci-contre montre les règles de composition cette
synthèse
additive des couleurs. Un pixel avec les valeurs (255,0,255) est un mélange de rouge et
de vert, il est ainsi affiché comme jaune.
La figure ci-après montre la décomposition d'une image couleur en ses trois canaux constitutifs.
|
$\quad$ |
|
$\quad$ | ||
|
|
On peut faire de traitement d'image avec Python, pour cela il faut charger la bibliothèque PIL (Python Imaging Library), qui permet d'avoir des fonctions supplémentaire et rendre le travail plus facile.
Pour créer une image avec Python on utilise la fonction
La fonction
L'exemple suivant montre comment on crée une image en niveau de gris,
from math import *
from PIL import Image
im = Image.new("L",(40,40)) # dimension de l'image
im.putpixel((20,20),255) # changer la couleur d'un pixel
im.show()
for i in range(10,31):
im.putpixel((i,10),255) # travailler sur une ligne
im.show() # visualiser l'image
im.save("im1.jpg") # sauvegarder la nouvelle image
Et voici le résultat ce premier essais
Le code suivant permet de créer une image en couleur, puis changer les couleur de l'image pixel par pixel
from PIL import Image
im = Image.new("RGB",(100,100)) # image en couleur
for j in range(100): # j parcourt les colonnes
for i in range(100): # i parcourt les lignes
im.putpixel((j,i),(255-i,255+j,i+j)) # mettre des couleurs
im.show()
im.save("im2.jpg") # sauvegarder la nouvelle image
Et voici le résultat ce deuxième essais
En s'inspirant des exemples ci-dessus, créer une image en couleur qui contient un rectangle et un triangle comme ci-après.
La fonction
La fonction
from PIL import Image
im = Image.open("ImC4.png")
# L'image doit être dans le même répertoire que le fichier python
NbC,NbL = im.size
print("Les dimension de l'image sont %d %d"%(NbC,NbL))
p = im.getpixel((1,1))
print(p[0],p[1],p[2])
im2 = Image.new('RGB',(NbC,NbL))
# nouveau image de même dimension que l'image ouverte
for j in range(NbC):
for i in range(NbL):
p = im.getpixel((j,i))
im2.putpixel((j,i),(255-p[0],255-p[1],255-p[2]))
im2.show()
im2.save("ImC4modifie.png")
Voici le résultat,
|
$\quad$ |
|
$\quad$ |
Copier l'image ImC4.png dans votre répertoire. A l'aide de
la fonction
Couper l'image ImC4.png en quatre images de dimensions identiques.
En utilisant la fonction
A partir d'une image en couleur (chaque pixel est représenté par 3 valeurs [r,g,b]), on peut créer
une image en
niveau de gris.
Pour cela, chaque pixel dans la nouvelle image est calculé en moyennant les trois valeurs de même
pixel dans l'image couleur.
from PIL import Image
im= Image.open("Grenade02.jpg")
L,H = im.size
# Création d'une nouvelle image
#(de même dimension)
imG = Image.new("L",(L,H))
for y in range(H):
for x in range(L):
p = im.getpixel((x,y))
# triplet pour chaque pixel
a = (p[0]+p[1]+p[2])//3
# moyenner les trois valeurs
imG.putpixel((x,y),a)
imG.save("GR_GRIS_G.png")
imG.show()
|
$\quad$ |
|
$\quad$ |
Le seuillage pour une image en niveau de gris consiste à mettre en 0 (donc noir) tout les pixels ayant un niveau de gris inférieur à une certaine valeur. Le seuillage permet de mettre en évidence des formes ou des objets dans une image.
|
$\quad$ |
|
$\quad$ |
|
|
$\quad$ |
|
$\quad$ |
|
On cherche à modifier une image en niveau de gris, de sorte que:
Chercher une fonction $f$ répondant à cette demande puis écrire le programme.
La détection de contours permet de repérer les pixels de l'image qui correspondent à une variation
importante de
l'intensité lumineuse.
Le but alors est de transformer une image en niveau de gris en une nouvelle image dans laquelle les
contours apparaissent
(par convention en blanc sur fond noir).
Ceci est très utile car il permet de détecter les formes, objets,.. dans une image.
from tkinter import *
from tkinter.messagebox import *
from tkinter.colorchooser import *
from tkinter.filedialog import *
from PIL import Image
from os import path, system
result = askopenfilename(title="Ouvrir une image :",
filetypes=(("Image", "*.png"),("Tout fichier", "*")))
im1= Image.open(result)
im1.show()
L,H =im1.size
im2 = Image.new("L",(L,H))
im3 = Image.new("L",(L,H))
for y in range(1,H-1):
for x in range(1,L-1):
pix0 = im1.getpixel((x,y)) # stockage du pixel courant
pix1 = im1.getpixel((x-1,y-1)) # de son voisin en haut à gauche
pix2 = im1.getpixel((x,y-1)) # de celui du dessus
pix3 = im1.getpixel((x+1,y-1)) # d'en haut à droite
pix4 = im1.getpixel((x-1,y)) # de gauche
pix5 = im1.getpixel((x+1,y)) # de droite
pix6 = im1.getpixel((x-1,y+1)) # d'en bas à gauche
pix7 = im1.getpixel((x,y+1)) # d'en-dessous
pix8 = im1.getpixel((x+1,y+1)) # d'en bas à droite
r = 8*pix0-pix1-pix2-pix3-pix4-pix5-pix6-pix7-pix8
# on applique le filtre sur la composante rouge du pixel courant,
s = r
#méthode 1 :
#On décale de 128 et on réalise une inversion ("négatif")
r = r+128
r = int(255-r)
im2.putpixel((x,y),r)
#méthode 2 :
#On s'assure que s entre 0 et 255 et on réalise une inversion ("négatif")
if s < 0: s = 0
if s > 255: s = 255
s = 255-s
im3.putpixel((x,y),s)
im2.save("CE_Contour1.png")
im3.save("CE_Contour2.png")
|
$\quad$ |
|
$\quad$ |
|
Ainsi, la
Cependant il est nécessaire que cette dissimulation s'effectue sans trop dégrader la qualité de
cette deuxième image afin de ne pas
éveiller de soupçons.
Dès lors en considérant les composantes rouge, verte et bleue des pixels d'une image au format .PNG,
on remarque que chacune de ces
composantes est décrite à l'aide de huit bits. Par exemple, les huit bits de la composante verte
d'un pixel d'une image peut être 10101110;
ce nombre est en fait le code binaire du nombre 174 ; en effet :
$$ 1\times 2^7+0\times 2^6+1 \times 2^5+0 \times 2^4+1 \times 2^3+1 \times 2^2+1 \times 2^1+0 \times
2^0= 174.$$
Afin de dissimuler une information dans une image, il est possible de vérifier qu'en ignorant ou
modifiant les quatre bits de poids faible
des composantes verte, rouge et bleue de chaque pixel, c'est-à-dire ceux associés aux puissances de
deux les plus faibles, la qualité de
l'image n'est pas sévèrement altérée.
Ainsi, nous pouvons réduire sans perte majeur d'informations, les composantes verte, rouge et bleue
de chaque pixel d'une image
respectivement à leurs quatre premiers bits, appelés les quatre bits de poids fort.
Donc il est possible de dissimuler une première image dans une deuxième image, de même taille, en
remplaçant les quatre bits de poids
faible des composantes verte, rouge et bleue de chaque pixel de la deuxième image par,
respectivement, les quatre bits de poids fort des
composantes verte, rouge et bleue de chaque pixel de la première image.
Enfin pour dissimuler un texte dans une image, il suffit de coder un caractère de ce texte en code
ASCII (American Standard Code for
Information Interchange).
En effet, le code ASCII d'un caractère est un nombre compris entre 0 et 255. Or le code 255 est
associé au code binaire 11111111, et tous
les autres nombres compris entre 0 et 254 peuvent aussi s'écrire en base deux à l'aide de huit
chiffres.
Donc il est possible de dissimuler le caractère d'un texte dans une image, en remplaçant les quatre
bits de poids faible de la composante
verte par les quatre bits de poids fort du code binaire du code ASCII de ce caractère, et en
remplaçant les quatre bits de poids faible de
la composante rouge par les quatre bits de poids faible du code binaire du code ASCII de ce
caractère. Sachant cacher le caractère d'un
texte dans un pixel, il est dès lors possible de dissimuler un texte dans une image dont le nombre
de pixel est strictement plus grand que
la longueur de ce texte.
Ainsi pour cacher une image $A$ dans une image $B$ on travaille pixel par pixel. Pour chaque pixel,
on procède de la façon suivante :
i.e. Les 4 bits de poids fort de chaque composante (R,V,B) de l'image résultat sont les 4 bits
de poids fort de l'image $B$ et
les 4 bits de poids faible sont les 4 bits de poids fort de l'image $A$.
Inversement, pour trouver une image cachée dans une image donnée $C$, la démarche est très simple.
On travaille également pixel par pixel.
Pour chaque pixel de l'image $C$, et pour chaque composante (R,V,B) de ce pixel: on récupère les
bits de poids faible puis on les décale
à gauche, i.e. les 4 bits de poids faible de l'image $C$ deviennent les 4 bits de poids fort
de l'image résultat.
|
$\quad$ |
|
Et voici le résultat obtenu.
|
$\quad$ |
|
Et voici le résultat obtenu.
Écrire un programme en Python permettant de cacher une image dans une deuxième image (de même taille) et de chercher une image cachée dans une image.