#!/usr/bin/env python
# coding: utf-8
# ![En tête general](https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/En_tete_general.png)
#
#
# © Copyright Franck CHEVRIER 2019-2021 https://www.python-lycee.com.
# Les activités partagées sur Capytale sont sous licence Creative Commons.
#
# Pour exécuter une saisie Python, sélectionner la cellule et valider avec SHIFT+Entrée.
#
# # Composition d'images (corrigé)
#
# ### Activité sur le traitement d'images n°2
# Le but de cette activité est d'apprendre à composer une nouvelles image à partir de deux images initiales.
# Cette activité fait suite à l'activité sur les traitements d'images n°1 (Application de filtres).
#
# Dans chacun des cas, les images qui seront composées entre elles auront les mêmes dimensions.
#
#
# ### Sommaire
#
# 1. Superposition d'images
# 2. Réalisation d'un anaglyphe
# 3. Incrustation sur fond vert
#
# ## 1. Superposition d'images
#
# Dans cette partie, on souhaite obtenir une nouvelle image par superposition de deux images.
# 1.1. Exécuter les cellules ci-dessous, qui permettent chacune :
# - d'ouvrir un fichier et de stocker l'image dans un objet Python de type Image;
# - d'afficher le format, le type de codage et la dimension de l'image;
# - d'afficher l'image.
#
# In[ ]:
# import du module permettant la gestion des images
from PIL import Image
import requests
from io import BytesIO
#ouverture de l'image 1
Im1 = Image.open(BytesIO(requests.get('https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/oiseau.jpg').content))
#affichage du format, du type et de la dimension de l'image 2
print("Nom: Im1","\nFormat:",Im1.format,"\nMode:",Im1.mode,"\nDimensions:",Im1.size) ;
#affichage de l'image
Im1
# In[ ]:
#ouverture de l'image 2
Im2 = Image.open(BytesIO(requests.get('https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/montagne.jpg').content))
#affichage du format, du type et de la dimension de l'image 2
print("Nom: Im2","\nFormat:",Im2.format,"\nMode:",Im2.mode,"\nDimensions:",Im2.size) ;
#affichage de l'image
Im2
# __1.2. Superposition par saturation.__
# $\;\;\;\;\;$__On donne la fonction Python sup_saturation ci-dessous.__
# $\;\;\;\;\;$__a. On suppose que les codes R,G,B de deux pixels correspondants dans les images originales sont (50,200,70) et (40,120,30).__
# $\;\;\;\;\;\;\;\;$__Quel sera le code R,G,B du pixel de l'image obtenue?__
# $\;\;\;\;\;$__b. Exécuter les deux cellules ci-dessous pour tester la fonction sup_saturation.__
# $\;\;\;\;\;$__c. Que peux-t-on dire de la luminosité de l'image obtenue par rapport à celles des images originales?__
#
# In[ ]:
def sup_saturation(im_or1,im_or2):
"""
fonction qui superpose deux images par saturation
"""
# vérification que les images sont de même format et taille
if (im_or1.format,im_or1.mode,im_or1.size) != (im_or2.format,im_or2.mode,im_or2.size): return "Images incompatibles"
# récupération des dimensions des images originales
L,H = im_or1.size
# création d'une image vierge, de même format et même taille que les images initiales
im_composee = Image.new( mode=im_or1.mode , size=(L,H) )
# ouverture de l'accès aux pixels des images
pix_or1 = im_or1.load()
pix_or2 = im_or2.load()
pix_composee = im_composee.load()
# on parcourt tous les pixels des images
for x in range(L):
for y in range(H):
R1,G1,B1 = pix_or1[x,y] #récupération des composantes R,G,B du pixel original de l'image originale im_or1
R2,G2,B2 = pix_or2[x,y] #récupération des composantes R,G,B du pixel original de l'image originale im_or2
R = R1+R2
G = G1+G2
B = B1+B2
pix_composee[x,y] = R,G,B #écriture des composantes R,G,B du pixel modifié
# on renvoie l'image modifiée
return im_composee
# In[ ]:
sup_saturation(Im1,Im2)
# __1.3. Superposition par maximum.__
# $\;\;\;\;\;$__On souhaite construire les composantes des pixels de la nouvelle image en prenant la plus grande des composantes des deux images.__
# $\;\;\;\;\;$__Écrire la fonction Python sup_max qui convient.__
# $\;\;\;\;\;$Aide : On peut utiliser la fonction Python max pour le calcul d'un maximum.
#
# In[ ]:
# Écrire ici la fonction sup_max
def sup_max(im_or1,im_or2):
"""
fonction qui superpose deux images par moyenne
"""
# vérification que les images sont de même format et taille
if (im_or1.format,im_or1.mode,im_or1.size) != (im_or2.format,im_or2.mode,im_or2.size): return "Images incompatibles"
# récupération des dimensions des images originales
L,H = im_or1.size
# création d'une image vierge, de même format et même taille que les images initiales
im_composee = Image.new( mode=im_or1.mode , size=(L,H) )
# ouverture de l'accès aux pixels des images
pix_or1 = im_or1.load()
pix_or2 = im_or2.load()
pix_composee = im_composee.load()
# on parcourt tous les pixels des images
for x in range(L):
for y in range(H):
R1,G1,B1 = pix_or1[x,y] #récupération des composantes R,G,B du pixel original de l'image originale im_or1
R2,G2,B2 = pix_or2[x,y] #récupération des composantes R,G,B du pixel original de l'image originale im_or2
R = max(R1,R2)
G = max(G1,G2)
B = max(B1,B2)
pix_composee[x,y] = R,G,B #écriture des composantes R,G,B du pixel modifié
# on renvoie l'image modifiée
return im_composee
# In[ ]:
# Tester ici un appel à la fonction sup_max
sup_max(Im1,Im2)
# __1.4. Superposition par la moyenne.__
# $\;\;\;\;\;$__On souhaite construire les composantes des pixels de la nouvelle image par calculs des moyennes des composantes des pixels initiaux.__
# $\;\;\;\;\;$__Écrire la fonction Python sup_moyenne qui convient.__
#
# In[ ]:
# Écrire ici la fonction sup_moyenne
def sup_moyenne(im_or1,im_or2):
"""
fonction qui superpose deux images par moyenne
"""
# vérification que les images sont de même format et taille
if (im_or1.format,im_or1.mode,im_or1.size) != (im_or2.format,im_or2.mode,im_or2.size): return "Images incompatibles"
# récupération des dimensions des images originales
L,H = im_or1.size
# création d'une image vierge, de même format et même taille que les images initiales
im_composee = Image.new( mode=im_or1.mode , size=(L,H) )
# ouverture de l'accès aux pixels des images
pix_or1 = im_or1.load()
pix_or2 = im_or2.load()
pix_composee = im_composee.load()
# on parcourt tous les pixels des images
for x in range(L):
for y in range(H):
R1,G1,B1 = pix_or1[x,y] #récupération des composantes R,G,B du pixel original de l'image originale im_or1
R2,G2,B2 = pix_or2[x,y] #récupération des composantes R,G,B du pixel original de l'image originale im_or2
R = (R1+R2)//2 # ou int((R1+R2)*0.5)
G = (G1+G2)//2
B = (B1+B2)//2
pix_composee[x,y] = R,G,B #écriture des composantes R,G,B du pixel modifié
# on renvoie l'image modifiée
return im_composee
# In[ ]:
# Tester ici la fonction sup_moyenne
sup_moyenne(Im1,Im2)
# ## 2. Réalisation d'un anaglyphe
#
#
# Un anaglyphe est une image permettant de donner l'illusion de la 3ème dimension à l'aide de lunettes à filtres bleu-rouge.
# Pour réaliser un anaglyphe, on commence par prendre deux photos de la même scène, avec un léger décalage de l'appareil (correspondant aux images perçues par les deux yeux de l'individu).
#
#
# ![anaglyphe](https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/Illu_anaglyphe.png)
#
#
#
#
#
- Si vous disposez de deux images (de mêmes type et dimensions), allez à la question 2.1.a.
# - Si vous ne disposez pas d'images, passez directement à la question 2.1.b. pour utiliser les images fournies.
#
#
#
#
#
# __2.1.a. TELECHARGEMENT DE VOS IMAGES__
# $\;\;\;\;\;\;\;\;$__Exécuter successivement les cellules ci-dessous pour télécharger des images personnelles.__
# $\;\;\;\;\;\;\;\;$__Elles seront stockées respectivement dans les variables image_gauche et image_droite.
__
# $\;\;\;\;\;\;\;\;$__Passer ensuite directement à la question 2.2.__
# In[ ]:
#Cellule pour le téléchargement de votre image de gauche
from PIL import Image
import ipywidgets as widgets
uploader1 = widgets.FileUpload(accept='image/*',multiple=False)
print("Cliquer pour charger l'image de gauche :")
display(uploader1)
# In[ ]:
#Cellule pour la mise en mémoire de votre image de gauche
from io import BytesIO
try:
[uploaded_file1] = uploader1.value
image_gauche = Image.open(BytesIO(uploader1.value[uploaded_file1]['content']))
print("Nom: image_gauche","\nFormat:",image_gauche.format,"\nMode:",image_gauche.mode,"\nDimensions:",image_gauche.size)
display(image_gauche)
except:
print("Vous n'avez pas chargé d'image ou son format n'est pas reconnu")
# In[ ]:
#Cellule pour le téléchargement de votre image de droite
uploader2 = widgets.FileUpload(accept='image/*',multiple=False)
print("Cliquer pour charger l'image de droite :")
display(uploader2)
# In[ ]:
#Cellule pour la mise en mémoire de votre image de droite
try:
[uploaded_file2] = uploader2.value
image_droite = Image.open(BytesIO(uploader2.value[uploaded_file2]['content']))
print("Nom: image_droite","\nFormat:",image_droite.format,"\nMode:",image_droite.mode,"\nDimensions:",image_droite.size)
display(image_droite)
except:
print("Vous n'avez pas chargé d'image ou son format n'est pas reconnu")
# __2.1.b. TELECHARGEMENT DES IMAGES FOURNIES__
# $\;\;\;\;\;\;\;\;$__Exécuter la cellule ci-dessous pour télécharger les images fournies.__
# $\;\;\;\;\;\;\;\;$__Elles seront stockées respectivement dans les variables image_gauche et image_droite.__
# In[ ]:
# Cellule pour charger les images fournies
from PIL import Image
import requests
from io import BytesIO
image_gauche = Image.open(BytesIO(requests.get('https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/test_gauche.jpg').content))
image_droite = Image.open(BytesIO(requests.get('https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/test_droite.jpg').content))
print("Nom: image_gauche","\nFormat:",image_gauche.format,"\nMode:",image_gauche.mode,"\nDimensions:",image_gauche.size) ; display(image_gauche)
print("Nom: image_droite","\nFormat:",image_droite.format,"\nMode:",image_droite.mode,"\nDimensions:",image_droite.size) ; display(image_droite)
# __2.2. Anaglyphe rapide : On souhaite réaliser l'anaglyphe de la façon suivante :__
# Pour chaque pixel de l’image à créer, on lui attribue la composante rouge de l'image de gauche, et les composantes bleue et verte de l'image de droite.
#
#
# ![anaglyphe](https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/Illu_anaglyphe_2.png)
#
#
# $\;\;\;\;\;$__a. Écrire la fonction Python anaglyphe_rapide qui convient.__
# In[ ]:
# Écrire ici la fonction anaglyphe_rapide
def anaglyphe_rapide(image_gauche,image_droite):
"""
fonction qui réalise un anaglyphe rapide
"""
# vérification que les images sont de même format et taille
if (image_gauche.format,image_gauche.mode,image_gauche.size) != (image_droite.format,image_droite.mode,image_droite.size): return "Images incompatibles"
# récupération des dimensions des images originales
L,H = image_gauche.size
# création d'une image vierge, de même format et même taille que les images initiales
anaglyphe = Image.new( mode=image_gauche.mode , size=(L,H) )
# ouverture de l'accès aux pixels des images
pix_gauche = image_gauche.load()
pix_droit = image_droite.load()
pix_anaglyphe = anaglyphe.load()
# on parcourt tous les pixels des images
for x in range(L):
for y in range(H):
Rg,Gg,Bg = pix_gauche[x,y] #récupération des composantes R,G,B du pixel de l'image de gauche
Rd,Gd,Bd = pix_droit[x,y] #récupération des composantes R,G,B du pixel de l'image de droite
R = Rg
G = Gd
B = Bd
pix_anaglyphe[x,y] = R,G,B
# on renvoie l'image modifiée
return anaglyphe
# $\;\;\;\;\;$__b. Tester la fonction anaglyphe_rapide.__
#
# In[ ]:
# Tester ici la fonction anaglyphe_rapide
anaglyphe_rapide(image_gauche,image_droite)
# __2.3. Anaglyphe précis :__
#
# On souhaite diminuer l'altération des couleurs de l'anaglyphe réalisé.
# Pour cela, on calcule les composantes R,G,B du pixel de l'anaglyphe à l'aide du tableau suivant.
#
# | Anaglyphe |$\;\;$| $\color{red}{R_g}$ | $\color{green}{G_g}$ | $\color{blue}{B_g}$ | | $\color{red}{R_d}$ | $\color{green}{G_d}$ | $\color{blue}{B_d}$ |
# |:--------------------:|:----:|:-----:|:-----:|:-----:| |:-----:|:-----:|:-----:|
# | $\color{red}{R}$ |$\;\;$| $41$% | $47$% | $16$% | |$-1$% | $-3$% | $0$% |
# | $\color{green}{G}$ |$\;\;$| $-4$% | $-4$% | $-2$% | |$38$% | $73$% | $1$% |
# | $\color{blue}{B}$ |$\;\;$| $-5$% | $-6$% | $1$% | |$-6$% | $-13$%| $130$%|
#
# Par exemple, la composante rouge R de l'anaglyphe se calcule à l'aide de la formule : R = int(0.41\*Rg+0.47\*Gg+0.16\*Bg-0.01\*Rd-0.03\*Gd).
#
#
#
#
# $\;\;\;\;\;$__a. Écrire la fonction Python anaglyphe_precis qui convient.__
# In[ ]:
# Écrire ici la fonction anaglyphe_precis
def anaglyphe_precis(image_gauche,image_droite):
"""
fonction qui réalise un anaglyphe precis
"""
# vérification que les images sont de même format et taille
if (image_gauche.format,image_gauche.mode,image_gauche.size) != (image_droite.format,image_droite.mode,image_droite.size): return "Images incompatibles"
# récupération des dimensions des images originales
L,H = image_gauche.size
# création d'une image vierge, de même format et même taille que les images initiales
anaglyphe = Image.new( mode=image_gauche.mode , size=(L,H) )
# ouverture de l'accès aux pixels des images
pix_gauche = image_gauche.load()
pix_droit = image_droite.load()
pix_anaglyphe = anaglyphe.load()
# on parcourt tous les pixels des images
for x in range(L):
for y in range(H):
Rg,Gg,Bg = pix_gauche[x,y] #récupération des composantes R,G,B du pixel de l'image de gauche
Rd,Gd,Bd = pix_droit[x,y] #récupération des composantes R,G,B du pixel de l'image de droite
R = int(0.41*Rg+0.47*Gg+0.16*Bg-0.01*Rd-0.03*Gd)
G = int(-0.04*Rg-0.04*Gg-0.02*Bg+0.38*Rd+0.73*Gd+0.01*Bd)
B = int(-0.05*Rg-0.06*Gg-0.01*Bg-0.06*Rd-0.13*Gd+1.30*Bd)
pix_anaglyphe[x,y] = R,G,B
# on renvoie l'image modifiée
return anaglyphe
# $\;\;\;\;\;$__b. Tester la fonction anaglyphe_precis.__
#
# In[ ]:
# Tester ici la fonction anaglyphe_precis
anaglyphe_precis(image_gauche,image_droite)
# ## 3. Incrustation sur fond vert
#
#
# Le procédé d’incrustation sur fond vert consiste à remplacer tous les pixels de l’image sur fond vert dont la composante verte est « dominante » par rapport aux deux autres par les pixels de l’image du fond à incruster.
#
# ![fond_vert](https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/Illu_incrustation_fond_vert.png)
#
#
#
#
#
- Si vous disposez d'une image sur fond vert et d'une image de paysage (de mêmes type et dimensions), allez à la question 3.1.a.
# - Si vous ne disposez pas d'images, passez directement à la question 3.1.b. pour utiliser les images fournies.
#
#
#
#
# __3.1.a. TELECHARGEMENT DE VOS IMAGES__
# $\;\;\;\;\;\;\;\;$__Exécuter successivement les cellules ci-dessous pour télécharger des images personnelles.__
# $\;\;\;\;\;\;\;\;$__Elles seront stockées respectivement dans les variables fond_vert et paysage.
__
# $\;\;\;\;\;\;\;\;$__Passer ensuite directement à la question 3.2.__
# In[ ]:
#Cellule pour le téléchargement de votre image sur fond vert
from PIL import Image
import ipywidgets as widgets
uploader3 = widgets.FileUpload(accept='image/*',multiple=False)
print("Cliquer pour charger l'image sur fond vert :")
display(uploader3)
# In[ ]:
#Cellule pour la mise en mémoire de votre image sur fond vert
from io import BytesIO
try:
[uploaded_file3] = uploader3.value
fond_vert = Image.open(BytesIO(uploader3.value[uploaded_file3]['content']))
print("Nom: fond_vert","\nFormat:",fond_vert.format,"\nMode:",fond_vert.mode,"\nDimensions:",fond_vert.size)
display(fond_vert)
except:
print("Vous n'avez pas chargé d'image ou son format n'est pas reconnu")
# In[ ]:
#Cellule pour le téléchargement de votre image de paysage
uploader4 = widgets.FileUpload(accept='image/*',multiple=False)
print("Cliquer pour charger l'image de paysage :")
display(uploader4)
# In[ ]:
#Cellule pour la mise en mémoire de votre image de paysage
try:
[uploaded_file4] = uploader4.value
paysage = Image.open(BytesIO(uploader4.value[uploaded_file4]['content']))
print("Nom: paysage","\nFormat:",paysage.format,"\nMode:",paysage.mode,"\nDimensions:",paysage.size)
display(paysage)
except:
print("Vous n'avez pas chargé d'image ou son format n'est pas reconnu")
# __3.1.b. TELECHARGEMENT DES IMAGES FOURNIES__
# $\;\;\;\;\;\;\;\;$__Exécuter la cellule ci-dessous pour télécharger les images fournies.__
# $\;\;\;\;\;\;\;\;$__Elles seront stockées respectivement dans les variables fond_vert et paysage.__
# In[ ]:
# Cellule pour charger les images fournies
from PIL import Image
import requests
from io import BytesIO
fond_vert = Image.open(BytesIO(requests.get('https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/personnage_test.jpg').content))
paysage = Image.open(BytesIO(requests.get('https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/paysage_test.jpg').content))
print("Nom: fond_vert","\nFormat:",fond_vert.format,"\nMode:",fond_vert.mode,"\nDimensions:",fond_vert.size) ; display(fond_vert)
print("Nom: paysage","\nFormat:",paysage.format,"\nMode:",paysage.mode,"\nDimensions:",paysage.size) ; display(paysage)
# __3.2. On souhaite réaliser l'incrustation sur fond vert de la façon suivante :__
# On fixe des coefficients de seuils $C_R=1,3$ et $C_B=1,3$.
# Pour chaque pixel de l’image sur fond vert, si ses composantes $R$, $G$, $B$ vérifient $G>C_R\times R$ et $G>C_B\times B$, alors on récupère le pixel du paysage, sinon on conserve le pixel de l'image sur fond vert.
#
#
# ![fond_vert](https://raw.githubusercontent.com/PythonLycee/PyLyc/master/img/Compo/Illu_incrustation_fond_vert.png)
#
#
# $\;\;\;\;\;$__a. Écrire la fonction Python incrustation qui convient.__
# In[ ]:
# Écrire ici la fonction incrustation
def incrustation(fond_vert,paysage,CR=1.3,CB=1.3):
"""
fonction qui réalise l'incrustation de l'image sur fond vert dans le paysage
"""
# vérification que les images sont de même format et taille
if (fond_vert.format,fond_vert.mode,fond_vert.size) != (paysage.format,paysage.mode,paysage.size): return "Images incompatibles"
# récupération des dimensions des images originales
L,H = fond_vert.size
# création d'une image vierge, de même format et même taille que les images initiales
im_incrust = Image.new( mode=fond_vert.mode , size=(L,H) )
# ouverture de l'accès aux pixels des images
pix_fond_vert = fond_vert.load()
pix_paysage = paysage.load()
pix_incrust = im_incrust.load()
# on parcourt tous les pixels des images
for x in range(L):
for y in range(H):
Rv,Gv,Bv = pix_fond_vert[x,y] #récupération des composantes R,G,B du pixel original de l'image sur fond vert
Rp,Gp,Bp = pix_paysage[x,y] #récupération des composantes R,G,B du pixel original de l'image paysage
if Gv > CR*Rv and Gv > CB*Bv:
pix_incrust[x,y] = Rp,Gp,Bp
else:
pix_incrust[x,y] = Rv,Gv,Bv
# on renvoie l'image modifiée
return im_incrust
# $\;\;\;\;\;$__b. Tester la fonction incrustation.__
# $\;\;\;\;\;\;\;\;$__Si nécessaire, on pourra modifier les valeurs des coefficients de seuil $C_R$ et $C_B$.__
# In[ ]:
# Tester ici la fonction incrustation
incrustation(fond_vert,paysage)
# © Copyright Franck CHEVRIER 2019-2021 https://www.python-lycee.com.
# Les activités partagées sur Capytale sont sous licence Creative Commons.