Richet Coraline Han Xiaofei L3 IUP Informatique 18/12/07 Projet Traitement d'images en C SOMMAIRE 1 Présentation du projet................................................................................................................... 2 1.1 Outils mis à disposition ............................................... 2 Mise en œuvre des fonctions .................................................. 2.1 Fonction de traitement de type Sobel .......................... 2.1.1 Algorithme de calcul du Sobel ................................... 2.1.2 Implémentati on de la fonction de calcul du Sobel de taille 3 .................................. 2.1.3 Implémentati on de la fonction de calcul du Sobel de taille paramétrable ................................................................................................................................. 6 2.2 Fonction de traitement d’érosion ......................................................................................... 8 2.2.1 Algorithme d’érosion ................................................................................................... 8 2.2.2 Implémentation de la fonction d’érosion ..................................................................... 8 2.3 Fonction de traitement de dilatation................................................................................... 11 2.3.1 Algorithme de dilatation ............................................................................................ 11 2.3.2 Implémentation de la fonction de dilatation .............................................................. 11 1/53 2.4 Fonction de traitement ouverture ....................................................................................... 13 2.4.1 Algorithme d’ouverture.............................................................................................. 13 2.4.2 Implémentation de la fonction d’ouverture ................................................................ 13 2.5 Fonction de traitement fermeture ....................................................................................... 14 2.5.1 Algorithme de fermeture ............................................................................................ 14 2.5.2 Implémentation de la fonction de fermeture .............................................................. 14 2.6 Fonction de traitement de filtrage par moyenne ................................................................ 15 2.6.1 Algorithme de filtrage par moyenne .......................................................................... 15 2.6.2 Implémentation de la fonction de filtrage par moyenne ............................................ 15 2.7 Fonction de traitement de segmentation par région (region-growing) .............................. 17 2.7.1 Algorithme de segmentation d’image par région (region-growing) .......................... 17 2.7.2 Implémentation de la fonction de segmentation d’image par région ......................... 18 2.7.3 Implémentation de la fonction de segmentation d’image par région avec un pixel d’amorce choisi au hasard .......................................................................................................... 22 3 Difficultés rencontrées ............................................................................................................... 23 4 Conclusion ................................................................................................................................. 24 5 Sources du projet ........................................................................................................................ 25 5.1 Fichier traitement.h : .......................................................................................................... 25 5.2 Fichier traitement.C : ......................................................................................................... 26 5.3 Fichier fifo.h : .................................................................................................................... 47 5.4 Fichier fifo.C : .................................................................................................................... 48 5.5 Fichier prog.C : .................................................................................................................. 52 1 Présentation du projet Le traitement d'images numériques est l'ensemble des techniques permettant de modifier une image numérique dans le but de l'améliorer ou d'en extraire des informations. Une image en niveau de gris est un tableau bidimensionnel (matrice) où chaque élément contient une valeur entre 0 et 255. Par convention, la valeur zéro représente le noir et la valeur 255 le blanc. 000 008 016 024 032 040 048 056 064 072 080 088 096 104 112 120 128 255 248 240 232 224 216 208 200 192 184 176 168 160 152 144 136 L'objectif du projet est de réaliser différents algorithmes de traitement d'images en langage C tels que : Sobel : mise en évidence des contours d’une image. Erosion et dilatation : supprimer les points de contours isolés ou combler les trous dans un contour d’une image. 1.1 Segmentation en région : partitionner l'image en zones homogènes. Outils mis à disposition Afin de pouvoir mettre en œuvre ces algorithmes de traitement d’images, des outils ont été mis à disposition : Un dossier IncludeLibImage comprenant : - Un fichier d’entête image.h définissant une structure de type image et des prototypes de fonctions (allocation /libération mémoire d’une image, affichage d’une image avec l’application xv …). 2/53 - Un fichier d’entête xAffichage.h nécessaire à la création d’une fenêtre permettant d’effectuer des modifications dynamiques en utilisant des touches de clavier. - Un fichier d’entête LoadSaveImages.h contenant des prototypes de fonctions d’enregistrement et de chargement d’images. Un dossier « XV » contenant les sources compilées du logiciel de traitement d’images XV. Un dossier srcImage contenant les sources des fichiers cités ci-dessus. Un dossier ExempleTraitement : - Un fichier traitement.h qui contiendra les prototypes des fonctions de traitement d’images à implémenter dans le cadre du projet. - Un fichier traitement.C qui contiendra les implémentations des fonctions décrites dans le fichier traitement.h. - Un fichier prog.C qui est le programme principal où sont appelées les fonctions de traitement d’images et utilisant le logiciel xv. - Un fichier progX.C qui appelle des fonctions de traitement d’images en utilisant la librairie Xaffichage. 3/53 2 Mise en œuvre des fonctions 2.1 2.1.1 Fonction de traitement de type Sobel Algorithme de calcul du Sobel Il consiste à appliquer un masque sur l’image afin de faire apparaître les endroits de l’image où les différences entre les pixels voisins sont les plus grandes. Ces différences correspondent au contour de l’image. Appliquer un masque sur une image consiste à déplacer sur l’image une fenêtre carrée de taille impair et supérieur à trois, centré à chaque fois sur un pixel (i,j) dont il faut évaluer le gradient. Pour chaque pixel de l’image, l’application d’un masque consiste à faire la somme pondérée des valeurs des pixels voisins de ce pixel. Exemple de somme pondérée : Ensuite il s’agit de normaliser cette valeur : Dv= Dv / somme des coefficients positifs Pour calculer le gradient en un pixel (i,j), il faut à la fois calculer le gradient vertical (avec un masque vertical) et le gradient horizontal avec un masque horizontal. Le résultat du gradient pour le pixel (i,j) est alors : La valeur calculée est ensuite placée dans le pixel (i,j) d’une image appelée image des gradients. 4/53 2.1.2 Implémentation de la fonction de calcul du Sobel de taille 3 Cette fonction est implémentée en langage C dans le fichier traitement.C : void basicThreeSobelFunction(const Image * in, Image * out) Cette fonction permet d'effectuer un traitement Sobel sur une image, à partir d'un masque vertical et horizontal de taille 3*3. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. Pour rappel, la structure de type Image est définie ainsi : Struct _Image { int magicNumber ; /* Pour vérifier que on a (pas) alloue de la mémoire */ int nbRow ; int nbCol ; octet *ptrZone ; /* Le vrai pointeur sur la zone image */ octet ** zone ; /* Un pointeur qui permet : zone[ligne][colonne] */ }; Typedef struct _Image Image ; Dans cette fonction, les masques vertical et horizontal de taille 3 ainsi que leurs valeurs respectives sont codées en dur dans la fonction : masque vertical maskV masque horizontal maskH L’image donné en paramètre Image * out est allouée par la fonction. La fonction effectue un parcours de tous les pixels (chaque colonne de chaque ligne) de l’image donnée en paramètre const Image * in. Pour chaque pixel de coordonnées Xpin et Ypin, la fonction prend en compte les 8 pixels voisins entourant ce pixel et effectue le calcul du gradient vertical normalisé en appliquant le masque vertical ainsi que le calcul du gradient horizontal normalisé en appliquant le masque horizontal. 5/53 Puis la fonction effectue le calcul du gradient de ce pixel à partir des gradients (vertical et horizontal) calculés précédemment. Ce gradient calculé est ensuite stocké dans le pixel de coordonnées Xpout et Ypout de l’image donnée en paramètre Image * out. Il est important de noter que la fonction n’effectue pas de calcul de gradient pour les pixels contenus dans la 1ère et dernière ligne ainsi que ceux contenus dans la 1ère et dernière colonne de l’image donnée en paramètre Image * in. En effet, il n’est pas possible d’appliquer un masque sur ces pixels du fait de leurs coordonnées particulières, par conséquent les gradients originaux de ces pixels sont stockés directement dans les pixels de coordonnées identiques dans l’image donnée en paramètre Image * out. Exemples de résultat de la fonction basicThreeSobelFunction: femme.ras original 2.1.3 femme.ras après un traitement Sobel lena.ras original lena.ras après un traitement SobelImplémentation de la fonction de calcul du Sobel de taille 6/53 paramétrable Cette fonction est implémentée en langage C dans le fichier traitement.C : void genericSobelFunction(const Image * in, Image * out, int ** maskV, int ** maskH, int maskSize) Cette fonction permet d’effectuer un traitement Sobel sur une image à partir d’un masque horizontal, un masque verticale et une taille de masque donnés en paramètres. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. Le paramètre int ** maskV est un pointeur de pointeurs d’entiers contenant un masque vertical alloué par l’application faisant appel à cette fonction et dont la taille est donné via le paramètre int maskSize. Le paramètre int ** maskH est un pointeur de pointeurs d’entiers contenant un masque horizontal alloué par l’application faisant appel à cette fonction et dont la taille est donné via le paramètre int maskSize. Le paramètre int maskSize est un entier définissant la taille des masques vertical et horizontal donnés en paramètres : cette taille doit être impaire et supérieure ou égal à 3. La fonction effectue d’abord un contrôle sur les paramètres en entrée : - La taille du masque doit être impaire : on vérifie cette condition en calculant le modulo de cette taille. Si le modulo retourne la valeur 1 il s’agit bien d’une taille impaire. - La taille du masque doit être supérieure à trois. - La taille du masque ne doit pas dépasser celle de l’image d’entrée : cette taille est inférieure au nombre de colonnes et de lignes de l’image donnée en paramètre const Image * in. La fonction effectue ensuite le calcul des coefficients de normalisation du masque horizontal en parcourant les valeurs du masque (de zéro à maskSize) et en faisant l’addition du contenu de chaque case pour les valeurs supérieures à zéro. Le même traitement est effectué pour le masque vertical. Ensuite La fonction effectue un parcours de tous les pixels (chaque colonne de chaque ligne) de l’image donnée en paramètre const Image * in. Pour chaque pixel de coordonnées Xpin et Ypin, la fonction calcul l’entier distanceMax (en fonction de la taille du masque) permettant de déterminer la distance maximal entre le pixel du centre et celui le plus éloigné. distanceMax étant la distance limite pour effectuer l’application du masque du pixel central : La fonction prend donc en compte les pixels voisins entourant ce pixel en fonction de distanceMax et effectue le calcul du gradient vertical normalisé en appliquant le masque vertical ainsi que le calcul du gradient horizontal normalisé en appliquant le masque horizontal. Puis la fonction effectue le calcul du gradient de ce pixel à partir des gradients (vertical et horizontal) calculés précédemment. Ce gradient calculé est ensuite stocké dans le pixel de coordonnées Xpout et Ypout de l’image donnée en 7/53 paramètre Image * out. Il est important de noter que la fonction n’effectue pas de calcul de gradient pour les pixels contenus dans les lignes inférieures à distanceMax et les dernière lignes supérieures à taille vertical en pixels de l’imagedistanceMax, ainsi que ceux contenus dans les colonnes inférieures à distanceMax et les dernières colonnes supérieures à taille horizontal en pixels de l’image-distanceMax. En effet, il n’est pas possible d’appliquer un masque sur ces pixels du fait de leurs coordonnées particulières, par conséquent les gradients originaux de ces pixels sont stockés directement dans les pixels de coordonnées identiques dans l’image donnée en paramètre Image * out. Exemple de résultat de la fonction genericSobelFunction avec un masque classique de taille 3 : 2.2 2.2.1 aquitaine.ras original traitement sobelFonction de traitement d’érosion aquitaine.ras après un Algorithme d’érosion L’érosion consiste à supprimer les points de contour (valeur 0 (C) noir) ayant au moins un voisin de type non contour (valeur 255 (NC) blanc). Cet algorithme permet de supprimer les points de contour isolés après avoir effectué un seuillage de l’image des gradients 2.2.2 Implémentation de la fonction d’érosion 8/53 Cette fonction est implémentée en langage C dans le fichier traitement.C : void erosionFunction(const Image* in,Image * out) Cette fonction effectue un traitement d’érosion sur une image. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. L’image donné en paramètre Image * out est allouée par la fonction. La fonction effectue un parcours de tous les pixels (chaque colonne de chaque ligne) de l’image donnée en paramètre const Image * in. Pour chaque pixel de coordonnées Xpin et Ypin, la fonction contrôle si ce pixel est noir (gradient égal à 0) : dans ce cas, la fonction prend en compte les pixels voisins entourant ce pixel. Si au moins un de ces pixels voisins est blanc (valeur de gradient égal à 255) alors la fonction stocke dans le pixel de coordonnées Xpout et Ypout du paramètre Image * out un gradient égal à 255 (blanc), sinon la valeur du gradient du pixel original est stockée. Il est important de noter que la fonction n’effectue pas de traitement pour les pixels contenus dans la 1ère et dernière ligne ainsi que ceux contenus dans la 1ère et dernière colonne de l’image donnée en paramètre Image * in. Les gradients originaux de ces pixels sont stockés directement dans les pixels de coordonnées identiques dans l’image donnée en paramètre Image * out. Exemple de résultat de la fontion erosionFunction : A noter qu’avant le traitement d’érosion, l’image subit un traitement de seuillage qui était déjà implémenté dans le projet. 9/53 lena.ras original lena.ras après seuillage + érosion 10/53 2.3 2.3.1 Fonction de traitement de dilatation Algorithme de dilatation L’érosion consiste à transformer les points de non contour (valeur 255 (NC) blanc) ayant au moins un voisin de type contour (valeur 0 (C) noir) Cet algorithme permet de combler les trous dans un contour après avoir effectué un seuillage de l’image des gradients 2.3.2 Implémentation de la fonction de dilatation Cette fonction est implémentée en langage C dans le fichier traitement.C : void dilatationFunction(const Image* in, Image * out) Cette fonction effectue un traitement de dilatation sur une image. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. L’image donné en paramètre Image * out est allouée par la fonction. La fonction effectue un parcours de tous les pixels (chaque colonne de chaque ligne) de l’image donnée en paramètre const Image * in. Pour chaque pixel de coordonnées Xpin et Ypin, la fonction contrôle si ce pixel est blanc (gradient égal à 255) : dans ce cas, la fonction prend en compte les pixels voisins entourant ce pixel. Si au moins un de ces pixels voisins est noir (valeur de gradient égal à 0) alors la fonction stocke dans le pixel de coordonnées Xpout et Ypout du paramètre Image * out un gradient égal à 0 (noir), sinon la valeur du gradient du pixel original est stockée. Il est important de noter que la fonction n’effectue pas de traitement pour les pixels contenus dans la 1ère et dernière ligne ainsi que ceux contenus dans la 1ère et dernière colonne de l’image donnée en paramètre Image * in. Les gradients originaux de ces pixels sont stockés directement dans les pixels de coordonnées identiques dans l’image donnée en paramètre Image * out. 11/53 Exemple de résultat de la fontion dilatationFunction : A noter qu’avant le traitement d’érosion, l’image subit un traitement de seuillage qui était déjà implémenté dans le projet. lena.ras original lena.ras après seuillage + dilatation 12/53 2.4 2.4.1 Fonction de traitement ouverture Algorithme d’ouverture Il consiste à effectuer un traitement d’érosion suivi d’un traitement de dilatation sur une image pour supprimer les petits objets. 2.4.2 Implémentation de la fonction d’ouverture void ouvertureFunction(const Image* in, Image * out) Cette fonction effectue un traitement d’ouverture sur une image. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. L’image donné en paramètre Image * out est allouée par la fonction. Dans cette fonction, on fait appel successivement aux fonctions erosionFunction et dilatationFunction. Cette fonction créer une image temporaire allouée qui est l’image de sortie de la fonction erosionFunction et l’image d’entrée de la fonction dilatationFunction. La mémoire allouée de l’image temporaire est finalement libérée à la fin du traitement. Exemple de résultat de la fontion ouvertureFunction : A noter qu’avant le traitement d’érosion, l’image subit un traitement de seuillage qui était déjà implémenté dans le projet. lena.ras original lena.ras après seuillage + ouverture 13/53 2.5 2.5.1 Fonction de traitement fermeture Algorithme de fermeture Il consiste à effectuer un traitement de dilatation suivi d’un traitement d’érosion sur une image pour combler les petits trous, les chenaux étroits et connecter les contours proches. 2.5.2 Implémentation de la fonction de fermeture void fermetureFunction(const Image* in, Image * out) Cette fonction effectue un traitement de fermeture sur une image. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. L’image donné en paramètre Image * out est allouée par la fonction. Dans cette fonction, on fait appel successivement aux fonctions dilatationFunction et erosionFunction. Cette fonction créer une image temporaire allouée qui est l’image de sortie de la fonction dilatationFunction et l’image d’entrée de la fonction erosionFunction. La mémoire allouée de l’image temporaire est finalement libérée à la fin du traitement. Exemple de résultat de la fontion fermetureFunction : A noter qu’avant le traitement d’érosion, l’image subit un traitement de seuillage qui était déjà implémenté dans le projet. lena.ras original lena.ras après seuillage + fermeture 14/53 2.6 Fonction de traitement de filtrage par moyenne 2.6.1 Algorithme de filtrage par moyenne Il consiste à lisser l’image en appliquant sur chaque pixel de cette image un masque ne contenant que des valeurs à 1 : cet algorithme s’apparente à l’algorithme de Sobel mis à part que les valeurs d’un unique masque sont toutes à 1. 2.6.2 Implémentation de la fonction de filtrage par moyenne void filtreMoyenneFunction(const Image* in, Image * out, int maskSize) Cette fonction effectue un filtrage par moyenne sur une image. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. Le paramètre int maskSize est un entier définissant la taille du masque qui contiendra que des valeurs 1 : cette taille doit être impaire et supérieure ou égal à 3. L’image donné en paramètre Image * out est allouée par la fonction. La fonction effectue d’abord un contrôle sur les paramètres en entrée : - La taille du masque doit être impaire : on vérifie cette condition en calculant le modulo de cette taille. Si le modulo retourne la valeur 1 il s’agit bien d’une taille impaire. - La taille du masque doit être supérieure à trois. - La taille du masque ne doit pas dépasser celle de l’image d’entrée : cette taille est inférieure au nombre de colonnes et de lignes de l’image donnée en paramètre const Image * in. La fonction créé un masque de taille maskSize*maskSize ne contenant que des valeurs 1. La fonction effectue ensuite le calcul des coefficients de normalisation du masque. Ensuite La fonction effectue un parcours de tous les pixels (chaque colonne de chaque ligne) de l’image donnée en paramètre const Image * in. Pour chaque pixel de coordonnées Xpin et Ypin, la fonction calcul l’entier distanceMax (en fonction de la taille du masque) permettant de déterminer la distance maximal entre le pixel du centre et celui le plus éloigné. distanceMax étant la distance limite pour effectuer l’application du masque du pixel central : La fonction prend donc en compte les pixels voisins entourant ce pixel en fonction de distanceMax et effectue le calcul du gradient normalisé en appliquant le masque créé. Ce gradient calculé est ensuite stocké dans le pixel de coordonnées Xpout et Ypout de l’image donnée en paramètre Image * out. Il est important de noter que la fonction n’effectue pas de calcul de gradient pour les pixels contenus dans les lignes inférieures à distanceMax et les dernière lignes supérieures à taille vertical en pixels de l’image15/53 distanceMax, ainsi que ceux contenus dans les colonnes inférieures à distanceMax et les dernières colonnes supérieures à taille horizontal en pixels de l’image-distanceMax. En effet, il n’est pas possible d’appliquer un masque sur ces pixels du fait de leurs coordonnées particulières, par conséquent les gradients originaux de ces pixels sont stockés directement dans les pixels de coordonnées identiques dans l’image donnée en paramètre Image * out. Exemple de résultat de la fontion filtreMoyenneFunction : lena.ras original lena.ras après filtreMoyenneFunction 16/53 2.7 2.7.1 Fonction de traitement de segmentation par région (region-growing) Algorithme de segmentation d’image par région (region-growing) Il permet de partitionner l’image en zone homogènes selon un critère déterminé: couleur, niveau de gris. On part d’un point amorce (seed) et on l’étend en ajoutant les points de la frontière qui satisfont le critère d’homogénéité Le point amorce peut être choisi soit par un humain, soit de manière automatique en évitant les zones de fort contraste (gradient important) => méthode par amorce. amorce croissance région finale Détail de l’algorithme : On définit une zone R qui contient la région à extraire. Initialement, R contient l’amorce. On utilise une file FIFO (First In, First Out) S qui contient les points frontière Initialement, S contient le voisinage de l’amorce. On retire p dans S si p est homogène avec R, on ajoute p à R et on ajoute à S les points du voisinage de p qui ne sont pas dans R et qui ne sont pas incompatibles. sinon, on marque p comme incompatible. On recommence tant que S n’est pas vide 17/53 2.7.2 Implémentation de la fonction de segmentation d’image par région void segmentationRegionGrowing(const Image *in,Image *out, int xPixelSeed, int yPixelSeed, int seuil) Cette fonction effectue une segmentation d’image par région. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. Le paramètre int xPixelSeed est un entier indiquant la position en abscisse de l’amorce. Le paramètre int yPixelSeed est un entier indiquant la position en ordonnée de l’amorce. Le paramètre int seuil est un entier indiquant un seuil de différence de gradient maximal à ne pas dépasser pour qu’un pixel puisse être inclus dans une région. L’image donné en paramètre Image * out est allouée par la fonction. Dans le cadre de cette fonction, une structure Pixel a été définie dans le fichier traitement.h afin de pouvoir stocker pour un pixel donné ses coordonnées et son gradient : typedef struct Pixel { Int x, Int y, Int gradient ; } Pixel ; Ensuite, il a fallu définir un composant supplémentaire pour la gestion d’une pile de type FIFO (first in first out) : les fichiers fifo.h et fifo.C. Le fichier fifo.h contient les prototypes de fonctions permettant la mise en œuvre d’une pile de type FIFO (first in first out) contenant pour chaque élément une structure de type Pixel. Le fichier fifo.c implémente en C les fonctions définies dans fifo.h. Une structure est définie dans fifo.h permettant de stocker les éléments d’une pile fifo : typedef struct fifo { Pixel * pixel ; Struct fifo * suivant ; }fifo ; 18/53 Les fonctions suivantes ont été implémentées : - fifo ** initFifo(fifo ** pile, int size) : cette fonction initialise et alloue (taille donnée en paramètre) la mémoire nécessaire pour une pile de type fifo. Elle renvoie un pointeur de pointeur de structure de type fifo. - void pushIntoFifo(fifo ** pile, Pixel * p) : cette fonction ajoute un élément à la pile. Cet élément ajouté contient un pointeur sur une copie de la structure Pixel qui était pointé par le paramètre Pixel * p. - int isAlreadyInFifo(fifo ** pile, Pixel * p) : cette fonction recherche un élément dans la pile Fifo, le critère de recherche étant le pixel pointé par le paramètre Pixel * p. Si la fonction trouve cet élément alors elle retourne 1 sinon 0. - Pixel * fifoPop(fifo ** pile, Pixel * buffer) : cette fonction retire le premier élément de la pile Fifo. La fonction retourne un pointeur sur la copie d’une structure de type Pixel qui était pointée dans le contenu de l’élément supprimé. - void fifoClear(fifo ** pile) : cette fonction supprime tous les éléments de la pile fifo. - int sizeOfFifo(fifo ** pile) : cette fonction retourne le nombre d’éléments de la pile fifo. La fonction segmentationRegionGrowing contrôle en premier lieu si les coordonnées de l’amorce données en paramètres ne dépassent pas l’image. Ensuite la fonction effectue une phase d’initialisation : elle alloue un pointeur de structure de type Pixel qui permettra de stocker les pixels appartenant à la région : Pixel * region. Le premier élément pointé par à la région est une structure de type Pixel contenant les coordonnées du pixel amorce ainsi que son gradient à partir de l’image donnée en paramètre const Image * in. La fonction alloue un pointeur de structure de type Pixel qui permettra de stocker les pixels dits « incompatibles » : Pixel * incompatibles. La fonction initialise une pile de type FIFO et y stocke (via la fonction pushIntoFifo) les 8 pixels voisins qui entourent le pixel amorce. Ensuite la fonction effectue une boucle jusqu’à ce que la taille de la pile FIFO soit nulle et à chaque itération effectue les traitements suivants : - elle récupère un pixel de la pile FIFO (via la fonction fifoPop). - Elle calcule le gradient moyen de la région et regarde si la valeur absolue de la soustraction du gradient un pixel récupéré et du gradient moyen est inférieur ou non au seuil. - Si cette valeur calculée est supérieur au seuil, alors le pixel est ajouté à la liste des incompatibles via le pointeur Pixel * incompatibles en ayant vérifié au préalable que ce pixel n’était pas déjà présent parmi les incompatibles (on évite ainsi les doublons inutiles). - Si cette valeur calculée est inférieur au seuil, alors le pixel est ajouté à la région via le pointeur Pixel * region. Puis, la fonction récupère les 8 pixels voisins entourant le pixel : les pixels n’appartenant ni à la région, ni aux incompatibles et n’étant pas déjà stockés dans la pile FIFO (testés via la fonction isAlreadyInFifo) sont alors stockés dans la pile FIFO (via la fonction pushIntoFifo). 19/53 Une fois toutes les itérations nécessaires effectuées, le pointeur Pixel * region permet alors d’accéder à tous les pixels de la région étendue (growing-region). La fonction effectue alors une dans une première passe une copie de tous les pixels de l’image donnée en paramètre const Image * in vers l’image donnée en paramètre Image * out. Puis dans une seconde passe, elle récupère toutes les coordonnées des pixels de la région via le pointeur Pixel * region et met la valeur du gradient à 255 (blanc) (c’est un choix totalement arbitraire) pour tous les pixels de coordonnées similaires de l’image donnée en paramètre Image * out. Au final, la fonction vide la pile FIFO et libère les pointeurs Pixel * region et Pixel * incompatibles. Ainsi, il apparait sur l’image traitée une zone blanche qui correspond à la zone de segmentation calculée. Bien évidemment, le choix de colorer en blanc la zone de segmentation est arbitraire car à partir du moment où l’on connait les coordonnées des pixels de la région tous les types de traitement de ces pixels sont possibles (on pourrait par exemple lisser la totalité de l’image par la fonction filtre par moyenne sauf la partie segmentée qui pourrait rester non lissée de manière à mieux la faire ressortir). 20/53 Exemple de résultat de la fontion segmentationRegionGrowing : A noter qu’avant le traitement de segmentation, l’image subit un traitement de filtre par moyenne. La taille de l’image d’origine est de 256 pixel * 256 pixels : femme.ras original L’exemple suivant est le résultat d’une segmentation avec comme paramètres un pixel amorce en x = 220, y = 100 avec un seuil à 60 : Un autre exemple avec comme paramètres un pixel amorce en x = 1, y = 1 avec un seuil à 20 : 21/53 2.7.3 Implémentation de la fonction de segmentation d’image par région avec un pixel d’amorce choisi au hasard void segmentationRegionGrowingRandomSeed(const Image *in,Image *out, int seuil) Cette fonction effectue une segmentation d’image par région identique à la fonction segmentationRegionGrowing, mis à part que c’est la fonction qui détermine les coordonnées du pixel d’amorce au hasard. Le paramètre const Image * in est un pointeur de type Image alloué par l’application faisant appel a cette fonction. Le paramètre Image * out est un pointeur de structure de type Image (non alloué) qui permettra de stocker l’image qui sera traitée. Le paramètre int seuil est un entier indiquant un seuil de différence de gradient maximal à ne pas dépasser pour qu’un pixel puisse être inclus dans une région. La fonction détermine au hasard, via la fonction rand() de la librairie stdlib.h une coordonnée x inférieur à la largeur en pixels de l’image const Image * in et une coordonnée y inférieur à la longueur en pixels de l’image const Image * in. Une fois ces deux coordonnées déterminées, la fonction fait appel à la fonction segmentationRegionGrowing de base avec en paramètres les coordonnées du pixel d’amorce calculés précédemment. 22/53 3 Difficultés rencontrées La première difficulté du projet a été de s’apercevoir que la compilation du projet d’origine (sans les fonctionnalités implémentées expliquées précédemment) nécessitait l’installation de la librairie x11-dev sous linux. En effet, il est important de ne pas faire l’amalgame entre la libraire x11 qui était déjà installée par défaut sur notre machine de développement (linux ubuntu 6.0.6) et la librairie x11-dev qui est une API offrant les fonctions nécessaires au développement d’application graphique et sur laquelle s’appuie les différents programmes du projet. Ensuite, la seconde difficulté principale a été l’écriture de la fonction Sobel générique : genericSobelFunction. Cette dernière se veut la plus générique possible car c’est à l’application utilisant cette fonction de donner en paramètres les masques horizontal et vertical ainsi que la taille de ces masques. Cette généricité entrainait une plus grande complexité que la fonction basicThreeSobelFunction (où les masques sont codés en dur) : elle nécessitait des contrôles supplémentaires des pixels de bordure d’image à ne pas traiter en fonction de la taille des masques vertical et horizontal. Cette dernière difficulté résolue nous a permis de bien appréhender la fonction filtreMoyenneFunction dont le paramètre int maskSize entrainait une complexité similaire. Enfin, la difficulté principale fut avant tout l’implémentation de la fonction segmentationRegionGrowing. En effet, il était d’abord nécessaire de bien comprendre l’algorithme de segmentation « region-growing » avant de pouvoir le coder. Ensuite nous avons été contraints, afin de suivre rigoureusement l’algorithme, de créer une structure de type Pixel permettant le stockage des coordonnées d’un pixel et son gradient, mais surtout de coder un nouveau module proposant des fonctions de manipulation d’une pile de type FIFO (first in first out). Une fois ce module développé, nous avons pu coder l’algorithme de segmentation dans les meilleures conditions, en prenant soin de maitriser correctement les allocations et libérations mémoire des pointeurs de structures Pixel (pour les pixels appartenant à la région et les pixels incompatibles) et de la pile FIFO. Par rapport à l’algorithme initial, nous avons essayé d’optimiser le code en effectuant des contrôles supplémentaires afin de ne pas stocker de doublons dans la pile FIFO et de ne pas ajouter de doublons inutiles dans la liste des pixels incompatibles. 23/53 4 Conclusion Ce projet fut une expérience motivante pour appréhender les problématiques de base inhérentes aux traitements d’images. Il nous a permis de conforter nos connaissances en termes de codage C, tout en intégrant une dimension « plus ludique » à la programmation : il était motivant de pouvoir observer graphiquement et concrètement les résultats de nos fonctions implémentées et d’imaginer des applications possibles à ce type de traitements d’images. Même si nous n’avons pas abordé ce sujet dans ce rapport, il est très intéressant pour une même fonctionnalité de segmentation d’image de voir les nombreuses approches possibles pour la mettre en œuvre. En effet, la segmentation par « region-growing » est l’approche la plus facile et la plus intuitive, mais c’est aussi celle qui nécessite les temps de traitements les plus longs et donc au demeurant la moins efficace. Il existe ainsi d’autres approches plus optimisées de cette fonctionnalité à travers les algorithmes dits de Split & Merge, de CSC, de Contours actifs et même à travers une approche probabiliste (algorithme de « condensation »). Le traitement d’image est une discipline à part entière nécessitant à la fois de bonnes connaissances en mathématiques et une bonne maitrise de la programmation et de l’optimisation d’algorithmes. Elle se veut concrète puisqu’applicable dans de nombreux domaines scientifiques et industrielles…par exemple, il n’est pas étonnant de s’apercevoir que l’algorithme de segmentation est directement appliqué pour l’analyse de séquences d’images IRM en médecine. A travers cette découverte des bases du traitement d’images, c’est un domaine nouveau et vaste qui s’est ouvert à nous. 24/53 5 Sources du projet 5.1 Fichier traitement.h : #ifndef SEUILLAGE_H #define SEUILLAGE_H #include "image.h" extern void seuillage(const Image * in, Image * out, octet seuil); extern void seuillageRVB(const ImageRVB * in, ImageRVB * out, octet seuil); extern void basicThreeSobelFunction(const Image * in,Image * out); extern void genericSobelFunction(const Image * in,Image * out,int ** maskV,int ** maskH,int maskSize); extern void erosionFunction(const Image* in,Image * out); extern void dilatationFunction(const Image* in,Image * out); extern void ouvertureFunction(const Image* in,Image * out); extern void fermetureFunction(const Image* in,Image * out); extern void filtreMoyenneFunction(const Image* in,Image * out,int maskSize); extern void segmentationRegionGrowing(const Image * in,Image * out, int xPixelSeed,int yPixelSeed,int seuil); extern void segmentationRegionGrowingRandomSeed(const Image * in,Image * out,int seuil); typedef struct Pixel { int x; int y; int gradient; } Pixel; #endif /* SEUILLAGE_H */ 25/53 5.2 Fichier traitement.C : #include #include #include #include #include #include #include #include "image.h" "traitement.h" <math.h> <malloc.h> <stdio.h> "fifo.h" <stdlib.h> "time.h" #define C 0 #define NC 255 void seuillage(const Image * in, Image * out, octet seuil) { int l = 0, c = 0; int nbRowI = in->nbRow, nbColI = in->nbCol; mallocImage(out,nbRowI,nbColI); // Si necessaire for(l=0;l<nbRowI;l++) { for(c=0;c<nbColI;c++) { out->zone[l][c] = (in->zone[l][c]>seuil) ? C : NC; // original : out->zone[l][c] = (in->zone[l][c]>seuil) ? C : NC; ?? } } } void seuillageRVB(const ImageRVB * in, ImageRVB * out, octet seuil) { int nbRowI = in->nbRow, nbColI = in->nbCol; mallocImageRVB(out,nbRowI,nbColI); seuillage(&in->R,&out->R,seuil); seuillage(&in->V,&out->V,seuil); seuillage(&in->B,&out->B,seuil); } //--------------------------------------------------------------------------------------------------// Fonction : basicThreeSobelFunction(const Image * in, Image * out) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // 26/53 // Cette fonction effectue un traitement "sobel" sur une image, à partir d'un mask vertical et horizontal // de taille 3*3. // // Le mask vertical est en dur dans la fonction : // maskV : -1 0 1 // -2 0 2 // -1 0 1 // // Le mask horizontal est en dur dans la fonction : // maskH : 1 2 1 // 0 0 0 // -1 -2 -1 //--------------------------------------------------------------------------------------------------void basicThreeSobelFunction(const Image * in,Image * out) { //recuperation du nombre de ligne de l'image in int nbRowI = in->nbRow; //recuperation du nombre de colonnes de l'image in int nbColI = in->nbCol; //initialisation du mask vertical int maskV[3][3]; maskV[0][0]=-1; maskV[0][1]= 0; maskV[0][2]= 1; maskV[1][0]=-2; maskV[1][1]= 0; maskV[1][2]= 2; maskV[2][0]=-1; maskV[2][1]= 0; maskV[2][2]= 1; int sommeCoefsPosMaskV=4; //somme des coefficients positifs //initialisation du mask horizontal int maskH[3][3]; maskH[0][0]=1; maskH[0][1]= 2; maskH[0][2]= 1; maskH[1][0]=0; maskH[1][1]= 0; maskH[1][2]= 0; maskH[2][0]=-1; maskH[2][1]= -2; maskH[2][2]=-1; int sommeCoefsPosMaskH=4; //somme des coefficients positifs //reservation memoire pour l image de sortie qui va etre generee mallocImage(out,nbRowI,nbColI); out->nbRow=nbRowI; out->nbCol=nbColI; 27/53 //on va parcourir toutes les lignes et colonnes de l'image int cptLine=0; //compteur de ligne int cptCol=0; //compteur de colonne for(cptLine=0;cptLine<nbRowI;cptLine++) { //parcours des colonnes for(cptCol=0;cptCol<nbColI;cptCol++) { //on ne traite pas la 1ere ni la derniere ligne,et la 1ere ni la derniere colonne //car les points appartenant a ces lignes et colonnes ne peuvent pas etre encadres par un mask if((cptLine!=0 && cptLine<nbRowI-1)&&(cptCol!=0 && cptCol<nbColI-1)) { int pixelMatrice[3][3]; pixelMatrice[0][0]=in->zone[cptLine-1][cptCol-1]; pixelMatrice[0][1]=in->zone[cptLine-1][cptCol]; pixelMatrice[0][2]=in->zone[cptLine-1][cptCol+1]; pixelMatrice[1][0]=in->zone[cptLine][cptCol-1]; pixelMatrice[1][1]=in->zone[cptLine][cptCol]; pixelMatrice[1][2]=in->zone[cptLine][cptCol+1]; pixelMatrice[2][0]=in->zone[cptLine+1][cptCol-1]; pixelMatrice[2][1]=in->zone[cptLine+1][cptCol]; pixelMatrice[2][2]=in->zone[cptLine+1][cptCol+1]; //calcul gradient vertical du point int dv=(maskV[0][0]*pixelMatrice[0][0] +maskV[0][1]*pixelMatrice[0][1] +maskV[0][2]*pixelMatrice[0][2] +maskV[1][0]*pixelMatrice[1][0] +maskV[1][1]*pixelMatrice[1][1] +maskV[1][2]*pixelMatrice[1][2] +maskV[2][0]*pixelMatrice[2][0] +maskV[2][1]*pixelMatrice[2][1] +maskV[2][2]*pixelMatrice[2][2])/sommeCoefsPosMaskV; //calcul gradient horizontal du point int dh=(maskH[0][0]*pixelMatrice[0][0] +maskH[0][1]*pixelMatrice[0][1] +maskH[0][2]*pixelMatrice[0][2] +maskH[1][0]*pixelMatrice[1][0] +maskH[1][1]*pixelMatrice[1][1] +maskH[1][2]*pixelMatrice[1][2] +maskH[2][0]*pixelMatrice[2][0] +maskH[2][1]*pixelMatrice[2][1] +maskH[2][2]*pixelMatrice[2][2])/sommeCoefsPosMaskH; // calcul du gradient int gradient=int (sqrt(dv*dv+dh*dh)); out->zone[cptLine][cptCol]=gradient; } else 28/53 { //copie dans l image out des valeurs des pixels originaux out->zone[cptLine][cptCol]=in->zone[cptLine][cptCol]; } } } //out->ptrZone=in->zone[0]; ???? } //-------------------------------------------------------------------------------------------------------// Fonction : genericSobelFunction(const Image * in, Image * out,int ** maskV,int ** maskH,int maskSize) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // int ** maskV : un pointeur de pointeurs d entiers qui contient un mask vertical // alloue par l application appellant cette fonction et de taille // maskSize*maskSize. // int ** maskH : un pointeur de pointeurs d entiers qui contient un mask horizontal // alloue par l application appellant cette fonction et de taille // maskSize*maskSize. // int maskSize : taille des masks donnes en parametres : cette taille doit etre impair // et superieur ou egal a 3. // // Cette fonction effectue un sobel sur une image, à partir d'un mask vertical et horizontal // donnes en parametres. //-------------------------------------------------------------------------------------------------------void genericSobelFunction(const Image * in,Image * out,int ** maskV,int ** maskH,int maskSize) { //contrôle si maskSize est impair et superieur ou egal a 3 //et que le mask n est pas plus grand que l image int ctlModMask=(int)fmod(maskSize,2); if(ctlModMask==1 && maskSize>=3 && maskSize<in->nbRow && maskSize<in->nbCol) { //recuperation du nombre de ligne de l'image in int nbRowI = in->nbRow; //recuperation du nombre de colonnes de l'image in int nbColI = in->nbCol; //calcul de la somme des coefficients de maskV int sommeCoefsPosMaskV=0; for(int i=0;i<maskSize;i++) { for(int j=0;j<maskSize;j++) { 29/53 if(maskV[i][j]>0) { sommeCoefsPosMaskV=sommeCoefsPosMaskV+maskV[i][j]; } } } //calcul de la somme des coefficients de maskH int sommeCoefsPosMaskH=0; for(int i=0;i<maskSize;i++) { for(int j=0;j<maskSize;j++) { if(maskH[i][j]>0) { sommeCoefsPosMaskH=sommeCoefsPosMaskH+maskH[i][j]; } } } //reservation memoire pour l image de sortie qui va etre generee mallocImage(out,nbRowI,nbColI); out->nbRow=nbRowI; out->nbCol=nbColI; //on va parcourir toutes les lignes et colonnes de l'image int cptLine=0; //compteur de ligne int cptCol=0; //compteur de colonne for(cptLine=0;cptLine<nbRowI;cptLine++) { //parcours des colonnes for(cptCol=0;cptCol<nbColI;cptCol++) { int distanceMax=(maskSize-1)/2; //distance max entre le pixel du centre et celui le plus eloigne if((cptLine>distanceMax && cptLine<nbRowI-distanceMax)&&(cptCol>distanceMax && cptCol<nbColI-distanceMax)) { //int pixelMatrice[maskSize][maskSize]; int ** pixelMatrice=(int **)malloc(sizeof(int*)*maskSize); for(int cptAlloc=0;cptAlloc<maskSize;cptAlloc++) { int * tmp=(int*)malloc(sizeof(int)*maskSize); *(pixelMatrice+cptAlloc)=tmp; } int distanceMax=(maskSize-1)/2; //distance max entre le pixel du centre et celui le plus eloigne for(int i=0;i<maskSize;i++) { 30/53 for(int j=0;j<maskSize;j++) { pixelMatrice[i][j]=in->zone[cptLine+i-distanceMax][cptCol+j-distanceMax]; } } //calcul gradient vertical du point int dv=0; for(int i=0;i<maskSize;i++) { for(int j=0;j<maskSize;j++) { dv=dv+maskV[i][j]*pixelMatrice[i][j]; } } dv=dv/sommeCoefsPosMaskV; //calcul gradient horizontal du point int dh=0; for(int i=0;i<maskSize;i++) { for(int j=0;j<maskSize;j++) { dh=dh+maskH[i][j]*pixelMatrice[i][j]; } } dh=dh/sommeCoefsPosMaskH; //desallocation de pixelMatrice for(int cptAlloc=0;cptAlloc<maskSize;cptAlloc++) { free(*(pixelMatrice+cptAlloc)); } free(pixelMatrice); // calcul du gradient int gradient=int (sqrt(dv*dv+dh*dh)); out->zone[cptLine][cptCol]=gradient; } else { //copie dans l image out des valeurs des pixels originaux out->zone[cptLine][cptCol]=in->zone[cptLine][cptCol]; } } } } } 31/53 //-------------------------------------------------------------------------------------------------------// Fonction : erosionFunction(const Image * in, Image * out) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l'application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // // Cette fonction effectue un traitement d "erosion" sur une image. //--------------------------------------------------------------------------------------------------------void erosionFunction(const Image* in,Image * out) { //recuperation du nombre de ligne de l'image in int nbRowI = in->nbRow; //recuperation du nombre de colonnes de l'image in int nbColI = in->nbCol; //reservation memoire pour l image de sortie qui va etre generee mallocImage(out,nbRowI,nbColI); out->nbRow=nbRowI; out->nbCol=nbColI; int cptLine=0; //compteur de ligne int cptCol=0; //compteur de colonne for(cptLine=0;cptLine<nbRowI;cptLine++) { //parcours des colonnes for(cptCol=0;cptCol<nbColI;cptCol++) { //on ne traite pas la 1ere ni la derniere ligne,et la 1ere ni la derniere colonne if((cptLine!=0 && cptLine<nbRowI-1)&&(cptCol!=0 && cptCol<nbColI-1)) { //si le pixel est noir int valeurPixel=in->zone[cptLine][cptCol]; if(valeurPixel==C) { // 0 1 2 // 3 p 4 // 5 6 7 int p0=in->zone[cptLine-1][cptCol-1]; int p1=in->zone[cptLine-1][cptCol]; int p2=in->zone[cptLine-1][cptCol+1]; int p3=in->zone[cptLine][cptCol-1]; int p4=in->zone[cptLine][cptCol+1]; int p5=in->zone[cptLine+1][cptCol-1]; int p6=in->zone[cptLine+1][cptCol]; int p7=in->zone[cptLine+1][cptCol+1]; if(p0==NC || p1==NC || p2==NC || p3==NC || p4==NC || p5==NC || p6==NC ||p7==NC) { 32/53 //un pixel dans son entourage direct est blanc //alors le pixel p devient blanc valeurPixel=NC; } } out->zone[cptLine][cptCol]=valeurPixel; } else { //copie dans l image out des valeurs des pixels originaux out->zone[cptLine][cptCol]=in->zone[cptLine][cptCol]; } } } } //-------------------------------------------------------------------------------------------------------// Fonction : dilatationFunction(const Image * in, Image * out) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l'application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // // Cette fonction effectue un traitement de "dilatation" sur une image. //--------------------------------------------------------------------------------------------------------void dilatationFunction(const Image* in,Image * out) { //recuperation du nombre de ligne de l'image in int nbRowI = in->nbRow; //recuperation du nombre de colonnes de l'image in int nbColI = in->nbCol; //reservation memoire pour l image de sortie qui va etre generee mallocImage(out,nbRowI,nbColI); out->nbRow=nbRowI; out->nbCol=nbColI; int cptLine=0; //compteur de ligne int cptCol=0; //compteur de colonne for(cptLine=0;cptLine<nbRowI;cptLine++) { //parcours des colonnes for(cptCol=0;cptCol<nbColI;cptCol++) { //on ne traite pas la 1ere ni la derniere ligne,et la 1ere ni la derniere colonne if((cptLine!=0 && cptLine<nbRowI-1)&&(cptCol!=0 && cptCol<nbColI-1)) { //si le pixel est blanc 33/53 int valeurPixel=in->zone[cptLine][cptCol]; if(valeurPixel==NC) { // 0 1 2 // 3 p 4 // 5 6 7 int p0=in->zone[cptLine-1][cptCol-1]; int p1=in->zone[cptLine-1][cptCol]; int p2=in->zone[cptLine-1][cptCol+1]; int p3=in->zone[cptLine][cptCol-1]; int p4=in->zone[cptLine][cptCol+1]; int p5=in->zone[cptLine+1][cptCol-1]; int p6=in->zone[cptLine+1][cptCol]; int p7=in->zone[cptLine+1][cptCol+1]; if(p0==C || p1==C || p2==C || p3==C || p4==C || p5==C || p6==C ||p7==C) { //un pixel dans son entourage direct est noir //alors le pixel p devient noir valeurPixel=C; } } out->zone[cptLine][cptCol]=valeurPixel; } else { //copie dans l image out des valeurs des pixels originaux out->zone[cptLine][cptCol]=in->zone[cptLine][cptCol]; } } } } //-------------------------------------------------------------------------------------------------------// Fonction : ouvertureFunction(const Image * in, Image * out) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // // Cette fonction effectue un traitement d "ouverture" sur une image : il s agit sur une image d appliquer // 2 traitements successifs sur l image : une erosion suivie d une dilatation. //--------------------------------------------------------------------------------------------------------void ouvertureFunction(const Image* in,Image * out) { Image iTmp; //une ouverture se fait via 2 traitements successifs : une erosion suivi d une dilatation de l image. erosionFunction(in,&iTmp); dilatationFunction(&iTmp,out); 34/53 freeImage(&iTmp); } //-------------------------------------------------------------------------------------------------------// Fonction : fermetureFunction(const Image * in, Image * out) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // // Cette fonction effectue un traitement de "fermeture" sur une image : il s agit sur une image d appliquer // 2 traitements successifs sur l image : une dilatation suivie d une erosion. C est donc le procede // inverse d une "ouverture". //--------------------------------------------------------------------------------------------------------void fermetureFunction(const Image* in,Image * out) { Image iTmp; //une fermeture se fait via 2 traitements successifs : une dilatation suivi d une erosion de l image. dilatationFunction(in,&iTmp); erosionFunction(&iTmp,out); freeImage(&iTmp); } //---------------------------------------------------------------------------------------------------------// Fonction : filtreMoyenneFunction(const Image * in,Image * out,int maskSize) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // int maskSize : la taille du mask qui servira au filtre par la moyenne, elle doit etre // superieur ou egal a 3 et impair. // // Cette fonction effectue un filtre dit "de la moyenne" sur une image : il s agit d appliquer un mask // contenant que des valeurs 1 de taille maskSize sur les pixels de l image. // exemple pour un mask de taille 3 : 1 1 1 // 1 1 1 // 1 1 1 //---------------------------------------------------------------------------------------------------------void filtreMoyenneFunction(const Image* in,Image * out,int maskSize) { //contrôle si maskSize est impair et superieur ou egal a 3 //et que le mask n est pas plus grand que l image int ctlModMask=(int)fmod(maskSize,2); if(ctlModMask==1 && maskSize>=3 && maskSize<in->nbRow && maskSize<in->nbCol) { //creation d'une matrice de taille maskSize contenant que des 1 int ** mask=(int**)malloc(sizeof(int*)*maskSize); for(int cpt=0;cpt<maskSize;cpt++) { 35/53 int * tmp=(int*)malloc(sizeof(int)*maskSize); *(tmp)=1; *(tmp+1)=1; *(tmp+2)=1; *(mask+cpt)=tmp; } //recuperation du nombre de ligne de l'image in int nbRowI = in->nbRow; //recuperation du nombre de colonnes de l'image in int nbColI = in->nbCol; //calcul de la somme des coefficients de maskV int sommeCoefsPosMask=0; for(int i=0;i<maskSize;i++) { for(int j=0;j<maskSize;j++) { if(mask[i][j]>0) { sommeCoefsPosMask=sommeCoefsPosMask+mask[i][j]; } } } //reservation memoire pour l image de sortie qui va etre generee mallocImage(out,nbRowI,nbColI); out->nbRow=nbRowI; out->nbCol=nbColI; //on va parcourir toutes les lignes et colonnes de l'image int cptLine=0; //compteur de ligne int cptCol=0; //compteur de colonne for(cptLine=0;cptLine<nbRowI;cptLine++) { //parcours des colonnes for(cptCol=0;cptCol<nbColI;cptCol++) { int distanceMax=(maskSize-1)/2; //distance max entre le pixel du centre et celui le plus eloigne if((cptLine>distanceMax && cptLine<nbRowI-distanceMax)&&(cptCol>distanceMax && cptCol<nbColI-distanceMax)) { int ** pixelMatrice=(int **)malloc(sizeof(int*)*maskSize); for(int cptAlloc=0;cptAlloc<maskSize;cptAlloc++) { int * tmp=(int*)malloc(sizeof(int)*maskSize); *(pixelMatrice+cptAlloc)=tmp; 36/53 } for(int i=0;i<maskSize;i++) { for(int j=0;j<maskSize;j++) { pixelMatrice[i][j]=in->zone[cptLine+i-distanceMax][cptCol+j-distanceMax]; } } //calcul gradient int dv=0; for(int i=0;i<maskSize;i++) { for(int j=0;j<maskSize;j++) { dv=dv+mask[i][j]*pixelMatrice[i][j]; } } dv=dv/sommeCoefsPosMask; //desallocation de pixelMatrice for(int cptAlloc=0;cptAlloc<maskSize;cptAlloc++) { free(*(pixelMatrice+cptAlloc)); } free(pixelMatrice); // calcul du gradient int gradient=dv; out->zone[cptLine][cptCol]=gradient; } else { //copie dans l image out des valeurs des pixels originaux out->zone[cptLine][cptCol]=in->zone[cptLine][cptCol]; } } } //liberation memoire du mask for(int cpt=0;cpt<maskSize;cpt++) { free(*(mask+cpt)); } free(mask); } 37/53 } //-----------------------------------------------------------------------------------------------------------------// Fonction : segmentationRegionGrowing(const Image * in,Image * out,int xPixelSeed,int yPixelSeed,int seuil) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // int xPixelSeed : coordonnee x du point de depart a partir duquel l algorithme regionGrowing demarre. // int yPixelSeed : coordonnee y du point de depart a partir duquel l algorithme regionGrowing demarre. // int seuil : pour chaque pixel rencontree, le critere de selection pour l appartenance a la region // s appuie sur ce seuil. // // Cette fonction effectue une segmentation de l image en utilisant l algorithme "region growing". //------------------------------------------------------------------------------------------------------------------void segmentationRegionGrowing(const Image * in,Image * out, int xPixelSeed,int yPixelSeed,int seuil) { //recuperation du nombre de ligne de l'image in int nbRowI = in->nbRow; //recuperation du nombre de colonnes de l'image in int nbColI = in->nbCol; if(xPixelSeed<=nbColI && yPixelSeed<=nbRowI) { //reservation memoire pour l image de sortie qui va etre generee mallocImage(out,nbRowI,nbColI); out->nbRow=nbRowI; out->nbCol=nbColI; //--------------------------------------------------------// // INITIALISATION // // la region contient l amorce (pixelSee) // // et la pile fifo contiendra le voisinage de l amorce // //--------------------------------------------------------// //allocation memoire pour des structures de srgPixel pour la region Pixel *region=(Pixel*)malloc(sizeof(Pixel)*(nbRowI*nbColI)); //allocation memoire pour des structures de srgPixel pour la liste des incompatibles Pixel *incompatibles=(Pixel*)malloc(sizeof(Pixel)*(nbRowI*nbColI)); int cptPixelsRegion=0; int cptPixelsIncompatibles=0; //on inclus le pixelSeed dans la region region->x=xPixelSeed; region->y=yPixelSeed; region->gradient=in->zone[yPixelSeed][xPixelSeed]; cptPixelsRegion++; 38/53 //initialisation de la pile Fifo qui contiendra les pixels voisins (qui n appartiennent pas a la region ni a la liste des //incompatibles ) d un pixel en analyse. fifo** pile; pile=initFifo(pile,nbRowI*nbColI); //voisinage de l amorce //contrôle les 8 pixels entourant // 0 1 2 // 3 p 4 // 5 6 7 Pixel * srgP0=(Pixel*)malloc(sizeof(Pixel)); srgP0->x=xPixelSeed-1; srgP0->y=yPixelSeed-1; srgP0->gradient=in->zone[srgP0->y][srgP0->x]; Pixel * srgP1=(Pixel*)malloc(sizeof(Pixel)); srgP1->x=xPixelSeed; srgP1->y=yPixelSeed-1; srgP1->gradient=in->zone[srgP1->y][srgP1->x]; Pixel * srgP2=(Pixel*)malloc(sizeof(Pixel)); srgP2->x=xPixelSeed+1; srgP2->y=yPixelSeed-1; srgP2->gradient=in->zone[srgP2->y][srgP2->x]; Pixel * srgP3=(Pixel*)malloc(sizeof(Pixel)); srgP3->x=xPixelSeed-1; srgP3->y=yPixelSeed; srgP3->gradient=in->zone[srgP3->y][srgP3->x]; Pixel * srgP4=(Pixel*)malloc(sizeof(Pixel)); srgP4->x=xPixelSeed+1; srgP4->y=yPixelSeed; srgP4->gradient=in->zone[srgP4->y][srgP4->x]; Pixel * srgP5=(Pixel*)malloc(sizeof(Pixel)); srgP5->x=xPixelSeed-1; srgP5->y=yPixelSeed+1; srgP5->gradient=in->zone[srgP5->y][srgP5->x]; Pixel * srgP6=(Pixel*)malloc(sizeof(Pixel)); srgP6->x=xPixelSeed; srgP6->y=yPixelSeed+1; srgP6->gradient=in->zone[srgP6->y][srgP6->x]; Pixel * srgP7=(Pixel*)malloc(sizeof(Pixel)); srgP7->x=xPixelSeed+1; srgP7->y=yPixelSeed+1; srgP7->gradient=in->zone[srgP7->y][srgP7->x]; 39/53 pushIntoFifo(pile,srgP0); //le push effectue une copie local dans la fonction du pixel pushIntoFifo(pile,srgP1); pushIntoFifo(pile,srgP2); pushIntoFifo(pile,srgP3); pushIntoFifo(pile,srgP4); pushIntoFifo(pile,srgP5); pushIntoFifo(pile,srgP6); pushIntoFifo(pile,srgP7); free(srgP0); free(srgP1); free(srgP2); free(srgP3); free(srgP4); free(srgP5); free(srgP6); free(srgP7); while(sizeOfFifo(pile)!=0) { Pixel * pixel=(Pixel*)malloc(sizeof(Pixel)); pixel=fifoPop(pile,pixel); //recuperation du premier pixel de la pile //calcul du gradient moyen de la region int gradientSomme=0; int regionCpt=0; while(regionCpt<cptPixelsRegion) { Pixel* tmp=region+regionCpt; gradientSomme=gradientSomme+tmp->gradient; regionCpt++; } int gradientMoyen=(int)gradientSomme/cptPixelsRegion; //gradient moyen de la region int absGradient=(int)fabs(pixel->gradient-gradientMoyen); //on regarde si la condition pour appartenir a la region est valide if(absGradient<seuil) { //on ajoute pixel a la region Pixel * tmp=region+cptPixelsRegion; tmp->x=pixel->x; tmp->y=pixel->y; tmp->gradient=gradientMoyen; cptPixelsRegion++; //recuperation des points du voisinage de p if(pixel->x-1>=0 && pixel->x+1<nbColI && pixel->y-1>=0 && pixel->y+1<nbRowI) { Pixel * srgP0=(Pixel*)malloc(sizeof(Pixel)); 40/53 srgP0->x=pixel->x-1; srgP0->y=pixel->y-1; srgP0->gradient=in->zone[srgP0->y][srgP0->x]; Pixel * srgP1=(Pixel*)malloc(sizeof(Pixel)); srgP1->x=pixel->x; srgP1->y=pixel->y-1; srgP1->gradient=in->zone[srgP1->y][srgP1->x]; Pixel * srgP2=(Pixel*)malloc(sizeof(Pixel)); srgP2->x=pixel->x+1; srgP2->y=pixel->y-1; srgP2->gradient=in->zone[srgP2->y][srgP2->x]; Pixel * srgP3=(Pixel*)malloc(sizeof(Pixel)); srgP3->x=pixel->x-1; srgP3->y=pixel->y; srgP3->gradient=in->zone[srgP3->y][srgP3->x]; Pixel * srgP4=(Pixel*)malloc(sizeof(Pixel)); srgP4->x=pixel->x+1; srgP4->y=pixel->y; srgP4->gradient=in->zone[srgP4->y][srgP4->x]; Pixel * srgP5=(Pixel*)malloc(sizeof(Pixel)); srgP5->x=pixel->x-1; srgP5->y=pixel->y+1; srgP5->gradient=in->zone[srgP5->y][srgP5->x]; Pixel * srgP6=(Pixel*)malloc(sizeof(Pixel)); srgP6->x=pixel->x; srgP6->y=pixel->y+1; srgP6->gradient=in->zone[srgP6->y][srgP6->x]; Pixel * srgP7=(Pixel*)malloc(sizeof(Pixel)); srgP7->x=pixel->x+1; srgP7->y=pixel->y+1; srgP7->gradient=in->zone[srgP7->y][srgP7->x]; //on va tester pour tous ses pixels si ils n appartiennent pas // a la region ou a la liste des incompatibles int int int int int int int int flagNonAutorisePushFifo_srgP0=0; flagNonAutorisePushFifo_srgP1=0; flagNonAutorisePushFifo_srgP2=0; flagNonAutorisePushFifo_srgP3=0; flagNonAutorisePushFifo_srgP4=0; flagNonAutorisePushFifo_srgP5=0; flagNonAutorisePushFifo_srgP6=0; flagNonAutorisePushFifo_srgP7=0; //test pour chaque pixel si il appartient pas deja a la region 41/53 int cptRegion=0; while(cptRegion<cptPixelsRegion) { Pixel * tmp=region+cptRegion; if((tmp->x==srgP0->x)&&(tmp->y==srgP0->y)) { flagNonAutorisePushFifo_srgP0=1; } else if((tmp->x==srgP1->x)&&(tmp->y==srgP1->y)) { flagNonAutorisePushFifo_srgP1=1; } else if((tmp->x==srgP2->x)&&(tmp->y==srgP2->y)) { flagNonAutorisePushFifo_srgP2=1; } else if((tmp->x==srgP3->x)&&(tmp->y==srgP3->y)) { flagNonAutorisePushFifo_srgP3=1; } else if((tmp->x==srgP4->x)&&(tmp->y==srgP4->y)) { flagNonAutorisePushFifo_srgP4=1; } else if((tmp->x==srgP5->x)&&(tmp->y==srgP5->y)) { flagNonAutorisePushFifo_srgP5=1; } else if((tmp->x==srgP6->x)&&(tmp->y==srgP6->y)) { flagNonAutorisePushFifo_srgP6=1; } else if((tmp->x==srgP7->x)&&(tmp->y==srgP7->y)) { flagNonAutorisePushFifo_srgP7=1; } cptRegion++; } //test pour chaque pixel si il appartient pas deja a la liste des incompatibles int cptIncompatibles=0; while(cptIncompatibles<cptPixelsIncompatibles) { Pixel * tmp=incompatibles+cptIncompatibles; if((tmp->x==srgP0->x)&&(tmp->y==srgP0->y)) { flagNonAutorisePushFifo_srgP0=1; } if((tmp->x==srgP1->x)&&(tmp->y==srgP1->y)) { 42/53 flagNonAutorisePushFifo_srgP1=1; } if((tmp->x==srgP2->x)&&(tmp->y==srgP2->y)) { flagNonAutorisePushFifo_srgP2=1; } if((tmp->x==srgP3->x)&&(tmp->y==srgP3->y)) { flagNonAutorisePushFifo_srgP3=1; } if((tmp->x==srgP4->x)&&(tmp->y==srgP4->y)) { flagNonAutorisePushFifo_srgP4=1; } if((tmp->x==srgP5->x)&&(tmp->y==srgP5->y)) { flagNonAutorisePushFifo_srgP5=1; } if((tmp->x==srgP6->x)&&(tmp->y==srgP6->y)) { flagNonAutorisePushFifo_srgP6=1; } if((tmp->x==srgP7->x)&&(tmp->y==srgP7->y)) { flagNonAutorisePushFifo_srgP7=1; } cptIncompatibles++; } //ok maintenant on push dans fifo les pixel dont les flags sont restes a zero //et en s assurant qu ils ne sont pas deja dans la pile if(flagNonAutorisePushFifo_srgP0==0 && isAlreadyInFifo(pile,srgP0)==0) { pushIntoFifo(pile,srgP0); } if(flagNonAutorisePushFifo_srgP1==0 && isAlreadyInFifo(pile,srgP1)==0) { pushIntoFifo(pile,srgP1); } if(flagNonAutorisePushFifo_srgP2==0 && isAlreadyInFifo(pile,srgP2)==0) { pushIntoFifo(pile,srgP2); } if(flagNonAutorisePushFifo_srgP3==0 && isAlreadyInFifo(pile,srgP3)==0) { pushIntoFifo(pile,srgP3); } if(flagNonAutorisePushFifo_srgP4==0 && isAlreadyInFifo(pile,srgP4)==0) { pushIntoFifo(pile,srgP4); } 43/53 if(flagNonAutorisePushFifo_srgP5==0 && isAlreadyInFifo(pile,srgP5)==0) { pushIntoFifo(pile,srgP5); } if(flagNonAutorisePushFifo_srgP6==0 && isAlreadyInFifo(pile,srgP6)==0) { pushIntoFifo(pile,srgP6); } if(flagNonAutorisePushFifo_srgP7==0 && isAlreadyInFifo(pile,srgP7)==0) { pushIntoFifo(pile,srgP7); } free(srgP0); free(srgP1); free(srgP2); free(srgP3); free(srgP4); free(srgP5); free(srgP6); free(srgP7); } } else { //on ajoute le pixel parmis la liste des incompatibles //mais on verifie d abord que ce pixel n appartient pas deja a cette liste int cptInc=0; int doublonIncompatibles=0; while(cptInc<cptPixelsIncompatibles) { Pixel * tmp=incompatibles+cptInc; if((pixel->x==tmp->x)&&(pixel->y==tmp->y)) { doublonIncompatibles=1; break; } cptInc++; } if(doublonIncompatibles==0) { Pixel * tmp=incompatibles+cptPixelsIncompatibles; tmp->x=pixel->x; tmp->y=pixel->y; tmp->gradient=pixel->gradient; cptPixelsIncompatibles++; } } free(pixel); } 44/53 //on effectue la copie des pixels de in vers out int cptLine=0; //compteur de ligne int cptCol=0; //compteur de colonne for(cptLine=0;cptLine<nbRowI;cptLine++) { //parcours des colonnes for(cptCol=0;cptCol<nbColI;cptCol++) { //copie dans l image out des valeurs des pixels originaux out->zone[cptLine][cptCol]=in->zone[cptLine][cptCol]; } } //maintenant tous les pixels qui nous interessent sont dans region int cptParcoursRegion=0; while(cptParcoursRegion<cptPixelsRegion) { Pixel * tmp=region+cptParcoursRegion; out->zone[tmp->y][tmp->x]=255; cptParcoursRegion++; } //clear de la pile fifoClear(pile); //penser a faire desallocation de region et incompatibles free(region); free(incompatibles); } } //-----------------------------------------------------------------------------------------------------------------// Fonction : segmentationRegionGrowingRandomSeed(const Image * in,Image * out,int seuil) // // Parametres : const Image * in : un pointeur de structure de type Image alloue par l application // faisant appel a cette fonction. // Image * out : un pointeur de structure de type Image (non alloue) qui permettra // de stocker l image qui sera calculee par la fonction. // int seuil : pour chaque pixel rencontree, le critere de selection pour l appartenance a la region // s appuie sur ce seuil. // // Cette fonction effectue une segmentation de l image en utilisant l algorithme "region growing" : les coordonnees // du pixel d amorce (seed) sont choisies au hasard par la fonction. //------------------------------------------------------------------------------------------------------------------void segmentationRegionGrowingRandomSeed(const Image * in,Image * out,int seuil) { int xSeed; srand((unsigned)time(NULL)); //initialise srand xSeed=(unsigned int)rand(); xSeed=(xSeed%in->nbCol); 45/53 int ySeed; ySeed=(unsigned int)rand(); ySeed=(ySeed%in->nbRow); segmentationRegionGrowing(in,out,xSeed,ySeed,seuil); } 46/53 5.3 Fichier fifo.h : #include "traitement.h" typedef struct fifo { Pixel * pixel; struct fifo *suivant; }fifo; extern extern extern extern extern extern fifo** initFifo(fifo** pile,int size); void pushIntoFifo(fifo ** pile,Pixel * p); Pixel* fifoPop(fifo** pile,Pixel * buffer); void fifoClear(fifo** pile); int sizeOfFifo(fifo** pile); int isAlreadyInFifo(fifo** pile,Pixel *p); 47/53 5.4 Fichier fifo.C : #include #include #include #include "fifo.h" "traitement.h" <malloc.h> <stdio.h> //---------------------------------------------------------------------------------// - Fonction : fifo ** initFifo(fifo ** pile,int size) // // - Parametres : fifo** pile : un pointeur de pointeur de structure de type fifo // non alloue. // int size : une taille qui servira a allouer la memoire necessaire // a la pile fifo. // // Cette fonction initialise et alloue la memoire necessaire pour une pile fifo. // Elle retourne un pointeur de pointeur de structure de type fifo. //---------------------------------------------------------------------------------fifo** initFifo(fifo** pile,int size) { pile=(fifo**)malloc(sizeof(fifo*)*size); //fifo pour les frontieres *pile=NULL; return pile; } //------------------------------------------------------------------------------------// - Fonction : void pushIntoFifo(fifo ** pile,Pixel * p) // // - Parametres : fifo ** pile : un pointeur de pointeur de structure de type fifo mais // alloue (via la fonction initFifo()). // Pixel * p : un pointeur de structure de type Pixel qui sera copie et // ajoute dans un element de la pile. // // Cette fonction ajoute un element dans la pile fifo. //-------------------------------------------------------------------------------------void pushIntoFifo(fifo ** pile,Pixel * p) { fifo * p_nouveau=(fifo*)malloc(sizeof(fifo)); if(p_nouveau!=NULL) { p_nouveau->suivant=NULL; //copie du pixel Pixel* tmp=(Pixel*)malloc(sizeof(Pixel)); tmp->x=p->x; tmp->y=p->y; tmp->gradient=p->gradient; 48/53 p_nouveau->pixel=tmp; if(*pile==NULL) { *pile=p_nouveau; } else { fifo * p_tmp=*pile; while(p_tmp->suivant!=NULL) { p_tmp=p_tmp->suivant; } p_tmp->suivant=p_nouveau; } } } //------------------------------------------------------------------------------------// - Fonction : void isAlreadyInFifo(fifo ** pile,Pixel * p) // // - Parametres : fifo ** pile : un pointeur de pointeur de structure de type fifo mais // alloue (via la fonction initFifo()). // Pixel * p : un pointeur de structure de type Pixel. // // Cette fonction recherche un element dans la pile fifo, le critère de recherche // etant le pixel pointe par le parametre Pixel * p. Si la fonction trouve cet // element alors elle retourne 1 sinon 0. //-------------------------------------------------------------------------------------int isAlreadyInFifo(fifo ** pile,Pixel * p) { int found=0; fifo* p_tmp=*pile; int cpt=0; while(p_tmp->suivant!=NULL) { Pixel * tmp=p_tmp->pixel; if((tmp->x==p->x) &&(tmp->y==p->y)) { found=1; break; } else { p_tmp=p_tmp->suivant; cpt++; } } 49/53 return found; } //---------------------------------------------------------------------------------------// - Fonction : Pixel* fifoPop(fifo ** pile,Pixel * buffer) // // - Parametres : fifo ** pile : un pointeur de pointeur de structure de type fifo mais // alloue (via la fonction initFifo()). // Pixel * buffer : un pointeur de structure de type Pixel alloue par // l'application appellant cette fonction qui servira // a stocker une copie dy pixel qui était dans l'element // supprime. // // Cette fonction retire le premier element de la pile fifo. // La fonction retourne un pointeur sur la copie d une structure de type Pixel qui etait // pointee dans le contenu de l element supprime. //---------------------------------------------------------------------------------------Pixel* fifoPop(fifo** pile,Pixel * buffer) { if(pile!=NULL) { fifo* p_tmp=(*pile)->suivant; Pixel * tmp=(*pile)->pixel; if(buffer!=NULL) { //on effectue une copie dans buffer buffer->x=tmp->x; buffer->y=tmp->y; buffer->gradient=tmp->gradient; } //liberation du pixel pour l element de la fifo //free(*pile)->pixel; free(tmp); free(*pile); *pile=NULL; *pile=p_tmp; if(buffer!=NULL) { return buffer; } else { return NULL; } } return NULL; } 50/53 //---------------------------------------------------------------------------------// - Fonction : void fifoClear(fifo** pile) // // - Parametres : fifo ** pile : un pointeur de pointeur de structure de type fifo // mais alloue (via la fonction initFifo()). // // Cette fonction supprime tous les elements de la pile fifo. //---------------------------------------------------------------------------------void fifoClear(fifo** pile) { while(*pile!=NULL) { fifoPop(pile,NULL); } } //---------------------------------------------------------------------------------// - Fonction : int sizeOfFifo(fifo ** pile) // // - Parametres : fifo ** pile : un pointeur de pointeur de structure de type fifo // mais alloue (via la fonction initFifo()). // // Cette fonction retourne le nombre d'elements presents dans la pile fifo. //----------------------------------------------------------------------------------int sizeOfFifo(fifo** pile) { int cpt=0; fifo * p_tmp=*pile; while(p_tmp->suivant!=NULL) { p_tmp=p_tmp->suivant; cpt++; } return cpt; } 51/53 5.5 Fichier prog.C : /* prog.C */ #include <stdio.h> #include "image.h" #include <malloc.h> #include "traitement.h" int main(void) { Image i0; Image iSeuillage; Image iSobel; Image iErosion; Image iDilatation; Image iOuverture; Image iFermeture; Image iMoyenne; Image iSegmentation; Image iSegmentationRandom; loadImage(&i0,"../Images/femme.ras"); //seuillage(&i0,&iSeuillage,30); //basicThreeSobelFunction(&i0,&i2); int ** maskV=(int**)malloc(sizeof(int*)*3); for(int i=0;i<3;i++) { int * tmp=(int*)malloc(sizeof(int)*3); *(maskV+i)=tmp; } maskV[0][0]=-1; maskV[0][1]= 0; maskV[0][2]= 1; maskV[1][0]=-2; maskV[1][1]= 0; maskV[1][2]= 2; maskV[2][0]=-1; maskV[2][1]= 0; maskV[2][2]= 1; //initialisation du mask horizontal int ** maskH=(int**)malloc(sizeof(int*)*3); for(int i=0;i<3;i++) { int * tmp=(int*)malloc(sizeof(int)*3); *(maskH+i)=tmp; } maskH[0][0]=1; maskH[0][1]= 2; maskH[0][2]= 1; maskH[1][0]=0; maskH[1][1]= 0; maskH[1][2]= 0; maskH[2][0]=-1; maskH[2][1]= -2; maskH[2][2]=-1; genericSobelFunction(&i0,&iSobel,maskV,maskH,3); seuillage(&iSobel,&iSeuillage,30); erosionFunction(&iSeuillage,&iErosion); dilatationFunction(&iSeuillage,&iDilatation); ouvertureFunction(&iSeuillage,&iOuverture); fermetureFunction(&iSeuillage,&iFermeture); filtreMoyenneFunction(&i0,&iMoyenne,3); segmentationRegionGrowing(&iMoyenne,&iSegmentation,1,1,20); segmentationRegionGrowingRandomSeed(&iMoyenne,&iSegmentationRandom,10); 52/53 //affichage des images displayImage("../Images/femme.ras"); saveImage(&iSeuillage,"../Resultats/seuil.ras"); displayImage("../Resultats/seuil.ras"); saveImage(&iSobel,"../Resultats/sobel.ras"); displayImage("../Resultats/sobel.ras"); saveImage(&iErosion,"../Resultats/erosion.ras"); displayImage("../Resultats/erosion.ras"); saveImage(&iDilatation,"../Resultats/dilatation.ras"); displayImage("../Resultats/dilatation.ras"); saveImage(&iOuverture,"../Resultats/ouverture.ras"); displayImage("../Resultats/ouverture.ras"); saveImage(&iFermeture,"../Resultats/fermeture.ras"); displayImage("../Resultats/fermeture.ras"); saveImage(&iMoyenne,"../Resultats/moyenne.ras"); displayImage("../Resultats/moyenne.ras"); saveImage(&iSegmentation,"../Resultats/segmentation.ras"); displayImage("../Resultats/segmentation.ras"); saveImage(&iSegmentationRandom,"../Resultats/segmentationRandom.ras"); displayImage("../Resultats/segmentationRandom.ras"); freeImage(&i0); freeImage(&iSeuillage); freeImage(&iSobel); freeImage(&iErosion); freeImage(&iDilatation); freeImage(&iOuverture); freeImage(&iFermeture); freeImage(&iMoyenne); freeImage(&iSegmentation); freeImage(&iSegmentationRandom); return 0; } 53/53