---

    settings:
        enabled_extensions:
            - default
            - extra
            - tables
            - tasklist
            - codehilite(linenums=true)
---
<style>
body{
    max-width: 1000px;
    width: 95%;
    margin-bottom: 60vh;
}
h1 {
    counter-reset: countA;
    text-align: center;
    color: #004335;
    background-color: #EDFFFF;
    padding-top: 10px;
    border-top: 5px solid #EEEEEE !important;
    border-bottom: 5px solid #EEEEEE !important;
    margin-top: 3em !important;
    left: -30px;
    width: calc(100% + 60px);
}
.markdown-body>h1:first-of-type{
    margin-top: 0px !important;
    padding: 20px;
    font-size: 3em;
    top: -30px;
    border-top: none !important;
}
h1 .headeranchor-link{
    margin-left: 0px !important;
}
h2 {
    counter-reset: countB;
    color: #004335;
    margin-top: 2em !important;
    left: -15px;
    width: calc(100% + 30px);
}
h2 .headeranchor-link{
    margin-left: -20px !important;
}
h3 { counter-reset: countC; }
h3 { counter-reset: countD; }
h1::before, h1::after {content: " - ";}
h2::before {
    content: counter(countA) ". ";
    counter-increment: countA;
}
h3::before {
    content: counter(countA) "-" counter(countB) ". ";
    counter-increment: countB;
}
h4::before {
    content: counter(countA) "-" counter(countB) "-" counter(countC) ". ";
    counter-increment: countC;
}
h5::before {
    content: counter(countA) "-" counter(countB) "-" counter(countC) "-" counter(countD) ". ";
    counter-increment: countD;
}
info, good, warn, err{
    border-left: 4px solid #000;
    padding: 5px;
    padding-left: 15px;
    display: inline-block;
}

info {    
    background-color: #E8FAFF;
    border-left-color: #8BE8FF;
}
good {    
    background-color: #E8FFEA;
    border-left-color: #6DFF7B;
}
warn {    
    background-color: #FFF5EB;
    border-left-color: #FFE28B;
}
err {    
    background-color: #fceded;
    border-left-color: #dfb5b4;
}
.toc{
    margin-left: 5%;
    padding-left: 5%;
    border-left: 5px solid #EEEEEE;
}
.toc>ul:first-child>li:first-child{
    display: none;
}
.linenos{
    color: #BBB;
    padding: 0px;
    border-right: 4px solid #EEE !important;
}
.linenos pre{
    padding-right: 5px;
}
.suppr{
    display: none;
    content: "";
}
todo::before{
    color: #F00;
    content: "TODO";
    background-color: #0FF;
    font-weight: bold;
    padding: 2px;
    margin-right: 5px;
}

.codehilite pre{
    background-color: #272822;
}
.hidden{
    display: none;
}

img{
    width: 70%;
}
.dual, .quad{
    text-align: center;
}
.dual img{
    max-width: calc(100% / 2 - 10px);
    margin: 5px;
}
.quad img{
    max-width: calc(50% / 2 - 10px);
    margin: 5px;
}

</style>

# TP 2 ImageJ : Filtrage, Contours, Morphologie Mathématique

__Thomas ABOT__
__Thibaut CHARLES__


<div class="hidden">
    katia.charriere@telecom-bretagne.eu
</div>
[TOC]

Partie I : Filtrage spatial, Contours
===============================================================================

Exercice 1 : Filtrage linéaire bidimensionnel non récursif dans le domaine spatial
-------------------------------------------------------------------------------

### Filtres
#### Smooth
<span class="dual">
![](moly_orig.PNG)![](moly_smooth.PNG)
![](freq_moly_orig.PNG)![](freq_moly_smooth.PNG)
</span>
L'image est bien "adoucie" (_smooth_), on note que les fréquences élevées sont filtrées.

#### Sharpen
<span class="dual">
![](moly_orig.PNG)![](moly_sharpen.PNG)
![](freq_moly_orig.PNG)![](freq_moly_sharpen.PNG)
</span>
On a ici rendu l'image plus "affûtée" (_sharpen_), on distingue mieux les contours : en effet, les hautes fréquences sont plus présentes que dans l'image originale. 

