TP2 - Stéganographie
¶

A. Ridard
In [ ]:
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.

No description has been provided for this image

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'
In [ ]:
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¶

  1. Déterminer le nombre maximal de caractères qu’il est possible de cacher dans l’image :
    • imgTest
    • joconde.png

Réponse

  1. Déterminer le nombre de caractères (à cacher) contenus dans :
    • la chaine 'Info'
    • le fichier texte.rtf

Réponse

Préparation de l'image¶

  1. 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()***

In [ ]:
# Réponse
In [ ]:
# Test

prepa(imgTest)

Codage et décodage d'un caractère¶

  1. 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
In [ ]:
# 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)
In [ ]:
# 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')))
In [ ]:
# Réponse
In [ ]:
# Test

codageCar([254, 254, 253, 145,  10,  65,  32, 254], 'I')
  1. 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.

In [ ]:
# Réponse
In [ ]:
# Test

decodageCar([254, 255, 254, 146, 11, 66, 32, 255])

Codage et décodage d'un texte¶

  1. 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
In [ ]:
# Réponse
In [ ]:
# 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()
  1. 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
In [ ]:
# Réponse
In [ ]:
# Test

long = 4
print(decodage(imgTestCod, long))

Test final¶

On commence par importer l'image que l'on souhaite utiliser pour dissimuler le texte.

In [ ]:
imgTest = io.imread('joconde.png')

pb.imshow(imgTest, interpolation='none')
pb.show()
  1. Représenter, dans une seule fenêtre, l’image initiale joconde.png et l’image codée (contenant le texte de secret.txt).
In [ ]:
# Réponse
  1. Récupérer et afficher le texte caché dans l’image codée.
In [ ]:
# Réponse