TP2 - Stéganographie ¶
import copy as cp
import numpy as np
import pylab as pb
from skimage import io
Algorithme pour dissimuler un texte dans une image¶
Dans une image en couleurs (tableau 3D), chaque pixel est représenté par un tableau 1D de 3 entiers compris entre 0 et 255 (niveaux de rouge, vert et bleu). Or, la modification du bit de poids faible (le dernier) pour un niveau de couleur change très peu cette couleur. On peut donc modifier tous ces bits dans une image, sans trop changer son apparence, pour y cacher de l’information comme un texte.
Plus précisément, on utilisera un niveau de couleur (trois disponibles par pixel dans une image en couleurs) pour cacher un bit suivant le principe de codage suivant :
- si le niveau de couleur est pair (dernier bit égal à 0), alors
- on conserve sa valeur pour y cacher le bit 0
- on lui ajoute 1 pour y cacher le bit 1
- si le niveau de couleur est impair (dernier bit égal à 1), alors
- on conserve sa valeur pour y cacher le bit 1
- on lui ajoute 1 pour y cacher le bit 0
Ainsi, un niveau de couleur codé fournit le bit 0 s’il est pair et le bit 1 s’il est impair. Le décodage (récupération de l’information cachée) est alors assuré par un simple test de parité.
Remarque : si le niveau de couleur est égal à 255, on ne peut lui ajouter 1. On réalisera donc un prétraitement de l’image pour transformer tous les 255 en 254.
Exemple : le tableau suivant réalise le codage et le décodage du 100ième caractère dans le code ASCII à savoir la lettre « d » : 01100100. Huit niveaux de couleurs sont alors nécessaires pour cacher les huit bits en question.
Objectif et décomposition en sous-problèmes¶
On veut construire :
- une fonction de codage qui permet de cacher un texte dans une image en couleurs (suffisamment grande)
- une fonction de décodage qui, étant donnée une image codée, permet de récupérer le texte caché connaissant sa longueur
Pour les tests durant la phase de construction, on utilisera :
- l’image en couleurs contenue dans la variable imgTest
- la chaine de caractères 'Info'
imgTest = np.array([[[255,255,253],[145,10,65],[32,255,40]],
[[110,55,53],[65,50,5],[132,200,140]],
[[255,255,253],[145,0,65],[32,255,40]],
[[110,55,53],[65,50,5],[132,200,140]]])
pb.imshow(imgTest, interpolation='none')
pb.show()
Pour le test final, on utilisera les éléments suivants disponibles sur Moodle :
- l’image en couleurs joconde.png
- le texte (composé de caractères ASCII) contenu dans le fichier texte.rtf
Questions préliminaires¶
- Déterminer le nombre maximal de caractères qu’il est possible de cacher dans l’image :
- imgTest
- joconde.png
Réponse
- Déterminer le nombre de caractères (à cacher) contenus dans :
- la chaine 'Info'
- le fichier texte.rtf
Réponse
Préparation de l'image¶
Déclarer une fonction prepa(img) définie de la manière suivante :
- entrée : une image en couleurs (tableau 3D)
- sortie : l’image aplatie et prétraitée (tableau 1D sans 255)
*Pour l'aplatissement, on pourra utiliser la méthode **.flatten()***
# Réponse
# Test
prepa(imgTest)
Codage et décodage d'un caractère¶
- Déclarer une fonction codageCar(lst8, car) définie de la manière suivante :
- entrées : une liste de 8 niveaux de couleurs, et un caractère
- sortie : la liste des 8 niveaux de couleurs codés
# Fonction intermédiaire
def decToBin(entier) :
"""Fournit la liste des 8 bits correspondant à l'écriture binaire de l'entier <= 255"""
lst = []
q, r = entier, 0
for i in range(8) :
q, r = divmod(q, 2)
lst = [r] + lst
return(lst)
# Test
# la fonction prédéfinie ord(car) fournit le code ASCII décimal du caractère car
print(ord('I'))
# la fonction prédéfinie bin(n) fournit l'écriture binaire de l'entier n
print(bin(ord('I')))
# notre fonction renvoie toujours un octet (sous forme de liste)
print(decToBin(ord('I')))
# Réponse
# Test
codageCar([254, 254, 253, 145, 10, 65, 32, 254], 'I')
Déclarer une fonction decodageCar(lst8Cod) définie de la manière suivante :
- entrée : une liste de 8 niveaux de couleurs codés
- sortie : le caractère caché
On pourra utiliser la fonction prédéfinie chr qui transforme le code ASCII décimal en caractère.
# Réponse
# Test
decodageCar([254, 255, 254, 146, 11, 66, 32, 255])
Codage et décodage d'un texte¶
- Déclarer une fonction codage(img, ch) définie de la manière suivante :
- entrées : une image en couleurs et une chaîne de caractères
- sortie : l'image codée dissimulant le texte
# Réponse
# Test
ch = 'Info'
imgTestCod = codage(imgTest, ch)
print('Première ligne de imgTest :\n', imgTest[0], '\n')
print('Première ligne de imgTestCod :\n', imgTestCod[0], '\n')
pb.subplot(1,2,1)
pb.title('Image initiale')
pb.imshow(imgTest, interpolation='none')
pb.subplot(1,2,2)
pb.title('Image codée')
pb.imshow(imgTestCod, interpolation='none')
pb.show()
- Déclarer une fonction decodage(imgCod, long) définie de la manière suivante :
- entrées : une image codée et la longueur du texte dissimulé
- sortie : le texte
# Réponse
# Test
long = 4
print(decodage(imgTestCod, long))
Test final¶
On commence par importer l'image que l'on souhaite utiliser pour dissimuler le texte.
imgTest = io.imread('joconde.png')
pb.imshow(imgTest, interpolation='none')
pb.show()
- Représenter, dans une seule fenêtre, l’image initiale joconde.png et l’image codée (contenant le texte de secret.txt).
# Réponse
- Récupérer et afficher le texte caché dans l’image codée.
# Réponse