Skip to content

Instantly share code, notes, and snippets.

@jeanpat
Last active July 21, 2022 12:55
Show Gist options
  • Save jeanpat/f194e1e6c3ef38a172e21e0d16b4db85 to your computer and use it in GitHub Desktop.
Save jeanpat/f194e1e6c3ef38a172e21e0d16b4db85 to your computer and use it in GitHub Desktop.
Comment peut-on analyser une image sous l'angle statistique? Une application: le filtrage médian.
Display the source blob
Display the rendered blob
Raw
{"cells":[{"metadata":{},"cell_type":"markdown","source":"**Importer les modules ci-dessous**"},{"metadata":{"trusted":false},"cell_type":"code","source":"import numpy as np\nfrom scipy import ndimage as nd\nfrom imageio import imread\nfrom matplotlib import pyplot as plt","execution_count":4,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 1- Image numérique et pixels \nles pixels d'une images sont codés par des nombres entiers entre 0 et 255 ($2^8 -1$):\n* noir :0\n* blanc:255\n\nToutes les nuances de gris sont données par des valeurs comprises entre 0 et 255.\n \n<figure> \n <img title='Une image est un tableau de nombres' \n src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgiyX1pRqnEMNH3_l8ESLHucyGelSQK1oEOYZc-3XHUihPI3nmY5dapiJHSlfEHY29LeQ864zx8VrF-nKdPVGdROP46TEcR-zMnuJ73Nr319JvMUb6Km3c4TsRrG6KW9Gl9YLlkMaPVouLLHzzpjA_6AryseRW9mV2Di5-m1TnU9BxOePd537bGfi2wBw/s704/imagematrix.png'\n width='700px' >\n <figcaption style=\"text-align: center; font-size: x-small;\" >Une image est un tableau de nombres</figcaption>\n</figure>"},{"metadata":{},"cell_type":"markdown","source":"## 1.1 Profil des niveau de gris le long d'une ligne de pixel (Densitogramme):\nUne image en niveau de gris est un tableau de nombres. On peut atteindre chaque pixel un par un, ligne par ligne, ou colonne par colonne.\nExécuter la cellule ci-dessous pour *construire* une ligne rouge sur l'image."},{"metadata":{"trusted":false},"cell_type":"code","source":"lena = imread('LenaBW.png')\nligne275 = lena[275 , :]\n\nred = imread('LenaBW.png')\nblue = imread('LenaBW.png')\ngreen = imread('LenaBW.png')\n\n# on met au maximum (255) la composante rouge de la ligne 275\n# on met au minimum (0) la composante bleue et verte de la ligne 275\nred[275, :] = 255\nblue[275, :] = 0\ngreen[275, :] = 0\n\nRGB = np.stack((red,blue, green), axis=2)","execution_count":33,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"plt.figure(figsize=(12,4))\n\nplt.subplot(121)\nplt.title('ligne 275')\nplt.imshow(RGB)\n\nplt.subplot(122)\nplt.title('Niveaux de gris le long de la ligne 275 (rouge)')\nplt.plot(ligne275)\n\nplt.show()","execution_count":34,"outputs":[{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"**Modifier le code ci-dessous pour tracer le profil de niveau de gris de la colonne 350**\n\nVous modifierez les pointillés ... de manière adéquate."},{"metadata":{"trusted":false},"cell_type":"code","source":"lena = imread('LenaBW.png')\ncolonne_350 = lena[:, ...]\n\nplt.subplot(111)\nplt.title('Niveaux de gris le long de la colonne 350')\nplt.plot(colonne_350)\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## 1.2 Diagramme en bâtons des niveaux de gris d'une image:\nC'est le diagramme en bâtons des niveaus de gris d'une image. On peut réaliser ce diagramme:\n * sur l'image entière\n * sur une ligne de pixels de l'image (ici la ligne 275, en rouge)\nles pixels de la ligne 275 de l'image originale de Léna sont dans la variable **densito** (un tableau à une ligne et à 515 colonnes, sauf erreur)."},{"metadata":{},"cell_type":"markdown","source":"### 1.2-a Exécuter la cellule ci-dessous pour afficher l'image avec une ligne rouge et le densitogramme correspondant"},{"metadata":{"trusted":false},"cell_type":"code","source":"#https://datacarpentry.org/image-processing/05-creating-histograms/\n\neffectif, valeur_gris = np.histogram(lena, bins=256, range=(0, 255))\n# configure et trace le diagramme en bâtons\nplt.figure(figsize=(12,4))\nplt.title(\"Diagramme en bâtons des niveaux de gris (image entière)\")\nplt.xlabel(\"niveau de gris\")\nplt.ylabel(\"effectif\")\nplt.xlim([0, 255]) # <- named arguments do not work here\n\nplt.bar(valeur_gris[0:-1], effectif) # <- or here\nplt.show()","execution_count":35,"outputs":[{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"### 1.2-b Compléter le code ci-dessous pour obtenir le diagramme en bâtons correspondant à la ligne rouge uniquement:\nVous remplacerez les pointillés par la bonne variable:"},{"metadata":{"trusted":false},"cell_type":"code","source":"effectif, valeur_gris = np.histogram(.........., bins=256, range=(0, 255))\n# configure and draw the histogram figure\nplt.figure(figsize=(12,4))\nplt.title(\"Diagramme en bâtons des niveaux de gris (image entière)\")\nplt.xlabel(\"niveau de gris\")\nplt.ylabel(\"effectif\")\nplt.xlim([0, 255]) # <- named arguments do not work here\n\nplt.bar(valeur_gris[0:-1], effectif) # <- or here\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Images bruitées:\nChargeons et affichons deux versions dégradées de l'image originale:"},{"metadata":{"trusted":false},"cell_type":"code","source":"saltPepper = imread('LenaSaltPepper.png')\nnoisy = imread('Lena_noisy.png')","execution_count":38,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Afffichons les. Il est possible ensuite de zoomer sur les différentes parties des images. On pourra en particulier zoomer sur les yeux, qui sont d'intérressantes régions comportant de transitions noir/blanc."},{"metadata":{"trusted":false},"cell_type":"code","source":"plt.figure(figsize=(12,4))\n\nplt.subplot(131)\nplt.title(\"lena\")\nplt.imshow(lena,cmap=\"gray\")\n\nplt.subplot(132)\nplt.title(\"lena poivre et sel\")\nplt.imshow(saltPepper,cmap=\"gray\")\n\nplt.subplot(133)\nplt.title(\"lena bruitée\")\nplt.imshow(noisy,cmap=\"gray\")\nplt.show()","execution_count":7,"outputs":[{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"# Diagramme en boîte: \n## Quel est l'effet du bruitage sur les paramètres statistiques d'une image?\n\n * le bruit influence t-til les paramètres de position? \n * le bruit influence-t-il les paramètres de dispersion?\n\nPour répondre à cette question, traçons les diagrammes en boite de ces trois images:\nPour accélérer le traitement, on ne va garder qu'un pixel sur quatre pour obtenir une image seize fois plus petite:\n```Python\nsmallerlena = lena[::4,::4]\n```\nensuite, on transforme le tableau en liste de type numpy.array:\n```Python\nflatlena = smallerlena.flatten()\n```\nPuis, on devra encore convertir cette liste en objet de type list pour pouvoir tracer le diagramme en boîte avec:\n```Python\nflatlena.tolist()\n```\n\n"},{"metadata":{"trusted":false},"cell_type":"code","source":"smallerlena = lena[::4,::4]\nflatlena = smallerlena.flatten()\n\nplt.figure()\nplt.subplot(121)\nplt.imshow(smallerlena)\n\nplt.subplot(122)\nplt.boxplot(flatlena.tolist())\nplt.show()","execution_count":28,"outputs":[{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"## Traçons les diagrammes en boîte des niveaux de gris de chacune des trois images"},{"metadata":{"trusted":false},"cell_type":"code","source":"flat_ln = flatlena.tolist()\n\nsmaller_sp = saltPepper[::4,::4]\nflat_sp = smaller_sp.flatten().tolist()\n\nsmaller_ns = noisy[::4,::4]\nflat_ns = smaller_ns.flatten().tolist()\n\n#print(type(flat_ln), type(flat_sp), type(flat_ns))\nplt.figure()\nplt.boxplot([flat_ln, flat_sp, flat_ns])\nplt.show()","execution_count":31,"outputs":[{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"## Diagrammes en boite des niveaux de gris de différentes parties de l'image:"},{"metadata":{"trusted":false},"cell_type":"code","source":"lignes_1 = slice(120,145)\ncolonnes_1 = slice(250,275)\nchapeau = lena[lignes_1,colonnes_1 ]\n\nlignes_2 = slice(370,395)\ncolonnes_2 = slice(180,205)\ncheveux = lena[lignes_2,colonnes_2 ]\n\nlignes_3 = slice(270,295)\ncolonnes_3 = slice(260,285)\noeilDroit = lena[lignes_3,colonnes_3 ]","execution_count":9,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Trois sous domaines de dimensions $25x25$ de l'image:\n\nOn affiche les trois domaines en niveau de gris. Puis les trois mêmes images sont affichées en fausse couleur avec une échelle de niveau de gris sur le côté."},{"metadata":{"trusted":false},"cell_type":"code","source":"plt.figure()\n\nplt.subplot(231, xticks= [], yticks=[])\nplt.title('chapeau')\nplt.imshow(chapeau, cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(232, xticks= [], yticks=[])\nplt.title('cheveux')\nplt.imshow(cheveux, cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(233, xticks= [], yticks=[])\nplt.title('Oeil droit')\nplt.imshow(oeilDroit, cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(234, xticks= [], yticks=[])\nplt.title('chapeau')\nplt.imshow(chapeau, cmap=\"hsv\", vmin=0, vmax=255)\nplt.colorbar()\n\nplt.subplot(235, xticks= [], yticks=[])\nplt.title('cheveux')\nplt.imshow(cheveux, cmap=\"hsv\", vmin=0, vmax=255)\nplt.colorbar()\n\nplt.subplot(236, xticks= [], yticks=[])\nplt.title('Oeil droit')\nplt.imshow(oeilDroit, cmap=\"hsv\", vmin=0, vmax=255)\nplt.colorbar()\n\n\nplt.show()","execution_count":26,"outputs":[{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"Dans la cellules ci dessous, remplacer les pointillés .......... pour tracer les diagrammes en boîte correspondant à chacun des trois sous domaines : *chapeau*, *cheveux* et *oeilDroit*:"},{"metadata":{"trusted":false},"cell_type":"code","source":"#On modifie les tableaux des partion d'image en liste\npixels_chapeau = chapeau.flatten().tolist()\npixels_cheveux = cheveux.flatten().tolist()\npixels_oeilDroit = oeilDroit.flatten().tolist()\n\ndata = [pixels_chapeau, ...... , .......]\n\nplt.figure()\nplt.title(\"Distribution des niveau de gris de trois domaines de l'image Léna\")\nplt.boxplot(data)\nplt.show()","execution_count":30,"outputs":[{"output_type":"stream","text":"<input>:8: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n","name":"stderr"},{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{},"cell_type":"markdown","source":"# Filtrage d'image et statistiques"},{"metadata":{},"cell_type":"markdown","source":"En zoomant sur les images, comment justifier le titre de l'image centrale?\n\n**Double cliquer cette cellule** et répondre sur les pointillés ci-dessous:\n\n + A quoi correspond le sel dans l'image? ...................................................\n \n + A quoi correspond le poivre dans l'image? ...................................................\n "},{"metadata":{"trusted":false},"cell_type":"code","source":"zoom_sp = saltPepper[250:292,240:285]\nzoom2_sp = saltPepper[276:281,274:279]\narray_sp = zoom2_sp.flatten()\n\nzoom = lena[250:292,240:285]\nzoom2 = lena[276:281,274:279]\narray_lena = zoom2.flatten()\n\nzoom_ns = noisy[250:292,240:285]\nzoom2_ns = noisy[276:281,274:279]\narray_ns = zoom2_ns.flatten()","execution_count":41,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"plt.figure(figsize=(12,4))\n\nplt.subplot(231)\nplt.imshow(zoom,cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(232)\nplt.imshow(zoom_sp,cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(233)\nplt.imshow(zoom_ns,cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(234)\nplt.imshow(zoom2,cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(235)\nplt.imshow(zoom2_sp,cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(236)\nplt.imshow(zoom2_ns,cmap=\"gray\", vmin=0, vmax=255)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Affichons les tableaux des valeurs des pixels"},{"metadata":{"trusted":false},"cell_type":"code","source":"print(\"lena\")\nprint(zoom2)\nprint()\n\nprint(\"lena poivre sel\")\nprint(zoom2_sp)\nprint()\n\nprint(\"lena bruitée\")\nprint(zoom2_ns)\nprint()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Regardons les valeurs des pixels d'une zone de chacune des trois images en affichant la valeur des pixels du coin supérieur gauche au coin inférieur droit du domaine de l'image (ici un carré de dimension $25 \\times 25$) sous forme de liste:\n* originale (lena)\n* image bruitée noir et blanc 'salt pepper)\n* image très bruitée (noisy)"},{"metadata":{"trusted":false},"cell_type":"code","source":"print(\"lena\",array_lena)\nprint()\nprint(\"lena poivre sel\",array_sp)\nprint()\nprint(\"lena bruitée\",array_ns)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Déterminer à la main la valeur mediane du niveau de gris des pixels:\n### combien y-a-t-il de pixels noir et blanc dans la liste des pixels de l'image Léna?\n"},{"metadata":{"trusted":false},"cell_type":"code","source":"len(array_lena)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### vérifier la mediane en triant les valeurs par ordre croissant"},{"metadata":{"trusted":false},"cell_type":"code","source":"array_lena.sort()\narray_lena","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"raw","source":"Quelle valeur trouvez-vous? ...............................................\n\n\n"},{"metadata":{},"cell_type":"markdown","source":"#### en copiant et modifiant le code ci-dessus, trouver la valeur médiane des pixels de lena poivre et sel:"},{"metadata":{"trusted":false},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### Dans le domaine de la version poivre-et-sel de Léna, que se passe-t-il si on remplace le pixel central par un pixel dont la valeur est la valeur médiane du niveau de gris des pixel de la région zoommée?"},{"metadata":{},"cell_type":"raw","source":".............................................."},{"metadata":{},"cell_type":"markdown","source":"### retrouver directement la valeur médiane du niveau de gris des pixels\nLe code ci-dessous permet de trouver la valeur médiane des pixel de ce morceau de l'image"},{"metadata":{"trusted":false},"cell_type":"code","source":"rang_mediane = 1+len(array_lena)//2\narray_lena[rang_mediane]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#### en copiant et modifiant ce code ci-dessus, vérifier la valeur médiane des pixels de lena poivre et sel:"},{"metadata":{"trusted":false},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Filtrage median d'une image:"},{"metadata":{"trusted":false},"cell_type":"code","source":"lena_median = nd.median_filter(lena, size=(5,5)) ","execution_count":36,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"plt.figure(figsize =(12,5))\nplt.subplot(131)\nplt.title(\"lena originale\")\nplt.imshow(lena_median, cmap=\"gray\")\n\nplt.subplot(132)\nplt.title(\"lena poivre sel\")\nplt.imshow(saltPepper, cmap=\"gray\")\n\nplt.subplot(133)\nplt.title(\"lena bruitée filtre median\")\nplt.imshow(lena_median, cmap=\"gray\")\nplt.show()","execution_count":57,"outputs":[{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{"trusted":false},"cell_type":"code","source":"zoom_sp_median = nd.median_filter(zoom_sp, size=(5,5))\nzoom2_sp_median = nd.median_filter(zoom2_sp, size=(5,5))","execution_count":46,"outputs":[]},{"metadata":{"trusted":false},"cell_type":"code","source":"plt.subplot(231, xticks=[], yticks=[])\nplt.title(\"lena originale\")\nplt.imshow(zoom, cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(232, xticks=[], yticks=[])\nplt.title(\"lena poivre sel\")\nplt.imshow(zoom_sp, cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(233, xticks=[], yticks=[])\nplt.title(\"lena bruitée filtre median\")\nplt.imshow(zoom_sp_median, cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(234, xticks=[], yticks=[])\nplt.title(\"lena originale\")\nplt.imshow(zoom2, cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(235, xticks=[], yticks=[])\nplt.title(\"lena poivre sel\")\nplt.imshow(zoom2_sp, cmap=\"gray\", vmin=0, vmax=255)\n\nplt.subplot(236, xticks=[], yticks=[])\nplt.title(\"lena bruitée filtre median\")\nplt.imshow(zoom2_sp_median, cmap=\"gray\", vmin=0, vmax=255)\nplt.show()","execution_count":50,"outputs":[{"output_type":"stream","text":"<input>:13: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.\n<input>:17: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.\n<input>:21: MatplotlibDeprecationWarning: Adding an axes using the same arguments as a previous axes currently reuses the earlier instance. In a future version, a new instance will always be created and returned. Meanwhile, this warning can be suppressed, and the future behavior ensured, by passing a unique label to each axes instance.\n","name":"stderr"},{"output_type":"display_data","data":{"application/javascript":"element.append(window._basthonDomNodeBus.pop(0));"},"metadata":{}}]},{"metadata":{"trusted":false},"cell_type":"code","source":"print(\"lena\",zoom2)\nprint()\nprint(\"lena poivre sel\",zoom2_sp)\nprint(\"lena filtre median\")\nprint(zoom2_sp_median)","execution_count":53,"outputs":[{"output_type":"stream","text":"lena [[201 193 190 175 153]\n [208 198 197 174 136]\n [214 198 190 160 117]\n [196 180 162 143 118]\n [170 163 156 154 144]]\n\nlena poivre sel [[201 193 190 175 153]\n [208 198 197 174 136]\n [214 198 255 0 117]\n [196 180 162 143 118]\n [170 163 156 154 144]]\nlena filtre median\n[[198 198 193 174 174]\n [198 196 190 162 153]\n [196 193 174 154 153]\n [180 170 163 154 144]\n [180 170 162 144 144]]\n","name":"stdout"}]},{"metadata":{"trusted":false},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3","language":"python"}},"nbformat":4,"nbformat_minor":2}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment