Skip to article frontmatterSkip to article content

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:

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

  1. écrivez une fonction rectangle_size qui calcule la taille du rectangle en fonction du nombre de couleurs
# votre code

def rectangle_size(n):
    """
    return a tuple (lines, cols) for
    the smallest rectangle that contains n cells
    """
    # your code goes here...
    ...
  1. écrivez la fonction patchwork telle que décrite en préambule
# 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

  1. lisez le fichier des couleurs en Python, et rangez cela dans la structure de données qui vous semble adéquate.
# votre code
  1. Affichez, à partir de votre structure, les valeurs rgb entières des couleurs suivantes
    'Red', 'Lime', 'Blue'
# votre code
  1. Faites une fonction patchwork2 qui fait ce qu’on veut

    Testez 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));
  1. Tirez aléatoirement une liste de couleurs et appliquez votre fonction à ces couleurs.
# votre code
  1. 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
  1. Appliquez la fonction à toutes les couleurs du fichier
    et sauver ce patchwork dans le fichier patchwork.png avec plt.imsave
# votre code
  1. 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

  1. Faites une fonction sepia qui prend en argument une image RGB et rend une image RGB sépia
# votre code
  1. 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

  1. Lisez l’image data/les-mines.jpg
# votre code
  1. Créez un nouveau tableau numpy.ndarray en sommant avec l’opérateur + les valeurs RGB des pixels de votre image
# votre code
  1. 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 ...)

# votre code
  1. Créez un nouveau tableau numpy.ndarray en sommant mais cette fois avec la fonction d’agrégation np.sum les valeurs RGB des pixels de votre image
# votre code
  1. Comme dans le 2., regardez son maximum et son type, et affichez la
# votre code
  1. Les deux images sont de qualité très différente, pourquoi cette différence ? Utilisez le help np.sum?
# votre code / explication
  1. 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
  1. 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 fonction numpy.where
# votre code
  1. 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

  1. Importez la librairie Imagede PIL (pillow)
    (vous devez peut être installer PIL dans votre environnement)
# votre code
  1. Quelle est la taille du fichier data/les-mines.jpg sur disque ?
file = "data/les-mines.jpg"
# votre code
  1. Lisez le fichier ‘data/les-mines.jpg’ avec Image.open et avec plt.imread
# votre code
  1. Vérifiez que les valeurs contenues dans les deux objets sont proches
# votre code
  1. Sauvez (toujours avec de nouveaux noms de fichiers)
    l’image lue par imread avec plt.imsave
    l’image lue par Image.open avec save et une quality=100
    (save s’applique à l’objet créé par Image.open)
# votre code
  1. Quelles sont les tailles de ces deux fichiers sur votre disque ?
    Que constatez-vous ?
# votre code
  1. Relisez les deux fichiers créés et affichez avec plt.imshow leur différence
# votre code