{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "![En tête](img/En_tete_general.png)\n", "\n", "\n", "*(C) Copyright Franck CHEVRIER 2019-2020 http://www.python-lycee.com/*\n", "\n", " Pour exécuter une saisie Python, sélectionner la cellule et valider avec SHIFT+Entrée.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Composition d'images\n", "\n", "### Activité sur le traitement d'images n°2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Le but de cette activité est d'apprendre à composer une nouvelles image à partir de deux images initiales.
\n", "Cette activité fait suite à l'activité sur les traitements d'images n°1 (Application de filtres).\n", "
\n", "Dans chacun des cas, les images qui seront composées entre elles auront les mêmes dimensions.\n", "\n", "\n", "### Sommaire\n", "\n", "1. Superposition d'images
\n", "2. Réalisation d'un anaglyphe
\n", "3. Incrustation sur fond vert
\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Superposition d'images\n", "\n", "Dans cette partie, on souhaite obtenir une nouvelle image par superposition de deux images." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1.1. Exécuter les cellules ci-dessous, qui permettent chacune :\n", "- d'ouvrir un fichier et de stocker l'image dans un objet Python de type Image;\n", "- d'afficher le format, le type de codage et la dimension de l'image;\n", "- d'afficher l'image.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "# import du module permettant la gestion des images\n", "from PIL import Image\n", "\n", "#ouverture de l'image 1\n", "Im1 = Image.open('img/Compo/oiseau.jpg')\n", "\n", "#affichage du format, du type et de la dimension de l'image 2\n", "print(\"Nom: Im1\",\"\\nFormat:\",Im1.format,\"\\nMode:\",Im1.mode,\"\\nDimensions:\",Im1.size) ; \n", "\n", "#affichage de l'image\n", "Im1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "\n", "#ouverture de l'image 2\n", "Im2 = Image.open('img/Compo/montagne.jpg')\n", "\n", "#affichage du format, du type et de la dimension de l'image 2\n", "print(\"Nom: Im2\",\"\\nFormat:\",Im2.format,\"\\nMode:\",Im2.mode,\"\\nDimensions:\",Im2.size) ; \n", "\n", "#affichage de l'image\n", "Im2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__1.2. Superposition par saturation.__
\n", "$\\;\\;\\;\\;\\;$__On donne la fonction Python sup_saturation ci-dessous.__
\n", "$\\;\\;\\;\\;\\;$__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).__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Quel sera le code R,G,B du pixel de l'image obtenue?__
\n", "$\\;\\;\\;\\;\\;$__b. Exécuter les deux cellules ci-dessous pour tester la fonction sup_saturation.__
\n", "$\\;\\;\\;\\;\\;$__c. Que peux-t-on dire de la luminosité de l'image obtenue par rapport à celles des images originales?__\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def sup_saturation(im_or1,im_or2):\n", " \"\"\"\n", " fonction qui superpose deux images par saturation\n", " \"\"\"\n", " \n", " # vérification que les images sont de même format et taille\n", " if (im_or1.format,im_or1.mode,im_or1.size) != (im_or2.format,im_or2.mode,im_or2.size): return \"Images incompatibles\"\n", " \n", " # récupération des dimensions des images originales\n", " L,H = im_or1.size\n", " \n", " # création d'une image vierge, de même format et même taille que les images initiales\n", " im_composee = Image.new( mode=im_or1.mode , size=(L,H) )\n", " \n", " # ouverture de l'accès aux pixels des images \n", " pix_or1 = im_or1.load()\n", " pix_or2 = im_or2.load()\n", " pix_composee = im_composee.load()\n", " \n", " # on parcourt tous les pixels des images\n", " for x in range(L):\n", " for y in range(H):\n", " R1,G1,B1 = pix_or1[x,y] #récupération des composantes R,G,B du pixel original de l'image originale im_or1\n", " R2,G2,B2 = pix_or2[x,y] #récupération des composantes R,G,B du pixel original de l'image originale im_or2\n", " \n", " R = R1+R2\n", " G = G1+G2\n", " B = B1+B2\n", " \n", " pix_composee[x,y] = R,G,B #écriture des composantes R,G,B du pixel modifié\n", " \n", " # on renvoie l'image modifiée\n", " return im_composee\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "sup_saturation(Im1,Im2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__1.3. Superposition par maximum.__
\n", "$\\;\\;\\;\\;\\;$__On souhaite construire les composantes des pixels de la nouvelle image en prenant la plus grande des composantes des deux images.__
\n", "$\\;\\;\\;\\;\\;$__Écrire la fonction Python sup_max qui convient.__
\n", "$\\;\\;\\;\\;\\;$Aide : On peut utiliser la fonction Python max pour le calcul d'un maximum.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Écrire ici la fonction sup_max\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "# Tester ici un appel à la fonction sup_max\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__1.4. Superposition par la moyenne.__
\n", "$\\;\\;\\;\\;\\;$__On souhaite construire les composantes des pixels de la nouvelle image par calculs des moyennes des composantes des pixels initiaux.__
\n", "$\\;\\;\\;\\;\\;$__Écrire la fonction Python sup_moyenne qui convient.__ \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Écrire ici la fonction sup_moyenne\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tester ici la fonction sup_moyenne\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Réalisation d'un anaglyphe\n", "\n", "
\n", "Un anaglyphe est une image permettant de donner l'illusion de la 3ème dimension à l'aide de lunettes à filtres bleu-rouge.
\n", "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).\n", "
\n", "\n", "![anaglyphe](img/Compo/Illu_anaglyphe.png)\n", "\n", "\n", "

\n", "\n", "
- Si vous disposez de deux images (de mêmes type et dimensions), allez à la question 2.1.a.

\n", "- Si vous ne disposez pas d'images, passez directement à la question 2.1.b. pour utiliser les images fournies.\n", "
\n", "

\n", "

\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__2.1.a. TELECHARGEMENT DE VOS IMAGES__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Exécuter successivement les cellules ci-dessous pour télécharger des images personnelles.__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Elles seront stockées respectivement dans les variables image_gauche et image_droite.
__\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Passer ensuite directement à la question 2.2.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Cellule pour le téléchargement de votre image de gauche\n", "from PIL import Image\n", "import ipywidgets as widgets\n", "\n", "uploader1 = widgets.FileUpload(accept='image/*',multiple=False)\n", "print(\"Cliquer pour charger l'image de gauche :\")\n", "display(uploader1)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Cellule pour la mise en mémoire de votre image de gauche\n", "from io import BytesIO\n", "try:\n", " [uploaded_file1] = uploader1.value\n", " image_gauche = Image.open(BytesIO(uploader1.value[uploaded_file1]['content']))\n", " print(\"Nom: image_gauche\",\"\\nFormat:\",image_gauche.format,\"\\nMode:\",image_gauche.mode,\"\\nDimensions:\",image_gauche.size)\n", " display(image_gauche)\n", "except:\n", " print(\"Vous n'avez pas chargé d'image ou son format n'est pas reconnu\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Cellule pour le téléchargement de votre image de droite\n", "\n", "uploader2 = widgets.FileUpload(accept='image/*',multiple=False)\n", "print(\"Cliquer pour charger l'image de droite :\")\n", "display(uploader2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Cellule pour la mise en mémoire de votre image de droite\n", "\n", "try:\n", " [uploaded_file2] = uploader2.value\n", " image_droite = Image.open(BytesIO(uploader2.value[uploaded_file2]['content']))\n", " print(\"Nom: image_droite\",\"\\nFormat:\",image_droite.format,\"\\nMode:\",image_droite.mode,\"\\nDimensions:\",image_droite.size)\n", " display(image_droite)\n", "except:\n", " print(\"Vous n'avez pas chargé d'image ou son format n'est pas reconnu\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__2.1.b. TELECHARGEMENT DES IMAGES FOURNIES__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Exécuter la cellule ci-dessous pour télécharger les images fournies.__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Elles seront stockées respectivement dans les variables image_gauche et image_droite.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "# Cellule pour charger les images fournies\n", "image_gauche = Image.open('img/Compo/test_gauche.jpg') \n", "image_droite = Image.open('img/Compo/test_droite.jpg') \n", "print(\"Nom: image_gauche\",\"\\nFormat:\",image_gauche.format,\"\\nMode:\",image_gauche.mode,\"\\nDimensions:\",image_gauche.size) ; display(image_gauche) \n", "print(\"Nom: image_droite\",\"\\nFormat:\",image_droite.format,\"\\nMode:\",image_droite.mode,\"\\nDimensions:\",image_droite.size) ; display(image_droite) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__2.2. Anaglyphe rapide : On souhaite réaliser l'anaglyphe de la façon suivante :__

\n", "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. \n", "\n", "\n", "![anaglyphe](img/Compo/Illu_anaglyphe_2.png)\n", "\n", "\n", "$\\;\\;\\;\\;\\;$__a. Écrire la fonction Python anaglyphe_rapide qui convient.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Écrire ici la fonction anaglyphe_rapide\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$\\;\\;\\;\\;\\;$__b. Tester la fonction anaglyphe_rapide.__
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "# Tester ici la fonction anaglyphe_rapide\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__2.3. Anaglyphe précis :__
\n", "\n", "On souhaite diminuer l'altération des couleurs de l'anaglyphe réalisé.
\n", "Pour cela, on calcule les composantes R,G,B du pixel de l'anaglyphe à l'aide du tableau suivant.
\n", "\n", "| 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}$ |\n", "|:--------------------:|:----:|:-----:|:-----:|:-----:| |:-----:|:-----:|:-----:|\n", "| $\\color{red}{R}$ |$\\;\\;$| $41$% | $47$% | $16$% | |$-1$% | $-3$% | $0$% |\n", "| $\\color{green}{G}$ |$\\;\\;$| $-4$% | $-4$% | $-2$% | |$38$% | $73$% | $1$% | \n", "| $\\color{blue}{B}$ |$\\;\\;$| $-5$% | $-6$% | $1$% | |$-6$% | $-13$%| $130$%| \n", "\n", "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).\n", "\n", "\n", "\n", "\n", "$\\;\\;\\;\\;\\;$__a. Écrire la fonction Python anaglyphe_precis qui convient.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Écrire ici la fonction anaglyphe_precis\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$\\;\\;\\;\\;\\;$__b. Tester la fonction anaglyphe_precis.__
\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "# Tester ici la fonction anaglyphe_precis\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. Incrustation sur fond vert\n", "\n", "
\n", "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.
\n", "\n", "![fond_vert](img/Compo/Illu_incrustation_fond_vert.png)\n", "\n", "\n", "

