3.1 - Un contour c'est quoi ?
Un contour dans une image en Noir & Blanc est défini comme la démarcation qui sépare les zones de pixels noirs des zones de pixels blancs. Pour les images traitées dans ce projet, tout ce qui se trouve à l'extérieur de l'image est considéré comme blanc. L'extraction de contour consiste donc à identifier et à suivre le bord qui marque la transition entre les zones noires et blanches, y compris celles adjacentes à l'espace "hors image".
Le processus d'extraction génère un polygone formé par une série de points qui décrivent ce contour. Ces points sont reliés par des segments qui tracent précisément le chemin du contour.
Exemple d'extraction de contour
L'image suivante illustre un exemple de grille d'image et la représentation correspondante des contours extraits :
Dans cet exemple, en partant du point (1.0, 0.0), le contour identifié est un polygone composé de 19 points (formant 18 segments). Ceux-ci décrivent le contour complet autour des blocs noirs comme suit :
- (1.0, 0.0) → (2.0, 0.0) → (2.0, 1.0) → (3.0, 1.0) → (4.0, 1.0)
- (4.0, 2.0) → (3.0, 2.0) → (3.0, 3.0) → (3.0, 4.0) → (2.0, 4.0)
- (1.0, 4.0) → (1.0, 3.0) → (2.0, 3.0) → (2.0, 2.0) → (1.0, 2.0)
- (0.0, 2.0) → (0.0, 1.0) → (1.0, 1.0) → (1.0, 0.0)
Cette série de points et de segments crée une frontière précise qui encapsule les zones noires, essentielle pour des analyses plus avancées comme la vectorisation ou d'autres formes de traitement d'image.
3.2 - Détermination du Contour
Fonctionnement de l'Algorithme
La tâche de détermination du contour dans une image en Noir & Blanc utilise un automate, que nous appellerons "robot", pour suivre le contour polygonal qui sépare les pixels noirs de l'image des pixels blancs. Le robot se déplace de manière à garder un pixel noir à sa droite et un pixel blanc à sa gauche, poursuivant ainsi son chemin jusqu'à ce qu'il revienne à son point de départ et retrouve son orientation initiale.
Définition des Orientations
Le robot peut se déplacer dans quatre directions cardinales, qui correspondent aux orientations suivantes :
Orientation
Definition contour.h:21
@ Est
Definition contour.h:21
@ Nord
Definition contour.h:21
@ Sud
Definition contour.h:21
@ Ouest
Definition contour.h:21
Cette énumération en C permet de définir clairement les orientations possibles pour le robot lorsqu'il navigue le long du contour de l'image.
Algorithme de Suivi du Contour
L'algorithme pour suivre le contour est décrit étape par étape ci-dessous :
- Trouver le Pixel de Départ :
- Identifier un pixel de départ ((x, y)) qui est sur le bord du contour entre les pixels noirs et blancs.
- Initialiser les Paramètres :
- Définir la position initiale à ((x_0, y_0) = (x - 1, y - 1)).
- Initialiser l'orientation à Est.
- Exécuter la Boucle de Suivi :
- Commencer une boucle pour suivre le contour.
- À chaque itération de la boucle :
- Mémoriser la Position : Enregistrer la position actuelle pour tracer le contour.
- Avancer : Déplacer le robot d'une unité dans la direction actuelle.
- Calculer la Nouvelle Orientation : Ajuster l'orientation basée sur les pixels adjacents pour maintenir le pixel noir à droite et le blanc à gauche.
- Vérifier la Condition de Fin : Si le robot revient à la position initiale ((x_0, y_0)) avec l'orientation Est, terminer la boucle.
- Fin de la Boucle :
- Le robot termine son parcours lorsque la condition de fin est satisfaite, signifiant que le contour complet a été suivi.
(x, y) ← trouver_pixel_depart(I);
(x0, y0) ← (x − 1, y − 1);
orientation ← EST;
boucle ← VRAI;
while (boucle) {
memoriser_position();
avancer();
nouvelle_orientation();
if (
position == (x0, y0) && orientation == EST) {
boucle ← FAUX;
}
}
memoriser_position();
void position(Robot *r, int *x, int *y)
Récupère et renvoie la position actuelle du robot.
Definition contour.c:136
3.3 - Contour sous forme d’une séquence
Le contour calculé doit être stocké sous forme d’une séquence de points. Cependant, la taille de cette séquence n’est pas connue à l’avance, ce qui implique des considérations spécifiques pour son stockage.
Solutions pour le stockage d'un contour
A - Stockage sous forme de file_input Les points du contour peuvent être stockés progressivement dans un file_input. Cependant, cette méthode présente un inconvénient majeur : l'accès aux file_inputs est généralement beaucoup plus lent que l'accès à la mémoire vive.
B - Stockage en mémoire
B-1) Structure de taille fixe de type tableau Une option est d'utiliser une structure de taille fixe pour stocker les points du contour. Cette structure est définie comme suit :
#define DIMMAX ...
double x, y;
unsigned int np;
struct Point_ Point
Type Point.
Liste_Point Contour
Definition sequence_point.h:50
Definition sequence_point.h:27
Type Point.
Definition geometry.h:34
Inconvénients :
- Si
DIMMAX
est trop grand, il peut être difficile de calculer plusieurs contours ou même un seul, en raison de la saturation de la mémoire.
- Si
DIMMAX
est trop petit, il sera impossible de stocker certains contours plus grands.
B-2) Structure adaptable à la taille du contour Une meilleure solution peut être d'utiliser une structure permettant d’adapter la taille de la mémoire en fonction du contour. Le contour est ainsi "construit" progressivement, à partir d'une séquence vide, en ajoutant au fur et à mesure les points à la fin de la séquence.
Structures recommandées : Les listes chaînées sont idéales pour ces opérations, car elles permettent :
- D'initialiser avec une séquence vide.
- D'ajouter un élément supplémentaire à la fin d’une séquence.
- De maintenir une séquence ordonnée.
- D'effacer une séquence (la vider).
Pour les tâches d'extraction de contour (tâches 3 et 5), les listes chaînées sont suffisantes. Cependant, pour les tâches de simplification de contour (tâches 6 et 7), une structure de données de type tableau est nécessaire pour pouvoir accéder à un élément d’un contour à l’aide d’un indice. En outre, l'opération de concaténation de deux listes chaînées peut être utile pour ces tâches.
Nos Solutions pour le stockage d'un contour
#include<stdio.h>
#include<stdlib.h>
if (el == NULL) {
fprintf(stderr, "Échec de l'allocation mémoire pour la création d'un nouvel élément de point\n");
exit(-40);
}
return el;
}
if (el == NULL) {
fprintf(stderr, "Échec de l'allocation mémoire pour la création d'un nouvel élément de contour\n");
exit(-50);
}
return el;
}
}
}
} else {
}
}
} else {
}
}
while (el) {
free(el);
el = suiv;
}
return L;
}
if (L1.
taille == 0)
return L2;
if (L2.
taille == 0)
return L1;
return L1;
}
fprintf(stderr, "Éch
ec de l'allocation mémoire pour la conversion de la liste en tableau\n");
exit(-60);
}
}
return T;
}
printf(
"%d segments\n", TP.
taille - 1);
printf(
"%d points: [", TP.
taille);
for (
int k = 0; k < TP.
taille; k++) {
printf(
"(%5.1f,%5.1f)", TP.
tab[k].
x, TP.
tab[k].
y);
}
printf("]\n");
}
Déclaration des fonctions pour geometry.c.
Liste_Point creer_liste_Point_vide()
Crée une liste de points vide.
Definition sequence_point.c:66
Liste_Contours creer_liste_Contours_vide()
Crée une liste de contours vide.
Definition sequence_point.c:77
Liste_Point supprimer_liste_Point(Liste_Point L)
Supprime tous les éléments de la liste de points et renvoie la liste vide.
Definition sequence_point.c:137
Liste_Point concatener_liste_Point(Liste_Point L1, Liste_Point L2)
Concatène la liste L2 à la suite de la liste L1 et renvoie la liste L1 modifiée.
Definition sequence_point.c:157
void ajouter_element_liste_Point(Liste_Point *L, Point e)
Ajoute l'élément e à la fin de la liste de points L.
Definition sequence_point.c:89
Cellule_Liste_Point * creer_element_liste_Point(Point v)
Crée une cellule de liste avec l'élément v.
Definition sequence_point.c:26
Tableau_Point sequence_points_liste_vers_tableau(Liste_Point L)
Crée une séquence de points sous forme d'un tableau de points à partir de la liste de points L.
Definition sequence_point.c:176
Cellule_Liste_Contours * creer_element_liste_Contours(Liste_Point v)
Crée une cellule de liste des contours avec la liste de points v.
Definition sequence_point.c:47
void ecrire_contour(Liste_Point L)
Écrit le contour L à l'écran.
Definition sequence_point.c:209
void ajouter_element_liste_Contours(Liste_Contours *L, Liste_Point e)
Ajoute un contour à la liste de contours L.
Definition sequence_point.c:113
Déclaration des fonctions pour sequence_point.c.
Definition sequence_point.h:36
Liste_Point data
Definition sequence_point.h:37
struct Cellule_Liste_Contours_ * suiv
Definition sequence_point.h:38
Definition sequence_point.h:20
Point data
Definition sequence_point.h:21
struct Cellule_Liste_Point_ * suiv
Definition sequence_point.h:22
Definition sequence_point.h:43
unsigned int taille
Definition sequence_point.h:44
Cellule_Liste_Contours * first
Definition sequence_point.h:45
Cellule_Liste_Contours * last
Definition sequence_point.h:46
unsigned int taille
Definition sequence_point.h:28
Cellule_Liste_Point * first
Definition sequence_point.h:29
Cellule_Liste_Point * last
Definition sequence_point.h:30
double y
Definition geometry.h:35
double x
Definition geometry.h:35
Definition sequence_point.h:55
Point * tab
Definition sequence_point.h:57
unsigned int taille
Definition sequence_point.h:56
Pourquoi Convertir une Liste en Tableau?
Dans le contexte de notre projet, où les contours des objets sont fréquemment accédés et manipulés pour diverses analyses et transformations, utiliser un tableau offre une efficacité nettement supérieure. Une fois que les contours sont stockés dans un tableau, il est beaucoup plus efficace de rechercher, d'accéder, et de modifier les points selon les besoins, comparativement à une structure dynamique comme une liste chaînée où chaque accès nécessite de traverser les liens de la liste depuis le début jusqu'à l'élément ciblé.