Skip to main content

Filtrage et détection de contour

Cours

Filtrage linéaire / non linéaire

Filtres linéaires

Produit de convolution : I(i,j)=(u,v)HI(i+u,j+v).H(u,v)I'(i,j) = \sum \limits_{(u,v) \in H} I(i+u, j + v) . H(u,v), HH centré sur (i,j)(i,j)

  • H : représente la fonction à appliquer (Box, Gaussienne, Laplacien)
  • Efficacité : utiliser des coefficients entiers + un paramètre de normalisation
  • Filtre Gaussien : influence des voisins plus ou moins proche, σ\sigma et taille du support: contrôle de filtrage

Filtres non linéaires

Filtre médian : I(i,j)=medianI(i+u,j+v)(u,v)HI'(i,j) = median\\{I(i+u, j+v) \\| (u,v) \in H\\}, HH : voisinage autour de (i,j)(i,j). Débruitge et "respect" des principales structures. Élimination des points isolés et des lignes fines, préservation des contours en "marche d'escalier" et lissage des coins.

Filtres min/max : I(i,j)=min/maxI(i+u,j+v)(u,v)HI'(i,j) = min \\/ max \\{I(i + u, j + v) \\| (u,v) \in H \\}

Filtre bilatéral

Mélanger l'influence sptiale et colorimétrique. Pour un pixel p=(i,j)Ip = (i,j) \in I, un pixel q=(u,v)V(p)q = (u,v) \in V(p) I(p)=qV(p)Gs(pq).Gc(I(p)I(q)).I(q)qV(p)GS(pq).Gc(I(p)I(q))I'(p) = \dfrac{\sum \limits_{q \in V(p)} G_s(\\|p-q\\|). G_c(\\|I(p) - I(q)\\|).I(q)}{\sum \limits_{q \in V(p)} G_S(\\|p-q\\|).G_c(\\|I(p) - I(q)\\|)}

G(x)=exp(x22σ2)[0,1]G_*(x) = \exp(-\dfrac{x^2}{2 \sigma^2}) \rightarrow [0,1] si, x+G(x)0x \rightarrow + \infty \Rightarrow G_* (x) \rightarrow 0, si x0G(x)1x \rightarrow 0 \Rightarrow G_*(x) \rightarrow 1

Interprétation

Si GS(.)=GC(.)=1G_S(.) = G_C(.) = 1 alors I'(p) = \dfrac{\sum \limits_{q \in V(p) I(q)}}{\sum \limits_{q \in V(p)^1}} = \dfrac{\sum \limits_{q \in V(p)} I(q)}{\\#\\{V(p)\\}} c'est à dire un filtre moyenneur

  • GS(pq):G_S(\\|p-q \\|) : pondération spatiale, un voisin proche spatialement contribue plus qu'un éloigné
  • GC(I(p)I(q)):G_C(\\|I(p) - I(q)): pondération colorimétrique, un voisin proche en valeur contribue plus qu'un éloigné. La préservation des différentes intensités permet d'indentifier les contours

NL Means

Détection du contour par le passage à zéro de la dérivée seconde. Utilisation du laplacien : Δf(x)=(2f)(x)=x2f(x)=x(xf(x))\Delta f(x) = (\nabla^2 f)(x) = \partial^2_x f(x) = \partial_x(\partial_x f(x)). Approximation discrète du Laplcien $$\Delta \Delta I(i,j) = \partial^2_i I(i,j) + \partial^2_j(i,j)$.

Filtre passe bas / haut 2D

C'est un filtre idéal pour une fréquence de coupure DD.

