diff --git a/Chapitre 2 - Récursivité/C06_tp_pivoter_image.py b/Chapitre 2 - Récursivité/C06_tp_pivoter_image.py new file mode 100644 index 0000000..a73a810 --- /dev/null +++ b/Chapitre 2 - Récursivité/C06_tp_pivoter_image.py @@ -0,0 +1,114 @@ +# TP p 128 + +# 1. L'étape (ii) fait des appels récursifs + +# 2. Pour une image de 2^n x 2^n pixels il y auras une profondeur de récurstion de n et il y auras 4^n appels récursifs + +# 3. Oui, l'algorithme reste corect si l'on inverse l'ordre des étapes (i) et (ii). + +# 4. Non, cet algorithme n'est pas facilement adaptable pour fonctionner avec +# des rectangles car il se base sur le fait de pouvoir diviser en 4 l'image. + +# 5. L'algorithme peut transformer l'image sur place. + +def echange_2blocs(m, x1, y1, x2, y2, w): + """ + Echange sur place (sans les pivoter) 2 blocs de w x w dans la matrice m, + le bloc 1 étant compris entre (x1, y1) et (x1 + (w-1), y1 + (w-1)) inclus, + et le bloc 2 étant de façon similaire entre (x2, y2) et (x2 + (w-1), y2 + (w-1)) inclus + Chaque pixel dans un bloc est échangé avec le pixel de même coordonnées dans le second bloc. + ------- + Complexité : quadratique en w. + """ + for i in range(w): + for j in range(w): + m[x2+i][y2+j], m[x1+i][y1+j] = m[x1+i][y1+j], m[x2+i][y2+j] + + +def permuter_4blocs(m, x, y, w): + """ + Permute sur place (sans les pivoter) les 4 blocs d'un carré dans l'image m, + le carré de w x w pixels compris entre (x, y) et (x + (w-1), y + (w-1)) inclus. + ------- + Suppose (entre autres) que w est pair. + ------- + Complexité : quadratique en w. + ------- + Attention, on adopte la convention "image" pour les matrices : + m[i][j] donne la i-ième ligne et j-ième colonne en partant du haut à gauche. + La permutation se fait en échangeant les quartiers 2 à 2: + - (imin, jmin) avec (imin, jmax) + - (imin, jmin) avec (imax, jmin) + - (imax, jmin) avec (imax, jmax) + où par exemple (imin, jmin) représente le bloc comportant les plus petites valeurs sur i et j. + """ + echange_2blocs(m, x, y, x, y + w // 2, w // 2) + echange_2blocs(m, x, y, x + w // 2, y, w // 2) + echange_2blocs(m, x + w // 2, y, x + w // 2, y + w // 2, w // 2) + + +def pivoter_rec(m, x, y, w): + """ + Pivote récursivement d'un quart de tour + le carré compris entre (x, y) et (x + (w-1), y + (w-1)) inclus + dans la matrice m. + ------- + Suppose (entre autres) que w est une puissance de 2. + ------- + Complexité : quadratique en w. + """ + if w > 1: + new_w = w//2 + pivoter_rec(m, x, y, new_w) + pivoter_rec(m, x+new_w, y, new_w) + pivoter_rec(m, x+new_w, y+new_w, new_w) + pivoter_rec(m, x, y+new_w, new_w) + permuter_4blocs(m, x, y, w) + + +def pivoter(m): + """ + Pivote une image d'un quart de tour à droite en utilisant l'algorithme récursif + de type « diviser pour régner » présenté dans le manuel. + ------- + Entrée: + - une matrice m, de dimensions 2^k x 2^k. + - m[0][0] représente le coin en haut à gauche de l'image, m[0][len(m)] le coin en haut à droite. + Modifie la matrice m sur place. + ------- + Complexité: k x 2^k x 2^k. + """ + w = len(m) + assert (w & (w - 1) == 0) and w != 0 + assert w == len(m[0]) + pivoter_rec(m, 0, 0, w) + + +# Test: +m = [['a','b'],['d','c']] +pivoter(m) +print(m==[['d', 'a'], ['c', 'b']]) + +m = [[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]] +pivoter(m) +print(m==[[13, 9, 5, 1], [14, 10, 6, 2], [15, 11, 7, 3], [16, 12, 8, 4]]) + +# Attention de choisir une image carrée (même nombre de pixels sur x et y) dont les dimensions soient une puissance de 2. +import matplotlib.pyplot as plt +import matplotlib.image as mpimg + + +m = [[.4,.1],[.8,.8]] +plt.imshow(m) +plt.show() +pivoter(m) +plt.imshow(m) +plt.show() + +img = mpimg.imread('python256_couleur.png').tolist() +imgplot = plt.imshow(img) +plt.show() + +pivoter(img) +plt.imshow(img) +plt.show() diff --git a/Chapitre 2 - Récursivité/exercices.py b/Chapitre 2 - Récursivité/exercices.py index 2fae0a4..9671ba8 100644 --- a/Chapitre 2 - Récursivité/exercices.py +++ b/Chapitre 2 - Récursivité/exercices.py @@ -165,4 +165,3 @@ better_hanoi(4, [4, 3, 2, 1], [], []) # Il faut faire du code simple sans utiliser goto, setjmp ou longjmp et ne pas utiliser de récursion directe ou indirecte. # Cela est utile car cela permet d'avoir un code plus clair et plus facilement analysable pour détécter des erreurs. -