Partie 3 : Extraction de contours#

Note : cette partie n’est pas nécessaire pour la suite du projet

Les formes des objets présents dans une image constituent une information privilégiée en traitement d’image. Ces formes peuvent être obtenues en détectant les contours (frontières) des objets. Dans beaucoup d’algorithmes, la recherche d’un objet dans une image se ramène souvent à la recherche d’un contour ayant une certaine forme.

Pour voir le contour, il faut une différence (gradient) de couleurs.

Si, dans une image, un objet A touche un objet B, c’est que des pixels de A touchent des pixels de B. Or il y a alors de fortes chances pour que la couleur des pixels de A soit différente de la couleur des pixels de B. Ainsi, les contours semblent intuitivement inclus dans les zones qui présentent de fortes disparités (gradients) de couleur.

On voit donc l’intérêt de rechercher dans les images les zones qui présentent de fortes disparités de couleurs, puisqu’elles contiennent les contours. Ces zones peuvent être obtenues par des opérations simples et efficaces sur l’image comme dans l’exemple ci-dessous

Exemple : détection de contours sur une image en niveau de gris

Portrait de Bruce Willis en noir et blanc Les contours de l'image dessinés en blanc sur fond noir

Illustration de l’intérêt de rechercher les zones à forte disparité. On constate que les contours corrèlent relativement bien aux zones à fortes disparités.

Le filtre de Sobel pour estimer le gradient#

Le filtre de Sobel est classiquement utilisé pour estimer la valeur de la disparité des intensités. En assimilant l’image à une fonction à deux variables, ce filtre peut s’interpréter comme des calculs d’une version discrète de la dérivée. À vous de réfléchir pourquoi la dérivée est forte lors d’un brusque saut de valeur, comme lorsque l’on traverse un contour.

Pour ce qui nous concerne, ce filtre consiste juste à calculer des différences au niveau du voisinage (horizontal et vertical) de chaque pixel.

L’intensité des différences d’intensité horizontales au niveau du pixel (i,j) dans l’image img est donnée par:

img[i-1][j-1] + 2*img[i][j-1] + img[i+1][j-1]
- img[i-1][j+1] - 2*img[i][j+1] - img[i+1][j+1]

L’intensité des différences d’intensité verticales est de même donnée par:

img[i-1][j-1] + 2*img[i-1][j] + img[i-1][j+1]
- img[i+1][j-1] - 2*img[i+1][j] - img[i+1][j+1]

L’intensité totale est la norme des intensités horizontale et verticale (voir le rappel plus loin).

Exercice 3.1 (*) : implantation du filtre de Sobel

Dans sobel-tout-en-un.cpp, copier les fonctions lirePGM et ecrirePGM qui seront utilisées pour les tests.

Ensuite, implanter dans sobel-tout-en-un.cpp les trois fonctions intensiteH, intensiteV et intensite qui prennent une image en entrée et renvoient une nouvelle image de même taille, dans laquelle chaque pixel a pour valeur respectivement l’intensité horizontale, verticale et totale au niveau du pixel dans l’image d’origine (une pseudo image en fait, car ces intensités peuvent être négatives).

Attention: proposez et programmez une façon de traiter spécifiquement les bords mais n’oubliez pas qu’il n’est pas possible de lire une valeur en dehors de l’image!

Indication: intensiteH et intensiteV sont là pour vous aider, il n’est pas obligatoire de s’en servir pour faire intensite. On rappelle que la norme d’un vecteur \(\left(h,v\right)\) est \(\sqrt{h^2+v^2}\). La fonction sqrt permet de calculer la racine.

N’oubliez pas de compiler et d’exécuter le fichier sobel-tout-en-un.cpp pour vérifier que vos fonctions sont bien implantées. Pensez à vérifier que vos images sont semblables à celles du dossier sobel/correction.

Seuillage des gradients#

Copier dans seuillage-tout-en-un.cpp les fonctions lirePGM et ecrirePGM qui seront utilisées pour les tests et la fonction intensite qui sera utilisée pour le seuillage des gradients.

Exercice 3.2 (*) Renormalisation des gradients

Implantez dans seuillage-tout-en-un.cpp la fonction renormalise.

L’idée est d’utiliser toutes les teintes possibles dans le cas où toutes les valeurs seraient comprises dans un petit intervalle \([0,v]\) avec \(v\leq 255\).