HL(u,v)={1;si;u2+v2D0;si;u2+v2>DHH(u,v)={1;si;u2+v2D0;si;u2+v2>DH_L(u,v) = \begin{cases} 1 \\; \text{si} \\; \sqrt{u^2 + v^2} \leq D \\\\ 0 \\; \text{si} \\; \sqrt{u^2 + v^2} > D \end{cases} \quad H_H(u,v) = \begin{cases} 1 \\; \text{si} \\; \sqrt{u^2 + v^2} \leq D \\\\ 0 \\; \text{si} \\; \sqrt{u^2 + v^2} > D \end{cases}

  • Plus DD est grand, plus on ne récupère que les contours et le bruit

  • Plus DD est petit, plus on perd du signal utile (l'image)

  • Filtre de Butterworth : HLB(u)=11+(uD)2nHHB(u)=11+(Du)2nH_{LB}(u) = \dfrac{1}{1 + (\dfrac{u}{D})^{2n}} \quad H_{HB}(u) = \dfrac{1}{1 + (\dfrac{D}{u})^{2n}}

  • Filtre Gaussien : HLB(u,v)=12πσexp(u2+v22σ2)HHB(u,v)=1HLG(u,v)H_{LB}(u,v) = \dfrac{1}{2\pi\sigma}\exp(-\dfrac{u^2 + v^2}{2 \sigma^2}) \quad H_{HB}(u,v) = 1 - H_{LG}(u,v)

  • Filtres rejet / passe bande : HBR(u,v)=11+wu2+v2((u2+v2)r2)2nHBP(u,v)=1HBR(u,v)H_{BR}(u,v) = \dfrac{1}{1+\dfrac{w \sqrt{u^2 + v^2}}{((u^2+v^2)-r^2)^{2n}}} \quad H_{BP}(u,v) = 1 - H_{BR}(u,v) avec rr le rayon et ww la largeur de la bande

Dérivées premières et fonctions discrètes

Les contours impliquent des grandes valeurs de la dérivée f(x)=df(x)dxf'(x)=\dfrac{df(x)}{dx} (Opérateurs du 1er ordre). L'approximation des dérivées (pente) utilise des points de droite et de gauche. Plusieurs approximations sont possibles

  • Différence à droite (forward) +f(u)=f(u+1)f(u)\partial^+ f(u) = f(u+1) - f(u)
  • Différence à gauche (backward) f(u)=f(u)f(u1)\partial^- f(u) = f(u) - f(u-1)
  • Différence centrée (moyenne) f(u)=f(u+1)f(u1)2\partial f(u) = \dfrac{f(u+1) - f(u-1)}{2}

Pour une image 2D discrète II, le gradient I(i,j)\nabla I(i,j) localisé au point (i,j)(i,j) est le vecteur :

  • I(i,j)=[iI(i,j);jI(i,j)]T\nabla I(i,j) = [\partial_i I(i,j) \\; \partial_j I(i,j)]^T
  • Magnitude du gradient (sa norme) I(i,j)2=(iI(i,j))2+(jI(i,j))2||\nabla I(i,j)||_2 = \sqrt{(\partial_i I(i,j))^2 + (\partial_j I(i,j))^2}
  • Direction du gradient : ϕ(I(i,j))=tan1(iI(i,j)jI(i,j))\phi(I(i,j)) = \tan^{-1} (\dfrac{\partial_i I(i,j)}{\partial_j I(i,j)})

Différences finies par convolution et moyenneur

  • Différence à droite : +f(u)=f(u+1)f(u)\partial^+ f(u) = f(u+1) - f(u) si H+=[0;1;1]H^+ = [0 \\; -1 \\; 1]
  • Différence centrée : f(u)=f(u+1)f(u1)2;H+=[1;0;1]f(u)=f(u)H\partial f(u) = \dfrac{f(u+1) - f(u-1)}{2} \\; H^+ = [ -1 \\; 0 \\; 1 ] \rightarrow \partial f(u) = f(u) \ast H. Les différences finies sont sensibles au bruit. Le bruit peut être vue comme un point de contour, il faut donc coupler la différentiation avec un filtrage.
  • Détecteur de Prewitt : HhP=(101101101)=(111)v(101)h;HvP=(111000111)=(101)v(111)hH_h^P = \begin{pmatrix} 1 & 0 & -1 \\\\ 1 & 0 & -1 \\\\ 1 & 0 & -1 \end{pmatrix} = \begin{pmatrix} 1 \\\\ 1 \\\\ 1 \end{pmatrix}_ v \otimes \begin{pmatrix} 1 & 0 & -1 \end{pmatrix}_ h \\; H_v^P = \begin{pmatrix} 1 & 1 & 1 \\\\ 0 & 0 & 0 \\\\ -1 & -1 & -1 \end{pmatrix} = \begin{pmatrix} 1 \\\\ 0 \\\\ -1\end{pmatrix}_v \otimes \begin{pmatrix} 1 & 1 & 1 \end{pmatrix}_h
  • Détecteur de Sobel : HhS=(101202101)=(121)v(101)h;HvS=(121000121)=(101)v(121)hH_h^S = \begin{pmatrix} 1 & 0 & -1 \\\\ 2 & 0 & -2 \\\\ 1 & 0 & -1 \end{pmatrix} = \begin{pmatrix} 1 \\\\ 2 \\\\ 1 \end{pmatrix}_ v \otimes \begin{pmatrix} 1 & 0 & -1 \end{pmatrix}_ h \\; H_v^S = \begin{pmatrix} 1 & 2 & 1 \\\\ 0 & 0 & 0 \\\\ -1 & -2 & -1 \end{pmatrix} = \begin{pmatrix} 1 \\\\ 0 \\\\ -1\end{pmatrix}_v \otimes \begin{pmatrix} 1 & 2 & 1 \end{pmatrix}_h

Autres approches : dérivées secondes

Détection du contour par le passage à zéro de la dérivée seconde. Pour cela on utilise le laplacien Δf(x)=(2f)(x)=x2f(x)=x(xf(x))\Delta f(x) = (\nabla^2 f)(x) = \partial^2_x f(x) = \partial_x(\partial_x f(x)). Son approximation discrète est ΔI(i,j)=i2I(i,j)+j2I(i,j)\Delta I(i,j) = \partial^2_i I(i,j) + \partial^2_j I(i,j).

Amélioration : filtre passe bas

L'idée est de filter l'image par une Gaussienne GσG_\sigma de largeur σ\sigma. Le Laplacien de II filtré par GσG_\sigma. Le Laplacien de II filtré par GσG_\sigma devient I×Gσ×Δ=I×(Δ×Gσ)=I×ΔGσI \times G_\sigma \times \Delta = I \times (\Delta \times G_\sigma) = I \times \Delta G_\sigma, cela revient à convoluer directement II avec le Laplacien de GσG_\sigma (LoG). La convolution avec une Gaussienne large rend l'image floue et les contours sont perdus.

Schéma classique d'extraction de contours :

  • calculer le gradient (\nabla) ou le Laplacien (Δ\Delta)
  • localiser les maxima locaux de la norme du gradient ou le passage à zéro du Laplacien
  • un seuillage permet d'avoir la carte binaire de contour mais il y a un risque de déconnexion des contours (améliorable via des algorithmes de re-chaînage)
  • utilisation des contours dans d'autres applications

Mise en pratique

median-filter <r> <ims> <imd>

Écrire le programme median-filter.cpp

  • ce programme permet de charger une image donnée en paramètre <ims>
  • l'image source est considérée comme une image en niveaux de gris
  • le programme réalise le filtrage médian où la fenêtre de recherche de taille (2r+1×2r+1)(2r + 1 \times 2 r +1) est déterminée par le paramètre <r>
  • sauver le résultat dans l'image <imd>
  • comparer avec la fonction medianBlur
  • visualiser avec pvisu les différents résultats

bilateral <sigma_s> <sigma_g> <ims> <imd>

Éviter le programme bilateral.cpp

  • ce programme permet de charger une image donnée en paramètre <ims>
  • l'image source est considérée comme une image en niveaux de gris
  • le programme réalise le filtrage bilatéral
  • le paramètre <sigma_g> permet de calculer la Gaussienne pour la pondération sur les intensités et ̀<sigma_s> celle pour la pondération des distances. On pourra pré-calculer ces coefficients et seuiller celle sur les distances afin de déterminer la taille du voisinage : Gσs(x)=exp(x2/2σs2)sG_{\sigma_s}(x) = \exp(-x^2 / 2 \sigma^2_s) \leq s, par exemple s=0.1s=0.1
  • le programme sauve l'image ̀<imd>
  • comparer les résultats avec la fonction ̀bilateralFilter`
  • visualiser avec pvisu les différents résultats

nl-means <sigma> <ims> <imd>

Écrire le programme nl-means.cpp

  • ce programme permet de charger une image donnée en paramètre <ims>̀
  • l'image source est considérée comme une image en niveaux de gris
  • le programme réalise le filtrage par moyenne non locales
  • le paramètre <sigma> permet de calculer les poids associés aux patchs
  • les autreus donnent des paramètres empiriques : une fenêtre de recherche de taille 11×1111 \times 11 et des patchs 7×77 \times 7
  • le programme sauve l'image <imd>
  • visualiser avec pvisu les différents résultats

fourier <ims> <freq>

Écrire le programme fourrier.cpp

  • ce programme permet de charger une image donnée en paramètre <ims>
  • le programme réalise la transformée de Fourier directe (fonction dft)
  • affiche le spectre d'amplitude et de phase (centrés) et la sauve dans les fichiers magnitude.png et phase.png
  • le programme réaliser un filtrage dans le domaine de Foourier et annule (de manière symétrique) la fréquence <freq> donnée en paramètre
  • sauve le spectre d'amplitude modifié dans un fichier ̀magnitude-modify.png` afin d'observer l'annulation des fréquences
  • le programme réalise la transformée de Fourier inverse et sauve le résultat dans le fichier inverse.png
  • visualiser avec pvisu les différents résultats