\n", "\n", "
- 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.

\n", "- Si vous ne disposez pas d'images, passez directement à la question 3.1.b. pour utiliser les images fournies.\n", "
\n", "

\n", "

\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__3.1.a. TELECHARGEMENT DE VOS IMAGES__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Exécuter successivement les cellules ci-dessous pour télécharger des images personnelles.__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Elles seront stockées respectivement dans les variables fond_vert et paysage.
__\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Passer ensuite directement à la question 3.2.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "#Cellule pour le téléchargement de votre image sur fond vert\n", "from PIL import Image\n", "import ipywidgets as widgets\n", "\n", "uploader3 = widgets.FileUpload(accept='image/*',multiple=False)\n", "print(\"Cliquer pour charger l'image sur fond vert :\")\n", "display(uploader3)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "#Cellule pour la mise en mémoire de votre image sur fond vert\n", "from io import BytesIO\n", "try:\n", " [uploaded_file3] = uploader3.value\n", " fond_vert = Image.open(BytesIO(uploader3.value[uploaded_file3]['content']))\n", " print(\"Nom: fond_vert\",\"\\nFormat:\",fond_vert.format,\"\\nMode:\",fond_vert.mode,\"\\nDimensions:\",fond_vert.size)\n", " display(fond_vert)\n", "except:\n", " print(\"Vous n'avez pas chargé d'image ou son format n'est pas reconnu\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "#Cellule pour le téléchargement de votre image de paysage\n", "\n", "uploader4 = widgets.FileUpload(accept='image/*',multiple=False)\n", "print(\"Cliquer pour charger l'image de paysage :\")\n", "display(uploader4)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Cellule pour la mise en mémoire de votre image de paysage\n", "\n", "try:\n", " [uploaded_file4] = uploader4.value\n", " paysage = Image.open(BytesIO(uploader4.value[uploaded_file4]['content']))\n", " print(\"Nom: paysage\",\"\\nFormat:\",paysage.format,\"\\nMode:\",paysage.mode,\"\\nDimensions:\",paysage.size)\n", " display(paysage)\n", "except:\n", " print(\"Vous n'avez pas chargé d'image ou son format n'est pas reconnu\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__3.1.b. TELECHARGEMENT DES IMAGES FOURNIES__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Exécuter la cellule ci-dessous pour télécharger les images fournies.__
\n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Elles seront stockées respectivement dans les variables fond_vert et paysage.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": false }, "outputs": [], "source": [ "# Cellule pour charger les images fournies\n", "fond_vert = Image.open('img/Compo/personnage_test.jpg') \n", "paysage = Image.open('img/Compo/paysage_test.jpg')\n", "print(\"Nom: fond_vert\",\"\\nFormat:\",fond_vert.format,\"\\nMode:\",fond_vert.mode,\"\\nDimensions:\",fond_vert.size) ; display(fond_vert) \n", "print(\"Nom: paysage\",\"\\nFormat:\",paysage.format,\"\\nMode:\",paysage.mode,\"\\nDimensions:\",paysage.size) ; display(paysage) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__3.2. On souhaite réaliser l'incrustation sur fond vert de la façon suivante :__\n", "
  • On fixe des coefficients de seuils $C_R=1,3$ et $C_B=1,3$.
  • \n", "
  • 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.
  • \n", "
    \n", "\n", "![fond_vert](img/Compo/Illu_incrustation_fond_vert.png)\n", "\n", "\n", "$\\;\\;\\;\\;\\;$__a. Écrire la fonction Python incrustation qui convient.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Écrire ici la fonction incrustation\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$\\;\\;\\;\\;\\;$__b. Tester la fonction incrustation.__
    \n", "$\\;\\;\\;\\;\\;\\;\\;\\;$__Si nécessaire, on pourra modifier les valeurs des coefficients de seuil $C_R$ et $C_B$.__" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Tester ici la fonction incrustation\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*(C) Copyright Franck CHEVRIER 2019-2020 http://www.python-lycee.com/*\n" ] } ], "metadata": { "celltoolbar": "Raw Cell Format", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.6" } }, "nbformat": 4, "nbformat_minor": 2 }