• Aucun résultat trouvé

Principe de l’algorithme de van Herk-Gil-Werman

8.2 Approche employant les algorithmes à réutilisation des valeurs

8.2.1 Principe de l’algorithme de van Herk-Gil-Werman

Le fonctionnement de l’algorithme de van Herk-Gil-Werman (mentionné par l’abréviation HGW dans la suite) était décrit originalementvH92pour les éléments structurants qui ont la forme d’un segment

symétrique et qui, par conséquent, désignent le nombre impair des pixels voisins. L’algorithme HGW est composé de 3 phases. Les deux premières préparent les valeurs intermédiaires des maxima (pour la dilatation) / minima (pour l’érosion) par la propagation des valeurs ; cette propagation est effectuée à l’échelle des blocs des pixels et non de l’image entière. Dans la troisième phase, nous évaluons les résultats finaux à partir des résultats intermédiaires. La figure 8.3 illustre une vue globale sur ce fonc- tionnement en désignant par les flèches les pixels de source et de destination pour l’opération max / min et en montrant ainsi la dépendance entre les résultats intermédiaires lors de l’évaluation.

valeur du bord

valeur du bord partie de l’image d’entrée

Résultat Buffer A

Buffer B

Élément structurant

FIG. 8.3 : Schéma de fonctionnement de l’algorithme de van Herk-Gil-Werman

Expliquons le fonctionnement de cet algorithme plus en détail. Tout d’abord, nous procédons, dans la direction parallèle à l’orientation de l’élément structurant, au découpage de l’image d’entrée en blocs de pixels qui sont de la même taille que celle de l’élément structurant et qui ont la dimension 1 dans la direction perpendiculaire. C’est à l’échelle de ces macro blocs que le traitement est indépendant du sens de parcours et que c’est à l’intérieur de ces macro blocs que nous allons effectuer la propagation des valeurs. La figure 8.3 illustre ce découpage sur une partie de l’image, qui correspond à une ligne de cette image, pour l’élément structurant horizontal. Les blocs découpés de 5 pixels sont délimités par la bordure épaisse.

Lors de l’explication du fonctionnement, nous allons supposer que l’image a des dimensions des mul- tiples de la taille de l’élément structurant. On obtiendra ainsi le découpage parfait de l’image aux macro blocs. Les cas spéciaux de l’image qui ne pourraient pas être découpés parfaitement et qui contiendraient

à chaque ligne un macro bloc de taille plus petite et connexe au bord de l’image seraient gérés par le ker- nel du calcul différent, spécifique à la zone de l’image connexe au bord. Ainsi, nous suivons l’idée de la décomposition du traitement en traitements de la zone de l’intérieur et en traitement de la zone du bord, comme présentés dans le chapitre 5, page 102 dans la section 5.1.2 qui était dédié à cette problématique. La première phase, p1, de cet algorithme qui nous fournit la première série des résultats intermé-

diaires, utilise la propagation à l’intérieur des macro blocs dans une direction, choisie par convention comme la direction suivant le sens des index montants. La figure 8.4(a) illustre cette situation. La propa- gation des valeurs est effectuée de la même manière que précédemment mentionnée dans le chapitre 7, page 7.2, dans la section 7.2 dédié aux skeletons applico-rédictifs mfoldl et mfoldl1. Donc, il est naturel d’utiliser ces skeletons pour exprimer cette phase de l’algorithme HGW dans le formalisme fonctionnel. Les résultats intermédiaires que nous obtenons après l’application de cette phase sont groupés, sur la fig. 8.4(a) en tant que Buffer A.

partie de l’image d’entrée

Buffer A

(a)Première phase, p1

partie de l’image d’entrée

Buffer B

(b)Deuxième phase, p2

FIG. 8.4 : Phases p1et p2de propagation des valeurs de l’algorithme de van Herk-Gil-Werman

Avant de donner la description formelle pour la première phase, nous présentons informellement le fonctionnement de la deuxième phase, p2, de l’algorithme HGW. Elle est, en effet, analogue à la première

et elle utilise la même manière de propagation des valeurs à l’exception du sens de la propagation qui est opposé. La figure 8.4(b) illustre cette situation.

Nous pouvons explorer les points communs est construire ainsi la description formelle d’une phase généralisée de la propagation des valeurs de l’algorithme HGW. La fonction phaseHGW est dédiée à ce but et définit cette phase généralisée :

phaseHGW :: (Ord α) ⇒ [ Char] → (α → α → α) → Ar ( I , I ) α → Ar ( I , I ) α phaseHGW how f mb = (array (bounds $ mb))

