Images

Négatif.

L'image à charger ici est une photographie de l'entrée du lycée au format ppm.

L'objectif de ce premier exercice est de lire les données dans ce fichier ppm et de créer un second fichier ppm qui contiendra l'image en négatif (ce qui signifie que chaque entier apparaissant dans le code d'un pixel est transformé en son complément à 255, c'est à dire x↦255-x).

Il s'agit donc de passer de la première image à la seconde :

lpa lpa inversé

Vous aurez éventuellement besoin des fonctions join() et split() pour lesquelles vous trouverez une présentation ici.

Une solution possible est présentée ci-dessous. Prenez le temps de tester, de faire des modifications, d'ouvrir les fichiers images associés...

 
# travail sur le  fichier source
with open('lpa.ppm','r') as f :
	# lecture du fichier et stockage dans une chaîne :
	lecture = f.read() 
	# transformation de la chaîne en liste :
	lecture = lecture.split()
	
 
# travail sur le fichier but :
with open('invlpa.ppm','w') as f :
	# on recopie l'entête
	# de la source vers le but
	for i in range(4) :
		f.write(lecture[i]+'\n')
	
	# on recopie maintenant les  valeurs rgb
	# après transformation 
	for i in range(4, len(lecture)):
		# transformation en entier :
		lecture[i] = int(lecture[i])
		# opération "complémentaire" :
		lecture[i] = 255 - lecture[i]
		# retransfo en chaine
		# car dans un fichier, on ne met que des chaînes :
		lecture[i] = str(lecture[i])
		# écriture dans le fichier but :
		f.write(lecture[i]+'\n')

Autre version en utilisant d'autres fonctions de lecture :


#ouverture en lecture
# du fichier source
fsource=open('lpa.ppm','r')

# ouverture en écriture du fichier
# à créer
fbut=open('invlpa.ppm','w')


# on recopie les 3 lignes d'entête
# de la source vers le but
for i in range(3) :
	L=fsource.readline()
	fbut.write(L)

#les lignes suivantes sont des chaînes constituées
# d'entiers entre 0 et 255 
# et terminées par '\n'

L=fsource.readline()
while L : # tant que la ligne lue n'est pas vide
	# suppression de '\n' en fin de chaîne
	L.rsplit('\n')
	# conversion en liste :
	L=L.split()
	# conversion en liste d'entiers
	L=[int(x) for x in L]
	# liste des compléments à 255
	L=[255-x for x in L]
	#conversion en liste de str
	L=[str(x) for x in L]
	# écriture des éléments dans le fichier but :
	for x in L :
		fbut.write(x+'\n')
	#lecture de la ligne suivante dans le fichier source
	L=fsource.readline()

fsource.close()
fbut.close()

Le zèbre trois fois trop lourd.

Le fichier à charger ici est une photo d'un zèbre au format ppm.

  1. Ouvrez ce fichier avec un éditeur de texte. Expliquez pourquoi on peut dire que ce fichier est trois fois trop lourd (il s'agit du poids en octets bien sûr) en observant les codes couleurs des pixels.
  2. En cherchant sur le web, la définition du format pgm (par exemple ici), écrire un programme python qui crée un fichier de l'image environ trois fois moins lourd.

Rappelons que chaque pixel est codé, dans le format ppm, par trois entiers (compris entre 0 et 255 et correspondant aux intensités respectives de rouge, vert, bleu).
On lit dans le fichier que chaque paquet de trois entiers correspondant à un pixel est constitué de trois entiers égaux. L'information est donc redondante et on devrait pouvoir la réduire.
Il se trouve que le format pgm (images en niveaux de gris) permet cette économie : dans ce format pgm, chaque pixel est codé par un seul entier entre 0 et 255, entier correspondant à l'intensité du gris du pixel.


# travail sur le fichier source :
with open('zebre.ppm','r') as f :
	# lecture du fichier et stockage dans une chaîne :
	lecture = f.read() 
	# transformation de la chaîne en liste :
	lecture = lecture.split()
 

# travail sur le fichier but :
with open('zebre.pgm','w') as f :
	#  l'entête :
	f.write('P2' + '\n')
	f.write(lecture[1]+'  '+lecture[2]+'\n')
	f.write(lecture[3]+'\n')
	# copie des codes R (sans copier G et B) :
	for i in range(4, len(lecture), 3):
		f.write(lecture[i] + '\n')

Consultez les poids des deux fichiers (pour le ppm initial : 7.9 Mo, pour le pgm obtenu : 2.6 Mo ). On a bien un rapport de 3 environ.

Griser.

Le fichier à charger ici est une photo de fruits et légumes au format ppm.

L'objectif est de transformer cette photo en photo en niveaux de gris. On cherche donc à passer de la joyeuse image colorée ci-dessous à la triste image grise.

coloré triste

En code RGB, on obtient du gris lorsque R = G = B. Un procédé simple pour passer en niveaux de gris est de remplacer les codes RGB en la moyenne (R+G+B)/3.

On trouve sur le web des formules telles que code du gris = 0.2125 R + 0.7154 G + 0.0721 B qui permettent d'améliorer assez sensiblement les résultats sur certaines images (par rapport au choix de la moyenne indiquée dans l'énoncé).


# travail sur le fichier source :
with open('fruitslegumes.ppm','r') as f :
	# lecture du fichier et stockage dans une chaîne :
	lecture = f.read() 
	# transformation de la chaîne en liste :
	lecture = lecture.split()
 

# travail sur le fichier but :
with open('fruitslegumes.pgm','w') as f :
	# écriture de l'entête :
	f.write('P2\n')
	f.write(lecture[1]+'  '+lecture[2]+'\n')
	f.write(lecture[3]+'\n')
	# calcul des moyennes :
	for i in range(4, len(lecture), 3):
		m = ( int(lecture[i]) + int(lecture[i+1]) + int(lecture[i+2]) ) // 3 
		f.write(str(m)+'\n')

Remarque

Dans la seconde série d'exercices, nous utiliserons le module PIL.

Ce module permet de manipuler les images et automatise bien sûr ce genre de traitement.

Exemple avec l'image suivante au format jpg :
panda


from PIL import Image

# ouverture de l'image initiale :
imageSource=Image.open('ptpanda.jpg')
# conversion en niveaux de gris :
imageSource=imageSource.convert('L')
# sauvegarde du résultat sous un nouveau nom :
imageSource.save('pandagris.jpg')
# on lance une visualisation :
imageSource.show()

On obtient :
panda

Le créateur de rose.

Le fichier à charger ici est la photo d'une rose au format ppm.

L'objectif est de créer une catégorie de rose verte.

En d'autres termes, vous devez transformer la rose rouge en la verte.

rose verte

L'idée consiste à simplement échanger les intensités de rouge et de vert.


# travail sur le fichier source :
with open('rose.ppm','r') as f :
	# lecture du fichier et stockage dans une chaîne :
	lecture = f.read() 
	# transformation de la chaîne en liste :
	lecture = lecture.split()
 

# travail sur le fichier but :
with open('verte.ppm','w') as f :
	# recopie de l'entête :
	f.write(lecture[0]+'\n')
	f.write(lecture[1]+'  '+lecture[2]+'\n')
	f.write(lecture[3]+'\n')
	# copie des codes RGB et échange des intensités R et G :
	for i in range(4, len(lecture), 3):
		r, g, b = lecture[i], lecture[i+1], lecture[i+2]
		f.write(g + ' ' + r + ' ' + b + '\n')

Pour vérifier que vous avez bien saisi le fonctionnement, vous pouvez ensuite tenter de transformer la rose en rose bleue ou tentez d'autres modifications.