Traitement image, suite
Nous allons effectuer des traitements différents de la semaine précédente sur l'image suivante:
Nous importons donc les mêmes modules, et la même méthode pour lire l'image:
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import numpy as np
img = mpimg.imread("Paris.jpg")
Les 4 transformations étudiées sont : flou, contours, symetrie axe horizontal, rotation (par composée de symétrie), et en utilisant la méthode diviser pour régner.
1. Flou⚓︎
En modifiant chaque pixel par la moyenne du pixel et des 8 adjacents, on obtient un léger flou. Il nous faut donc pour chaque pixel calculer une moyenne à partir des pixels de gauche, du haut, de droite et du bas.
Nous allons alors rogner de 2 lignes et 2 colonnes pour toujours avoir des pixels sur les côtés. Il est aussi possible de ne pas rogner et de calculer une moyenne autrement pour les pixels du bord de l'image.
def flou(img):
forme = img.shape
largeur = forme[1]
hauteur = forme[0]
image_t = np.ndarray((forme[0] - 2, forme[1] - 2,3)) # création d'une image vide au format rogné de 2 lignes et 2 colonnes
# parcours des pixels de l'image d'origine
for x in range(1 ,largeur -1):
for y in range(1, hauteur -1):
pixc = img[y][x].copy() # copie du pixel du centre
pixel = np.zeros(3) # création d'un pixel avec la valeur [0 0 0]
# parcours des 9 pixels inclus dans le carré autour du pixel
for deltax in [-1,0,1]:
for deltay in [-1,0,1]:
pixel += img[...][...] / (9 * 255) # ajout de la valeur de chaque pixel avec la pondération 1/9 et ramené en flottant
# ajout du pixel Ă l'image contour
image_t[y - 1][x - 1]= np.array(pixel)
return image_t
2. Contours⚓︎
Pour détecter les contours dans une image, il est possible d'utiliser le filtre de Laplace.
L'idée est de calculer une moyenne comme pour le flou mais avec des pondérations positives et négativess pour les pixels autour.
En donnant une pondération 8 au pixel central et -1 aux pixels adjacents, les pixels entourés de pixels de mêmes couleurs auront ainsi une couleur noire.
Remarque: pour éviter une structure conditionnelle, sans changer la valeur de cette moyenne pondérée.
il est possible pour chacun des 9 pixels du carré de compter 1 fois positivement celui du centre et 1 fois negativement tous les pixels.
def laplace(img):
forme = img.shape
largeur = forme[1]
hauteur = forme[0]
image_t = np.ndarray(forme)
for x in range(1,largeur -1):
for y in range(1, hauteur - 1):
pixc = img[y][x].copy()
pixel = np.zeros(3)
for deltax in [-1,0,1]:
for deltay in [-1,0,1]:
pixel += ... # ajout de la valeur du pixel central
pixel -= ... # soustraction de la valeur du pixel concerné [y + deltay][x + deltax]
# ajout du pixel Ă l'image contour
image_t[y - 1][x - 1]= np.array(pixel/255)
return image_t
3. Symétrie d'axe horizontal⚓︎
hauteur = img.shape[0]
Le code est assez simple, il suffit de remplacer le pixel[y][x]
par pixel[hauteur - 1 - y][x]
Attention hauteur - 1
et pas hauteur
car y commence Ă 0 et finit Ă hauteur - 1
. Sans cette précaution, nous aurions une sortie de tableau.
3. Rotation⚓︎
Une rotation de 90° anti-horaire peut être obtenue en compsant une symétrie d'axe horizontal et une autre symétrie d'axe la diagonale principale du carré.
Le code sera alors assez semblable à celui de la symétrie.
def rotation(img):
forme = img.shape
largeur = forme[1]
hauteur = forme[0]
nouvelle_forme = (forme[1], forme[0],3) # au cas où l'image n'est pas carrée, les dimensions largeur, hauteur sont permutées.
image_t = np.ndarray(nouvelle_forme)
for x in range(largeur):
for y in range(hauteur) :
image_t[y][x] = img[...][...] /255
return image_t
4. Rotation avec la méthode diviser pour régner.⚓︎
Rappel : la méthode diviser pour régner, divise un problème en plusieurs problèmes indépendants qui seront traités séparément avant d'être combinés.
Les 3 étapes sont : diviser, régner, combiner
Ici L'image est divisée en 4 parties par deux axes: un horizontal, un vertical
1 2
3 4
Chacune des parties est transformée par rotation, puis
Les parties sont réassemblées d'ans l'ordre :
2 4
1 3
Pour assembler les parties, nous utilisons deux méthodes np.hstack
et np.vstack
qui permettent de coller des tableaux (matrices) respectivement horizontalement et verticalement.
def rotation_dpr(img):
forme=img.shape
largeur = forme[1]
hauteur = forme[0]
ml = largeur // 2 # mi largeur
mh = hauteur // 2 # mi hauteur
# Diviser
hg = img[0:mh,0:ml] # quart haut gauche
hd = img[0:mh,ml:largeur] # quart haut droit
bg = img[mh:hauteur,0:ml] # quart bas gauche
bd = img[mh:hauteur,ml:largeur] # quart bas droite
# RĂ©gner
rhg = rotation(hg)
rhd = rotation(hd)
rbg = rotation(bg)
rbd = rotation(bd)
# Combiner (Assemblage)
haut = np.hstack([rhd,rbd])
bas = np.hstack([rhg,rbg])
return np.vstack([haut,bas])
Remarque Cette utilisation du diviser pour régner est ici moins intéressante que pour le tri fusion. En effet, la résolution de chaque sous-problème n'ayant pas une compléxité quadratique, il n'y a pas de gain de compléxité temporelle globale.