#### Shadows
<span class="dual">
![](moly_orig.PNG)![](moly_shadow.PNG)
![](freq_moly_orig.PNG)![](freq_moly_shadow.PNG)
</span>
A la manière de la fonction _sharpen_, des hautes fréquences sont ajoutées. A cela s'ajoute l'apparition d'ombres au niveau des changements de couleur (zones responsables des hautes fréquences de l'image)

#### Convolution

##### Test / Vérification
<span class="dual">
![](TestConvolve_orig.PNG)![](TestConvolve_customkernel.PNG)
</span>
La convolution est correcte : il s'agit bien d'une détection de contour.

##### Flou Gaussien
<span class="dual">
![](moly_orig.PNG)![](moly_gaussien.PNG)
![](freq_moly_orig.PNG)![](freq_moly_gaussien.PNG)
</span>
Ce filtre effectue une _moyenage_ de l'intensité avec les intensités environnantes, d'où l'effet de flou : les contours sont adoucis, les hautes fréquences atténuées.

##### Gradient N
<span class="dual">
![](moly_orig.PNG)![](moly_gradientN.PNG)
![](freq_moly_orig.PNG)![](freq_moly_gradientN.PNG)
</span>
Ce filtre effectue une forme de détection de contour par sa forme (sur la verticale) et in intensification des couleurs (par sa forme sur l'horizontale) :
$$
\begin{pmatrix}
    -1 & -2 & -1 \\\\
    0 & 0 & 0 \\\\
    1 & 2 & 1 \\\\
\end{pmatrix}
$$
D'où d'effet d'ombre et les intensités de couleur plus tranchantes.

##### Laplacien
<span class="dual">
![](moly_orig.PNG)![](moly_laplacien.PNG)
![](freq_moly_orig.PNG)![](freq_moly_laplacien.PNG)
</span>
Cette convolution soustrait à chaque pixel les intensités (pondérées) des pixels environnants, d'où l'intensification des intensités (plus sombre ou plus clair que l'original). 



Exercice 2 : Filtres non-linéaires bidimensionnels, les filtres médians
-------------------------------------------------------------------------------

### Médian
<span class="dual">![](cornee_orig.PNG)![](cornee_median.PNG)</span>

### Moyenne
<span class="dual">![](cornee_orig.PNG)![](cornee_mean.PNG)</span>

Les deux filtres, moyenneur et médian, ne laissent pas apparaître de différence entre les deux images. Cependant, les représentations fréquentielles laissent apparaître des différences : le filtre médian semble filtrer plus de fréquences (hautes) que le filtre _mean_.

### Bateau, Salt and Pepper
<span class="dual">![](bateau_orig.PNG)![](bateau_saltandpepper.PNG)</span>

#### Médian, taille 3
<span class="dual">![](bateau_saltandpepper.PNG)![](bateau_saltandpepper_median3.PNG)</span>
#### Moyenne, taille 3
<span class="dual">![](bateau_saltandpepper.PNG)![](bateau_saltandpepper_mean3.PNG)</span>

On constate que les filtres moyenneur et médian, ont rendu le bruit moins visible. Cependant, le filtre ayant le mieux fait disparaître le bruit, à savoir le filtre médian, à également été le plus destructif : l'image originale est moins reconnaissable qu'avec le filtre moyenneur.

Exercice 3 : Introduction à la détection de contours
-------------------------------------------------------------------------------
Pour détecter un contour avec un masque 1x3, un masque (-x, 0, x) peut être utilisé, avec x l'intensité du contour en fonction de la différence d'intensité des pixels environnant : une zone homogène donnera un résultat nul alors qu'un changement d'intensité donnera une valeur positive ou nulle en fonction de la transition et de la valeur de x :
* si x>=1, un passage de clair à gauche vers sombre à droite donnera une valeur non nulle, les autres changements donnant une valeur nulle.
* si x<=-1, un passage de sombre à gauche vers clair à droite donnera une valeur non nulle, les autres changements donnant une valeur nulle.

* Si l'on suit cette logique, le filtre 1x3 proposé précédemment peut être transformé en filtre 3x3 suivant :
$$
\begin{pmatrix}
    0 & 0 & 0 \\\\
    x & 0 & -x \\\\
    0 & 0 & 0 \\\\
\end{pmatrix}
$$
Ce filtre détecte toujours les discontinuités horizontales.
<span class="dual">![](detail_horiz.PNG)</span>

* Pour une discontinuité verticale :
$$
\begin{pmatrix}
    0 & x & 0 \\\\
    0 & 0 & 0 \\\\
    0 & -x & 0 \\\\
\end{pmatrix}
$$

<span class="dual">![](detail_vertical.PNG)</span>

Pour une discontinuité oblique, deux solution, suivant l'angle de la discontinuité :

* 45° :
$$
\begin{pmatrix}
    x & 0 & 0 \\\\
    0 & 0 & 0 \\\\
    0 & 0 & -x \\\\
\end{pmatrix}
$$

<span class="dual">![](detail_45deg.PNG)</span>

* 315° (-45°) :
$$
\begin{pmatrix}
    0 & 0 & -x \\\\
    0 & 0 & 0 \\\\
    x & 0 & 0 \\\\
\end{pmatrix}
$$

<span class="dual">![](detail_315deg.PNG)</span>

#### Sobel + médian
<todo/> Pb d'affichage
<span class="quad">![](bateau_noise.PNG)![](bateau_sobel.PNG)[](bateau_medianSobel.PNG)</span>

#### Médian, taille 3
<span class="dual">![](bateau_saltandpepper.PNG)![](bateau_saltandpepper_median3.PNG)</span>

L'image traitée aven un filtre médian est contient moins de bruit, même l'image avec le traitement du filtre de Sobel. Le traitement du filtre de Sobel fait bien, avec au filtre médian, une détection des contours (sans orientation comme dans les premiers exemples de cet exercice).

#### Red_COQ2
<todo/> pb aff
<span class="quad">![](redCoq2_orig.PNG)![](redCoq2_sobel.PNG)![](redCoq2_redCoq2_sobelThreshold.PNG)</span>
Le filtre de Sobel a fait ressortir les contours des cellules, et le seuillage a éliminé les parties trop claires. Il ne reste alors que les cellules et les impuretés (leur contour est lui aussi ressorti).


Partie II : Morphologie Mathématique
===============================================================================

Traitement d'images binaires
-------------------------------------------------------------------------------

### Importance du choix de l'élément structurant (voisinage)

#### Érosion de taille 3 sur l'image partB

##### Érosion carrée
<span class="quad">![](partb_orig.PNG)![](partb_carre.PNG)</span>
##### Érosion héxagonale
<span class="quad">![](partb_orig.PNG)![](partb_hexagonal.PNG)</span>
##### Érosion Circulaire
<span class="quad">![](partb_orig.PNG)![](partb_cercle.PNG)</span>

#### Cercle1
<span class="quad">![](cercle_orig.PNG)</span>

##### Érosion carrée/hexagonale/circulaire
<span class="quad">![](cercle_erode_carre.PNG)![](cercle_erode_hexa.PNG)![](cercle_erode_cercle.PNG)</span>
##### Dilatation carrée/hexagonale/circulaire
<span class="quad">![](cercle_dilate_carre.PNG)![](cercle_dilate_hexa.PNG)![](cercle_dilate_cercle.PNG)</span>

#### Cercle2
- Idem que pour Cercle1
- Disparition du cercle quand l'érosion est trop forte

#### Rectangles
<span class="quad">![](rectangle_orig.PNG)</span>


##### Érosion carrée/hexagonale/circulaire
<span class="quad">![](rectangle_erode_carre.PNG)![](rectangle_erode_hexa.PNG)![](rectangle_erode_cercle.PNG)</span>
##### Dilatation carrée/hexagonale/circulaire
<span class="quad">![](rectangle_dilate_carre.PNG)![](rectangle_dilate_hexa.PNG)![](rectangle_dilate_cercle.PNG)</span>


#### Deviner le type de voisinage

On prend une forme de base, puis on le dilate beaucoup.

On remarque que la dilatation se fait en utilisant un élément carré
<span class="quad">![](binary_dilate_cercle.PNG)![](binary_dilate_rectangle.PNG)</span>


#### Choix du voisinage

Il dépend de l'image source:

- On préférera un voisinage carré pour conserver les angles de l'image
- Le voisinage circulaire est plus adapté pour les images avec des formes courbes

### Utilisation des transformations élémentaires

#### Circuit

Obtention des frontières par différence entre l'image érodée/dilatée et l'image originale

_Image originale/érodée/différence entre les deux_
<span class="quad">![](circuit_orig.PNG)![](circuit_erode.PNG)![](circuit_diff.PNG)</span>

#### Grains de café
On érode les grains de café pour faire disparaître les plus petits, puis on dilate puis compte les grains restants.

_Image originale/érodée/dilatée/comptage_
<span class="quad">![](cafe_orig.PNG)![](cafe_erodeCercle3.PNG)![](cafe_dilateCercle2.PNG)![](cafe_count.PNG)</span>

#### Circuit (bis)
On érode le circuit afin de faire disparaître les pistes puis dilate autant qu'on a érodé afin de retrouver la taille originale des pastilles.
Une fois qu'on a les pastilles, on fait la différence entre l'originale et les pastilles.

_Image originale/érodée/re-dilatée/différence_
<span class="quad">![](circuit_orig.PNG)![](circuit_pastilles_erodeCercle4.PNG)![](circuit_pastilles_erodeCercle4_dilateCercle4.PNG)![](circuit_pistes.PNG)</span>

Pour isoler les pistes obliques, il faut éroder l'image suivant une ligne oblique.

### Transformations utiles

#### Remplissage des trous

On peut boucher les trous en dilatant puis érodant l'image.

_Image originale/binarisée/érodée/re-dilatée_
<span class="quad">![](circuit_2_color.PNG)![](circuit_2_binary.PNG)![](circuit_2_erode.PNG)![](circuit_2_dilate.PNG)</span>

#### Étiquetage

_Image originale/étiquetée_
<span class="quad">![](partb_orig.PNG)![](partb_etiquetteRGB.PNG)</span>

### Exercice

_Image originale/binarisée/érodée/re-dilatée/Comptage_
<span class="quad">![](riz_orig.PNG)![](riz_binary.PNG)![](riz_erodeHorizontal4.PNG)![](riz_dilateHorizontal4.PNG)![](riz_count.PNG)</span>

Morphologie décimale
-------------------------------------------------------------------------------

### Cornée

_Originale / érosion / soustraction & binarisation_
<span class="quad">![](cornee_orig.PNG)![](cornee_erosion8hexa.PNG)![](cornee_substractbinary.PNG)</span>


_Approximation des contours via érosion_
<span class="quad">![](Cornee_erodeCercle1_approxContour.PNG)</span>

On constate que l'on peut détecter les contour des cellules, cependant le centre des cellules (noyaux) ressort lui aussi par cette technique.

### Gradient morphologique

_Originale / Gradient de Sobel_
<span class="quad">![](babouin_orig.PNG)![](babouin_sobel.PNG)</span>

_Originale / Dilatée / Érodée / Gradient morphologique_
<span class="quad">![](babouin_orig.PNG)![](babouin_dilate2cercle.PNG)![](babouin_erosion2cercle.PNG)![](babouin_gradientmorpho.PNG)</span>

Le filtre de Sobel effectue une meilleur détection des contours que le gradient morphologique (contours plus flous).


### Filtrage morphologique

#### Fermeture
_Originale / ... / Fermeture_
<span class="quad">![](babouin_orig.PNG)![](babouin_fermeture1.PNG)![](babouin_diffFermeture.PNG)</span>

#### Ouverture
_Originale / ... / Ouverture_
<span class="quad">![](babouin_orig.PNG)![](babouin_ouverture1.PNG)![](babouin_diffOuverture.PNG)</span>

Faire la différence entre la fermeture/ouverture et l'originale donne des détections de contours avec moins d'intensité que le filtre de Sobel, mais semblent avoir plus de détails dans les zones ayant beaucoup de contours (zones de poils par exemple) et moins de détails dans les zones avec moins de contours à détecter (yeux par exemple) qu'avec Sobel.


Exercices d'application
-------------------------------------------------------------------------------

### Image partB

<todo/>

### Image meb

_Originale / Binarisation / Érosion / Dilatation / Comptage_
<span class="quad">![](meb_orig.PNG)![](meb_binary.PNG)![](meb_erodeCercle2.PNG)![](meb_dilate4.PNG)![](meb_countIs407.PNG)</span>

On supprime bien les grosses billes, mais il reste des petits éléments de la taille des billes qui sont comptés comme étant des billes.


### Image circuit "binarisée"

<todo/>