PYTHON > traitement d’images avec Python

Le format PGM

PGM (portable graymap) : images en niveau de gris. Iimage matricielle, sans compression, assez peu utilisé mais facilement manipulable.

Conversion d'un JPEG en PGM avec le logiciel GIMP

image JPEG

Télécharger le fichier photo.jpg

Dans GIMP :

Ouvrir le fichier avec GIMP, puis :
Fichier → Enregistrer sous → Sélectionner le type de fichier → Image PGM
Exporter
Formatage des données → Brut
Enregistrer

Renommez ce fichier : image.pgm

Télécharger le fichier image.pgm

inversion de couleurs

inversion_image_pgm.py permet d'inverser les couleurs d'une image.
On obtient ainsi le "négatif" :

# script inversion_image_pgm.py
import imghdr, struct

print("Inversion d'une image PGM en mode binaire à 256 niveaux de gris\n")

NomFichierSource = 'image.pgm'
NomFichierDestination = 'imageInverse.pgm'

print('Fichier source :',NomFichierSource)
print('Fichier destination :',NomFichierDestination)

def Inversion(octet):
    # cette fonction fait une inversion du niveau de gris
    # 0 (noir)    -> 255 (blanc)
    # 255 (blanc) -> 0 (noir)
    return 255-octet

if imghdr.what(NomFichierSource)=='pgm':	# test du format de l'image
    FichierSource = open(NomFichierSource,'rb')
    TailleFichier = len(FichierSource.read())
    print('\nTaille du fichier (en octets) :',TailleFichier)

    Largeur = int(input('Largeur de l\'image (en pixels) ? '))
    Hauteur = int(input('Hauteur de l\'image (en pixels) ? '))
    NbPixel = Largeur*Hauteur

    TailleEntete = TailleFichier - Largeur*Hauteur

    FichierSource.seek(0)

    # extraction de l'en-tête
    # la variable Entete est une chaîne d'octets (type bytes)
    Entete = FichierSource.read(TailleEntete)

    # extraction des données
    # Data est une liste de nombre entiers (type list)
    # la fonction int() retourne le contenu d'un octet sous forme d'un entier
    
    Data = [int(i) for i in FichierSource.read()]	# compréhension de listes

    FichierSource.close()

    if NbPixel == len(Data):
        print('Nombre de pixels :',Largeur*Hauteur)
        print("Nombre d'octets de données :",len(Data))
        print("Taille de l'en-tête :",TailleEntete)

        FichierDestination = open(NomFichierDestination,'wb')
        # écriture de l'en-tête du fichier destination
        FichierDestination.write(Entete)

        # écriture des données du fichier destination
        for i in Data:
            # conversion de type : int en bytes            
            FichierDestination.write(struct.pack('B',Inversion(i)))

        FichierDestination.close()
        print('Travail terminé !')

    else:
        print('Erreur dans la saisie des données !')

else:
    print("Ce n'est pas une image PGM !")
>>>
Inversion d'une image PGM en mode binaire à 256 niveaux de gris

Fichier source : image.pgm
Fichier destination : imageInverse.pgm

Taille du fichier (en octets) : 153654
Largeur de l'image (en pixels) ? 480
Hauteur de l'image (en pixels) ? 320
Nombre de pixels : 153600
Nombre d'octets de données : 153600
Taille de l'en-tête : 54
Travail terminé !

Le script crée le fichier imageInverse.pgm dans le répertoire courant.

Affichons l'en-tête des fichiers image PGM :

>>> import binascii
>>> print(binascii.hexlify(Entete))	# contenu de l'en-tête en hexadécimal
b'50350a232043524541544f523a2047494d5020504e4d2046696c7465722056657273696f6e20312e310a343830203332300a3235350a'
>>> print(Entete)		# contenu de l'en-tête en chaîne de caractères
b'P5\n# CREATOR: GIMP PNM Filter Version 1.1\n480 320\n255\n'

L'en-tête contient en particulier la largeur et la hauteur de l'image (480 pixels x 320 pixels) et le nombre 255 (soit 256 niveaux de gris).

La couleur d'un pixel est codée sur un octet.
On va du noir (0x00) au blanc (0xff) en passant par tous les niveaux de gris.

>>> print(Data[0],hex(Data[0])) 	# premier octet : pixel en haut à gauche de l'image
153 0x99
>>> print(Data[1],hex(Data[1])) 	# deuxième octet : pixel à droite du précédent
142 0x8e
>>> print(hex(Data[479])) 	# 480ème octet : pixel en haut à droite
0xbf
>>> print(hex(Data[480])) 	# 481ème octet : pixel de la deuxième ligne à gauche
0x92
>>> print(hex(Data[153599]))  	# dernier octet : pixel en bas à droite de l'image (320ème ligne)
0x25

Avec un éditeur hexadécimal, observons le contenu du fichier image.pgm :

GHex

et comparons avec le contenu du fichier imageInverse.pgm :

GHex

Librairie Pillow (Python Imaging Library)

Cette librairie fournit des outils de traitement d'images.
Pillow est un fork de l'ancienne librairie PIL.

Installation sous Windows ou GNU/LinuxIl faut donc la télécharger et l'installer.

Télécharger la librairie Pillow

Traitement d'images avec la librairie Pillow

Le script suivant permet de convertir une photo en couleur au format JPEG en une image en niveau de gris au format PGM, puis de la transposer (retournement, miroir).
Les résultats sont affichés dans des fenêtres graphiques indépendantes et enregistrés dans des fichiers images :

# Pillow 6.0.0
# importation du module Image de la librairie Pillow
from PIL import Image

# ouverture de l'image
img = Image.open('photo.jpg')
# affichage de l'image
img.show()
# affichage de la taille de l'image (en pixels)
print(img.size)
# conversion au format PPM (en couleur) et enregistrement de l'image
img.save('photo.ppm','PPM')
img.show()
# conversion en niveau de gris (pour obtenir le format PGM)
img0 = img.convert('L')
# enregistrement dans le fichier image.pgm
img0.save('image.pgm')
img0.show()

# retournement de l'image
img1 = img0.rotate(180)
# affichage et enregistrement de l'image retournée
img1.show()
img1.save('image_retourne.pgm')

# miroir horizontal
img2 = img0.transpose(Image.FLIP_LEFT_RIGHT)
img2.show()
img2.save('image_miroir_horizontal.pgm')

# miroir vertical
img3 = img0.transpose(Image.FLIP_TOP_BOTTOM)
img3.show()
img3.save('image_miroir_vertical.pgm')
>>>
(480, 320)

Exercices

Exercice 10.1 ★

1) Reprendre le script inversion_image_pgm.py de manière à réduire l'image initiale à deux couleurs (noir et blanc) en utilisant un seuil :

2) Faire la même chose avec le logiciel GIMP.

Exercice 10.2 ★★

1) Reprendre le script inversion_image_pgm.py de façon à retourner l'image (rotation à 180 degrés) :

2) Faire la même chose avec le logiciel GIMP.

Exercice 10.3 ★★

1) Reprendre le script inversion_image_pgm.py afin de faire une transformation miroir horizontal :

2) Faire la même chose avec le logiciel GIMP.

Exercice 10.4 ★★

1) Reprendre le script inversion_image_pgm.py afin de faire une transformation miroir vertical :

2) Faire la même chose avec le logiciel GIMP.

Exercice 10.5 ★ Redimensionner une image JPEG

Avec resize() du module Image de la librairie Pillow, redimensionner une image JPEG.

>>>
Redimensionnement d'une image JPEG

Nom de l'image originale ? photo.jpg
Taille de l'image originale : (largeur, hauteur) = (1944, 2592)

Nouvelle taille :
Hauteur en pixels ? 800
Largeur en pixels : 600

Enregistrement de l'image redimensionnée
Nom de l'image redimensionnée ? photo_1.jpg

Exercice 10.6 ★★ Calcul du diamètre d'un disque

1) A l'aide de la méthode getpixel() du module Image de la librairie Pillow, estimer le diamètre d'un disque blanc d'une image à fond noir.

getpixel((x,y)) retourne la couleur du pixel de coordonnées (x,y).

Par exemple :

>>>
Nom du fichier ? disque.png

Largeur en pixels :  380
Hauteur en pixels :  250

Nombre de pixels (blanc) :  8820
Position du centre : x = 129.0 y = 100.0
Diamètre en pixels : 105.971565925

2) Application en astronomie

Estimer les dimensions de cette étoile rouge géante (image JPEG) :

Exercice 10.7 ★★ Captcha

Avec le module ImageDraw de la librairie Pillow et en s'inspirant du script camembert.py, créer un générateur de captcha :

Exercice 10.8 ★★

Ecrire un script qui permet d'extraire de l'en-tête d'un fichier PGM :

  • la largeur de l'image (en pixels)
  • la hauteur de l'image (en pixels)
  • le nombre de niveaux de gris
  • les commentaires éventuels

Exercice 10.9 ★★★

L'image suivante contient un code secret. Saurez-vous le décrypter ?

Indice n°1 : Python n'est pas nécessaire.

Indice n°2 :

Code secret: bhq24


Télécharger le fichier enigmaCodeSecret.pgm

Exercice 10.10 ★★ Programmation orientée objet

Où il est question de manipuler une image au format PGM avec une classe Python.
L'objectif de cet exercice est de compléter la classe avec de nouvelles méthodes.

Télécharger le sujet et les ressources.

Webographie

--

 

--

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *