Licence CC BY-NC-ND, Valérie Roy & Thierry Parmentelat
pour réaliser ce TP localement sur votre ordi, si ce n’est pas déjà fait, commencez par télécharger le zip
TP images (2/2)¶
merci à Wikipedia et à stackoverflow
import numpy as np
from matplotlib import pyplot as plt
Création d’un patchwork¶
v1¶
on se propose d’écrire un code pour créer des tableaux dans le genre de celui-ci (affiché avec plt.imshow
):

# pour cela on se définirait par exemple
colors = [
[255, 0, 0],
[0, 255, 0],
[0, 0, 255],
[255, 255, 0],
[255, 0, 255],
]
après quoi on appellerait la fonction patchwork
- que vous allez devoir écrire - comme ceci:
plt.imshow(patchwork(colors))
remarquez les choses suivantes:
- si par exemple on avait passé 9 couleurs, on aurait créé un carré 3x3, mais comme ici on a passé à la fonction une liste de 5 couleurs, pour que ça tienne dans un rectangle, on se décide sur un rectangle de taille 2x3
- la taille totale de l’image est de 10x15, car par défaut chaque petite tuile a une taille de 5 pixels
- du coup le dernier carré est rempli avec une couleur par défaut - ici DarkGray (dans la v2 on pourra utiliser les couleurs par leur nom, mais n’anticipons pas; pour l’instant notez que DarkGray c’est 169, 169, 169)
on va permettre à l’appelant de changer ces valeurs par défaut
ça signifie que si on appelait
# cette fois on passe 10 couleurs (colors + colors est une liste de 10 couleurs)
# et on fixe la taille des tuiles, et la couleur de fond noire
plt.imshow(patchwork(colors + colors, side=10, background=[0, 0, 0]))
on obtiendrait cette fois (observez la taille en pixels de l’image)

exercice
- écrivez une fonction
rectangle_size
qui calcule la taille du rectangle en fonction du nombre de couleurs
indice
votre fonction retourne un tuple avec deux morceaux: le nombre de lignes, et le nombre de colonnes
dans un premier temps, vous pouvez vous contenter d’une version un peu brute: on pourrait utiliser juste la racine carrée, et toujours fabriquer des carrés
par exemple avec 5 couleurs créer un carré 3x3 (et remplir les 4 cases restantes avec la couleur de fond)
mais si vous avez le temps, pour 5 couleurs, un rectangle 3x2 c’est quand même mieux !
voici pour vous aider à calculer le rectangle qui contient n couleurs
n rect n rect n rect n rect 1 1x1 5 2x3 9 3x3 14 4x4 2 1x2 6 2x3 10 3x4 15 4x4 3 2x2 7 3x3 11 3x4 16 4x4 4 2x2 8 3x3 12 3x4 17 4x5
# votre code
def rectangle_size(n):
"""
return a tuple (lines, cols) for
the smallest rectangle that contains n cells
"""
# your code goes here...
...
- écrivez la fonction
patchwork
telle que décrite en préambule
indices
- sont potentiellement utiles pour cet exo:
- la fonction
np.indices()
- l’indexation d’un tableau par un tableau
- la fonction
- souvenez-vous que chaque “tuile” a une taille réglable
- et qu’il vous faut peindre les tuiles surnuméraires avec une couleur de fond paamétrable
# votre code
def patchwork(colors, side=10, background=[169, 169, 169]):
"""
- colors is expected to be a list of n colors; it can be either
* a list like e.g. [[255, 0, 0], [0, 255, 0], ... ]
* or a numpy array of shape n, 3
- side is the "width" of each square
- optional background it used to pad the rest of the image when
the <n> colors are not enough to fill a rectangle
here we use DarkGray as the default
"""
# your code here
...
# si vous voulez tester
# plt.imshow(patchwork(colors));
# si vous voulez tester
# plt.imshow(patchwork(colors+colors, side=10, background=[0, 0, 0]))
v2 (optionnel)¶
dans cette version, on a envie de pouvoir faire essentiellement la même chose, mais avec des noms de couleurs
et pour cela on vous fournit un fichier textuel de description des couleurs qui se trouve dans data/rgb-codes.txt
et qui ressemble à ceci:
AliceBlue 240 248 255
AntiqueWhite 250 235 215
Aqua 0 255 255
.../...
YellowGreen 154 205 50
Comme vous le devinez, le nom de la couleur est suivi des 3 valeurs
de ses codes R
, G
et B
# with patchwork v2 one could use this data
color_names = [
'DarkBlue', 'AntiqueWhite', 'LimeGreen', 'NavajoWhite',
'Tomato', 'DarkGoldenrod', 'LightGoldenrodYellow', 'OliveDrab',
'Red', 'Lime',
]
et ce qu’on veut, c’est pouvoir faire par exemple
patchwork2(color_names)
pour obtenir ceci

exercice
- lisez le fichier des couleurs en
Python
, et rangez cela dans la structure de données qui vous semble adéquate.
# votre code
- Affichez, à partir de votre structure, les valeurs rgb entières des couleurs suivantes
'Red'
,'Lime'
,'Blue'
# votre code
Faites une fonction
patchwork2
qui fait ce qu’on veutTestez votre fonction en affichant le résultat obtenu sur un jeu de couleurs fourni
# votre code
def patchwork2(color_names, side=10, background_color="DarkGray"):
'''
create a patchwork image with <color_names>, which are resolved
from the text file loaded above
the other two parameters are passed to the `patchwork` function above
except that the background color is expected to ba a color name too
'''
# your goes goes here
...
# ou encore
#plt.imshow(patchwork2(color_names, side=20, background="DarkGray"));
# et pour le tester
#plt.imshow(patchwork2(color_names));
- Tirez aléatoirement une liste de couleurs et appliquez votre fonction à ces couleurs.
# votre code
- Sélectionnez toutes les couleurs à base de blanc (i.e. dont le nom contient
white
) et affichez leur patchwork
même chose pour des jaunes
# votre code
- Appliquez la fonction à toutes les couleurs du fichier
et sauver ce patchwork dans le fichierpatchwork.png
avecplt.imsave
# votre code
- Relisez et affichez votre fichier
attention si votre image vous semble floue c’est juste que l’affichage grossit vos pixels
# votre code
vous devriez obtenir quelque chose comme ceci

Image en sépia¶
Pour passer en sépia les valeurs R, G et B d’un pixel, on applique la transformation suivante
R' = 0.393 * R + 0.769 * G + 0.189 * B
G' = 0.349 * R + 0.686 * G + 0.168 * B
B' = 0.272 * R + 0.534 * G + 0.131 * B
# exemple de produit de matrices avec `numpy.dot`
# le help(np.dot) dit: dot(A, B)[i,j,k,m] = sum(A[i,j,:] * B[k,:,m])
i, j, k, m, n = 2, 3, 4, 5, 6
A = np.arange(i*j*k).reshape(i, j, k)
B = np.arange(m*k*n).reshape(m, k, n)
C = A.dot(B)
# or C = np.dot(A, B)
print(f"en partant des dimensions {A.shape} et {B.shape}")
print(f"on obtient un résultat de dimension {C.shape}")
print(f"et le nombre de termes dans chaque `sum()` est {A.shape[-1]} == {B.shape[-2]}")
en partant des dimensions (2, 3, 4) et (5, 4, 6)
on obtient un résultat de dimension (2, 3, 5, 6)
et le nombre de termes dans chaque `sum()` est 4 == 4
Exercice
- Faites une fonction
sepia
qui prend en argument une image RGB et rend une image RGB sépia
# votre code
- Passez l’image
data/les-mines.jpg
en sépia
# votre code
Voici ce que vous devriez obtenir avec l’images des Mines
l’original

la version sepia

Somme dans une image & overflow¶
- Lisez l’image
data/les-mines.jpg
# votre code
- Créez un nouveau tableau
numpy.ndarray
en sommant avec l’opérateur+
les valeurs RGB des pixels de votre image
# votre code
Regardez le type de cette image-somme, et son maximum; que remarquez-vous?
Affichez cette image-somme; comme elle ne contient qu’un canal il est habile de l’afficher en “niveaux de gris” (normalement le résultat n’est pas terrible ...)niveaux de gris ?cherchez sur google
pyplot imshow cmap gray
# votre code
- Créez un nouveau tableau
numpy.ndarray
en sommant mais cette fois avec la fonction d’agrégationnp.sum
les valeurs RGB des pixels de votre image
# votre code
- Comme dans le 2., regardez son maximum et son type, et affichez la
# votre code
- Les deux images sont de qualité très différente, pourquoi cette différence ? Utilisez le help
np.sum?
# votre code / explication
- Passez l’image en niveaux de gris de type entiers non-signés 8 bits
(de la manière que vous préférez)
# votre code
- Remplacez dans l’image en niveaux de gris,
les valeurs >= à 127 par 255 et celles inférieures par 0
Affichez l’image avec une carte des couleurs des niveaux de gris
vous pouvez utilisez la fonctionnumpy.where
# votre code
- avec la fonction
numpy.unique
regardez les valeurs différentes que vous avez dans votre image en noir et blanc
# votre code
Exemple de qualité de compression¶
- Importez la librairie
Image
dePIL
(pillow)
(vous devez peut être installer PIL dans votre environnement)
# votre code
- Quelle est la taille du fichier
data/les-mines.jpg
sur disque ?
file = "data/les-mines.jpg"
# votre code
- Lisez le fichier ‘data/les-mines.jpg’ avec
Image.open
et avecplt.imread
# votre code
- Vérifiez que les valeurs contenues dans les deux objets sont proches
# votre code
- Sauvez (toujours avec de nouveaux noms de fichiers)
l’image lue parimread
avecplt.imsave
l’image lue parImage.open
avecsave
et unequality=100
(save
s’applique à l’objet créé parImage.open
)
# votre code
- Quelles sont les tailles de ces deux fichiers sur votre disque ?
Que constatez-vous ?
# votre code
- Relisez les deux fichiers créés et affichez avec
plt.imshow
leur différence
# votre code