#!/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.