◦ ( zip ixs ) ◦ ( mfoldl1 f ) ◦ (map ( mb! ) )

$ ixs

where ixs = streamAr2D how mb

Le choix exact de la propagation est spécifié par le paramètre how. En regardant bien cette fonction, nous nous apercevons que son corps est, en effet, identique à celui de la fonction pGenMB (cf. sa définition dans le chapitre 7, page 152) qui décrivait la propagation SIMD dans un macro bloc composé des vecteurs paquetés. Les deux fonctions diffèrent dans leurs signatures de types et, par conséquent, dans l’usage

prévu. Tant que la fonction pGenMB a été conçue directement pour le travail avec les vecteurs paquetés, la fonction d’une phase généralisée phaseHGW est destinée tout d’abord au travail avec les éléments de base. C’est en effet cette similitude qui va lier les algorithmes de la propagation SIMD et les stratégies de parallélisation de l’algorithme de van Herk-Gil-Werman.

Pour pouvoir dériver les phases concrètes p1et p2de la propagation à partir de la phase généralisée,

nous nous baserons sur le paramètre dir qui exprimera textuellement la direction du segment, ”Fst” / ”Snd” si l’élément structurant suit la direction de la première / deuxième coordonnée, respectivement. La première phase de l’algorithme HGW est définie par la fonction phase1 :

phase1 :: (Ord α) ⇒ [ Char] → (α → α → α) → Ar ( I , I ) α → Ar ( I , I ) α phase1 dir f mb = phaseHGW ("FW"++dir) f mb

et la deuxième phase de l’algorithme HGW est définie par la fonction phase2 :

phase2 :: (Ord α) ⇒ [ Char] → (α → α → α) → Ar ( I , I ) α → Ar ( I , I ) α phase2 dir f mb = phaseHGW ("BW"++dir) f mb

Les deux fonctions utilisent à l’interne la fonction généralisée phaseHGW et la spécifient pour le par- cours en avant (par "FW") dans le cas de la phase p1 et pour le parcours en arrière (par "BW") dans

le cas de la phase p2. Notons que les deux premières phases peuvent être exécutées en même temps en

exploitant ainsi le parallélisme des tâches.

La troisième phase utilise les résultats intermédiaires obtenus par l’application de la phase p1et p2

et les combine dans le résultat final de l’algorithme. La fig. 8.5 illustre son fonctionnement.

valeur du bord valeur du bord

Résultat Buffer A

Buffer B

Zone de la gestion du bord Zone de la gestion du bord Élément structurant

FIG. 8.5 : Schéma de fonctionnement de l’algorithme de van Herk, phase p3

Elle ne travaille pas à l’échelle des macro blocs mais à celle d’une ligne (colonne). Étant donné k le nombre des pixels désignés par l’élément structurant, nous extrayons, pour une position donnée x d’une dimension correspondant au pixel central à l’échelle d’une ligne (colonne), les pixels avec l’index x + (k−1)2 à partir du buffer A et les pixels avec l’index x − (k−1)2 à partir du buffer B. Puisqu’il s’agit du calcul utilisant les vecteurs de déplacement pour évaluer la valeur d’un pixel, tous les phénomènes de traitement non-dépendants du sens du parcours par les éléments structurants, comme présentés dans le chapitre 5, page 99, entrent en jeu, notamment ceux qui sont connexes à la gestion des pixels aux bords de l’image. La figure 8.6 illustre ce travail sur l’exemple de trois pixels, un placé dans la zone intérieure de l’image et d’autres placés dans la zone de traitement des bords de l’image.

Nous présentons la définition de la fonction phase3Gen qui effectue cette troisième phase et qui, pour extraire une valeur à partir des buffers temporaires bufA et bufB, utilise l’approche naïve au traitement

valeur du bord

Résultat Buffer A

Buffer B

Zone de la gestion du bord Zone de la gestion du bord Élément structurant

valeur du bord

FIG. 8.6 : Exemple de la fusion des valeurs des buffers A et B lors de la phase p3pour un pixel dans la zone

intérieure de l’image et pour les pixels dans les zones touchant les bords de l’image

phase3Gen :: [ Char] → BroderFnc→ I → (α → α → α) → ( Ar ( I , I ) α, Ar ( I , I ) α) → Ar ( I , I ) α phase3Gen dir brdfnc k f (bufA, bufB) =

listArray (bounds $ bufA)

◦ (map ( λ i → f ( sampGen brdfnc bufA (p1 i ) )

( sampGen brdfnc bufB (p2 i ) ) ) ) ◦ indices

