Projet steganographie : Tampon d'image

Objectif.

Le tampon d'image consiste à cacher une image dans une autre, l'idée est basée sur le fait que l'être humain (et les périphériques de l'ordinateur) a du mal à percevoir les petites nuances de couleurs.

Pixel de l'image publique

Pixel de l'image privée

Pixel de l'image tampon

Pixel de l'image cachee

Nombre de bits de poids fort de l'image à cacher à prendre :

Sur un exemple :

Dans un premier temps nous allons construire une fonction qui va pour chaque pixel ôter n bits de poids faibles, et voir le peu d'influence si n est petit, puis nous allons faire une fonction qui mélangera deux images en ajoutant une pondération (cette fonction va faire le tampon) et enfin créer une fonction qui va récupérer l'image cachée.

Quelle image est cachée dans l'image ci dessous ?

Bits de poids faibles.

On rappelle que par exemple le nombre 137 est stocké en mémoire dans l'octet 10001001.

Ôter le bit de poids faible consiste à mettre le dernier bit à 0 (s'il est déjà il n'y a rien à faire), on obtient alors 10001000 = 136, de même si on veut ôter 2 bits de poids faibles on doit mettre les deux derniers bits à 0 comme le deuxiéme était déjà à 0, on ne le change pas et on obtient également 10001000 =136.

Mathématiquement ôter n bits de poids faibles s’interprète comme une soustraction du reste de la division entière par \(2^n\). Si a est un entier entre 0 et 255 alors a-a%(2**n) est l'entier qui correspond avec n bits de poids faible en moins. Un autre moyen d'oter n bits de poids faibles d'un nombre a est de faire a//(2**n) * (2**n). Néanmoins par la suite on va décomposer un octet dans un tableau de bits, celà va être plus simple à comprendre.

Projet

Faire une fonction decimal_en_bits(n) qui prend un nombre décimal entre 0 et 255 et va retourner un tableau de 8 bits correspondant à sa décomposition en binaire. (voir cours pour se rapeller de l'algorithme). Par exemple decimal_en_bits(24) = [ 0, 0, 0, 1, 1, 0, 0, 0].

Projet

Faire une fonction bits_en_decimal(tableau) qui fait l'inverse de la fonction précédente, on lui donne un tableau de 0 ou 1 et elle retourne le décimal qui correspond, par exemple bits_en_decimal([0, 0, 1, 0, 1, 0, 0, 0]) = 40.

Projet

Faire une fonction poids_faibles_a_0(nb,n=1) où nb est un nombre décimal et n représente le nombre de bits de poids faible à mettre à 0 et qui va retourner un nombre qui correspond à nb privé de n bits de poids faible. Par exemple si nb = 220 = 110111002 alors :

Projet

Faire une fonction image_moins_poids_faibles(image,n=0), qui prend une EZ_image et qui retourne une EZ_image qui correspond à la transformation consistant à ôter n bits de poids faible à chaque couleur (pas à l'opacité par contre).

Constater qu'oter un ou deux bits ne change pas grand chose. Noubliez pas il faut d'abord charger une image avec EZ.charge_image puis lancer la fonction précédente et enfin sauvegarder la réponse avec le nom de votre choix avec EZ.sauvegarde_image(). Sauvegarder en BMP pour ne pas avoir de pertes.

Comme les bits de poids faibles n'ont pas une grosse influence sur nos yeux, on va les utiliser pour cacher une autre information. Les techniques sont nombreuses

Pour la suite essayer de prendre deux images de la même dimension, une image dite publique qui va contenir l'image que l'on va montrer et une image dite privée qui sera cachée dedans.

Projet

Faire une fonction conserve_poids_forts(nb,n=1) qui a un nombre nb entre 0 et 255 va donner le nombre qui correspond en ne conservant que les n bits de poids forts Par exemple si nb = 220 = 110111002 alors :

Projet

Faire une fonction melange(publique,privée,nb_bits), qui va prendre deux images publique et privée et qui va retourner une image de même dimension que publique et qui va avoir pour chaque pixel les couleurs correspondantes de publique ôtées des nb_bits bits de poids faibles et ajoutée des nb_bits bits de poids forts de l'image privée.

+=

Maintenant que l'image est cachée, on va la remontrer. (bien sur elle va perdre en détail)

Exercices

Faire une fonction prend_poids_faibles(nb,n=1) qui a un nombre nb entre 0 et 255 va donner le nombre qui correspond à ses n bits de poids faibles. Par exemple si nb = 220 = 110111002 alors :

Projet

Faire une fonction faible_en_fort(nb,n=1) qui va prendre un nombre n et retourner le nombre dont les n bits de poids forts sont égaux aux n bits de poids faibles du nombre d'origine (le reste des bits étant à 0). Par exemple avec 220 = 110111002 :

Vous pouvez soit utiliser la fonction précédente et multiplier par une puissance de 2 ou travailler à partir d'un tableau de bits.

Projet

Faire une fonction montre_cachee(image,nb_bits) qui va retourner l'image cachée contenu dans l'image.

L'image mélangée doit être sauvegardée en BMP car la compression est trop destructive, il existe cependant des techniques de tampon numérique qui résistent à la compression.

Aller plus loin

Projet
  1. Si une image est en noire et blanc que dire du niveau de rouge, de bleur et de vert ?
  2. Que se passe t'il si on veut cacher une image en noir et blanc dans les 2 bits de poids faibles et que l'on décache l'image ? A t'on \(2^2×2^2×2^2 = 64\) couleurs ? Expliquer.
  3. On va faire mieux et stocker le niveau de gris de chaque pixel, pour cela on va utiliser les deux bits de poids faibles du rouge, et les trois du vert et du bleu, on aura donc 8 bits et l'image en noir et blanc sera cachée sans perte ! L'idée pour chaque pixel est la suivante : On prend le niveau de gris de l'image cachée (8bits) et on stocke les deux bits de poids fort dans le rouge, les trois bits suivants dans le vert et les derniers dans le bleu.

  4. Couleur image publique :

    Niveau gris :

    donne :
  5. Faire une fonction qui redonne l'image cachée par la méthode précédente et voir l'image cachée dans le ponton de la page.