Indication: Il peut être pertinent de chercher le max des valeurs.

Testez votre fonction avec la fonction de test proposée.

Exercice 3.3 (**) Seuillage de l’intensité

Vous allez remarquer que l’on détecte beaucoup de contours. Il serait bon de ne garder que ceux qui semblent correspondre aux contours des objets. Les pixels avec une forte réponse au filtre de Sobel corrèlent bien avec les pixels des contours.

Implanter la fonction seuillage dans seuillage-tout-en-un.cpp

Utiliser seuillageTest pour tester vos résultats. Notamment, proposer plusieurs valeurs de seuil pour les images indiquées.

Double seuillage de l’intensité du gradient#

Même en réglant manuellement le seuil, des pixels peuvent être indûment considérés comme des contours. Une façon de diminuer ce nombre d’erreurs consiste à appliquer un seuil très élevé pour extraire des graines puis d’appliquer un seuil plus faible mais de ne garder que les pixels connectés aux graines.

Exercice 3.4 (***) Croissance du contour de 1 pas

Implantez la première fonction doubleSeuillage « Filtre de double seuillage » dans seuillage-tout-en-un.cpp qui prend en argument une image d’intensité imgIntensite et une image imgContour, qui code un ensemble de pixels sélectionnés (0 si sélectionné, 255 sinon) et qui renvoie une image dans laquelle les pixels sont à 0 si et seulement si d’une part ils ont une intensité supérieure à seuil et d’autre part ils sont voisins d’un pixel sélectionné dans imgContour (255 sinon).

Utilisez la fonction doubleSeuillageTest pour vérifier vos résultats et proposer des paramètres pour les exemples indiqués.

Exercice 3.5 (***) Croissance du contour de plusieurs pas et visualisation

Implantez la deuxième fonction fonction doubleSeuillage «Filtre de double seuillage iteratif» dans seuillage-tout-en-un.cpp qui prend en argument une image img et qui renvoie une image dans laquelle un pixel est à 0 si et seulement si il a dans l’image une intensité supérieure à seuilFort, ou bien une intensité supérieure à seuilFaible tout en étant connecté à un pixel d’intensité supérieure à seuilFort par un chemin de taille inférieure à nbAmelioration (255 sinon).

Indication

Indication

Utilisez la fonction seuillage pour calculer les pixels d’intensité supérieure à seuilFort; puis appliquer nbAmelioration fois la fonction doubleSeuillage précédente pour successivement calculer leurs voisins d’intensité supérieure à seuilFaible, puis les voisins de ces voisins, et ainsi de suite.

Utiliser la fonction doubleSeuillageIteratifTest pour vérifier vos résultats et proposer des paramètres pour les exemples indiqués.

Aller plus loin#

Exercice 3.6 (**) Lissage

Afin de diminuer l’influence du bruit dans l’intensité, il peut être intéressant de lisser l’image avant de calculer le filtre de Sobel. Une façon de faire est de remplacer la valeur de chaque pixel par la moyenne des quatre pixels voisins, ou des 8 voisins.

Exercice 3.7 (***) Améliorer l’algorithme

Dans doubleSeuillage, on parcourt l’image en entier pour chercher des pixels connectés aux pixels déjà sélectionnés. Il serait plus efficace de n’explorer que le voisinage des pixels déjà sélectionnés. De plus, il serait intéressant de continuer ce processus tant que de nouveaux pixels sont sélectionnés. Implémenter ces deux améliorations.

Aller beaucoup plus loin#

Quelques références sur les techniques d’extraction de contours et son utilisation:

  • http://fr.wikipedia.org/wiki/Filtre_de_Sobel

  • http://en.wikipedia.org/wiki/Sobel_operator

  • un article référence sur le sujet de l’extraction de contour : Scale-space and edge detection using anisotropic diffusion, Pietro Perona and Jitendra Malik, Pattern Analysis and Machine Intelligence, IEEE Transactions on 12 (7), 629–639, 1990.

  • ce domaine de recherche est encore très actif, on peut citer par exemple la publication : Hierarchical segmentation and identification of thoracic vertebra using learning-based edge detection and coarse-to-fine deformable model, Jun Ma and Le Lu, Computer Vision and Image Understanding, 2013