$ bufA

where

p1 ( x1, x2) = if (how == "Fst" ) then ( x1 + div (k−1) 2, x2) else ( x1, x2 + div (k−1) 2)

p2 ( x1, x2) = if (how == "Fst" ) then ( x1 − (div (k−1) 2), x2) else ( x1, x2 − (div (k−1) 2)) Le paramètre dir spécifie la direction du segment (”Fst” ou ”Snd”) et la fonction brdf nc assure l’extraction des valeurs pour les index à l’extérieur du domaine des deux buffers. k est le nombre des éléments constituant le segment et f est la fonction à effectuer (max ou min). Dans le cœur de cette fonction, nous créons le stream des index ixs par la fonction indices du Haskell, nous procédons à l’échantillonnage des deux buffers à l’aide de la fonction sampGen pour les positions décalées p1et p2

et nous appliquons ensuite la fonction f . La fonction listArray crée, d’une manière standard, un array à partir d’un stream des résultats. Ainsi, nous obtenons une ligne (colonne) des valeurs résultantes de l’opération morphologique.

L’algorithme entier de van Herk-Gil-Werman que nous construisons à partir de ces trois phases et qui travaille avec les segments suivant l’axe de la première coordonnée (Fst) est présenté par l’algorithme 8.2 en tant que fonction algoHGWFst. Notre intérêt pour cette première coordonnée sera éclairci par la suite lors de la description de la version SIMD de cet algorithme. Notons que la spécification pour les segments suivant la direction de la deuxième coordonnée est analogue et peut être facilement dérivée à partir de la définition de la fonction algoHGWFst.

L’algorithme HGW prend quatre arguments : k est la taille du segment symétrique, brdf nc est la fonction qui assure l’obtention de la valeur de l’extérieur du domaine de l’image lors d’échantillonnage des buffers dans la phase p3, f est la fonction qui assure l’opération morphologique et ar est l’array

d’entrée. Malgré la forme peu standard de cet algorithme, son fonctionnement n’est pas plus compliqué que ceux déjà rencontrés. Nous commençons par appliquer (sur la ligne 18) sur l’array ar le découpage, ligne 17, en colonnes composées des éléments de base. Nous passons, ligne 16, d’un array à un flux de données (colonnes dans ce cas) et nous appliquons sur chaque colonne (ligne 6) un bloc de traitement (entre les lignes 7 et 14).

Ce bloc fonctionnel est dédié à la construction des buffer A et B. Il ne fait que découper chaque colonne (ligne 14) en macro blocs de taille k du segment, exprime cette colonne en tant que flux des macro blocs et applique sur chacun d’eux la phase1 et la phase2 de traitement par la propagation des

Algorithme 8.2 : algoHGWFst, Algorithme de van Herk-Gil-Werman de dilatation/érosion par un segment suivant la direction de la première coordonnée

1 algoHGWFst :: I → BroderFnc→ (α → α → α) → Ar ( I , I ) α → Ar ( I , I ) α 2 algoHGWFst k brdfnc f ar = 3 arrayFromMxNBlocs 4 ◦ ( listArray ( (1,1) , (1,q)) ) 5 ◦ (map (phase3Gen "Fst" brdfnc k f ) ) 6 ◦ (map ( 7 ( λ (mbsA,mbsB) →(

8 arrayFromMxNBlocs◦ ( listArray ( (1,1) , (mbnum,1)) ) $ mbsA,

9 arrayFromMxNBlocs◦ ( listArray ( (1,1) , (mbnum,1)) ) $ mbsB

10 )

11 )

12 ◦ ( λmbs → (map (phase1 "Fst" f ) mbs),( map (phase2 "Fst" f ) mbs) )

13 ◦ elems 14 ◦ (arrayToMxNBlocs mbnum 1) ) 15 ) 16 ◦ elems 17 ◦ (arrayToMxNBlocs 1 q) 18 $ ar 19 where 20 (p,q) = dimsAr2D ar 21 mbnum= div p k

valeurs. Les lignes restantes de ce bloc fonctionnel (ligne 7 à 11) construisent deux buffers à partir des résultats du traitement à l’intérieur des macro blocs.

L’application de la phase3Gen se poursuit, ligne 5, à l’échelle du stream des colonnes et prend comme argument le stream des tuples composés, pour chacune des colonnes des deux buffers correspon- dants. Les lignes restantes (ligne 3 et 4) recomposent l’array de sortie à partir du stream résultant des colonnes.