• Aucun résultat trouvé

3.3.1 Filtre/processus individuel

Tous les filtres ont la même structure générique leur permettant la manipulation de plusieurs textures entrantes et la génération d’une unique texture de sortie avec des composantes arbi- traires (figure3.5)58. Les textures générées successivement à chaque pas temporel sont stockées dans un tampon cyclique pour éviter des copies coûteuses en temps et en mémoire. La configura- tion de la carte graphique et toutes les opérations nécessaires à l’exécution du programme n’ont pas à être connu de l’utilisateur qui précise uniquement les textures à utiliser et implémente le code du programme (nommé shader) dans un langage standard59. Sur la figure est effectuée une différenciation entre deux textures, qui peuvent être par exemple les images successives d’une séquence vidéo ou de n’importe quel tampon cyclique produit par un autre filtre. Voici une version du code shader associé :

uniform sampler2D tex0,tex1; void main(void) {

vec2 coords = gl_TexCoord[0].st; vec4 a = texture2D(tex0,coords); vec4 b = texture2D(tex1,coords); gl_FragColor = a−b;

}

Listing 3.1 – Code source d’un pixel shader de différenciation

58. Les figures et codes des sections à suivre, quoique légèrement modifiés, proviennent d’un article en cours de révision dans la revue Machine Vision and Applications (Springer)

3.3. Implémentation des processus visuels

Optional parameters

Graphics card memory

...

Pixel shader

Input textures

Shader source code

Output texture

Figure 3.5 – La carte graphique exécute un programme (pixel shader program) et chaque pipeline génère individuellement les pixels d’une nouvelle texture en combinant les textures déjà stockées dans la mémoire de la carte. Ledit programme peut exploiter des paramètres additionnels et effectuer des calculs complexes quoique locaux.

A ce code exécuté sur la carte graphique est associé un programme Java contrôlant la carte graphique. Le shader est ainsi compilé, chargé sur la carte graphique, et les textures entrantes associées aux variables tex0 et tex1 via un objet Effect. L’appel new Effect(n,w,h) produit une instance de la classe qui permet d’accéder aux n textures consécutives de dimensions (w,h) produites par l’effet. L’effet nommé difference utilise ici le tampon de sortie de l’effet camera comme entrée. Cet effet camera stocke les images brutes d’un périphérique d’acquisition, per- mettant ainsi du prefetching et une allocation optimale de la mémoire. La dernière ligne du code ci-dessous associe la texture de l’effet camera au temps t à la variable d’entrée tex0 et celle au temps discret t-1 à tex1.

Effect camera = new Effect(2,w,h); camera.setName("Input");

Effect difference = new Effect(1,w,h); difference .setName("Differenciation ");

difference .setShader("uniform [...] a−b; }"); difference .setTextures(

new Effect []{ camera,camera}, new int []{0,1}

);

Listing 3.2 – Différenciation au niveau du code Java

Un autre exemple utilisant un ensemble de filtres plus complexes est détaillé dans l’annexe

D de ce manuscrit. Bien que celle-ci ne soit en principe pas nécessaire à la compréhension de ce chapitre, elle pousse plus loin la description de la librairie. Elle montre en effet comment produire du code shader et le compiler depuis un programme écrit dans un langage haut niveau et inclut des portions du code Java et JOGL contrôlant l’exécution et la gestion des textures sur la carte graphique.

3.3.2 Multitude de processus

Les structures nécessaires à la prise en compte des relations entre plusieurs effets sont ici illustrées par un ensemble de processus rétiniens et corticaux (dont une partie du code est incluse dans l’annexeD). Ceux-ci pourraient être grandement améliorés et optimisés mais sont repris ici pour illustrer les besoins d’applications complexes et les différents types d’interactions possibles entre effets. Comme précédemment décrit, chaque effet est individuellement défini par son code source et les textures associées à ses entrées. Lorsqu’un ensemble de processus doit être mis à jour, les dépendances temporelles déterminent leur séquencement.

Rods

Figure 3.6 – Simulation de l’effet des bâtonnets de la rétine sur une images brute.

Blur

level n+1

level n

Figure 3.7 – Effet de flou potentiellement récursif simulant des champs récepteurs de taille variable.

On-off

Figure 3.8 – Effet reproduisant le comportement d’extraction dynamique de contraste des cellules ganglionnaires "on center off surround".

Chaque figure de cette section représente un effet dont le nom est écrit au centre (figures3.6,

3.7,3.8,3.9et3.10). Les flèches noires représentent les dépendances, liant les entrées de l’effet à la sortie qu’il produit. La plupart de ces effets ne prennent qu’une texture en entrée, tels que les

3.3. Implémentation des processus visuels

persistance

(time t-1)

blind spot

fovea

Retina

Figure 3.9 – Effet de simulation de la perception rétinienne, incluant par exemple la densité variable des photorécepteurs et la tâche aveugle.

MT

time t

t-2

t-1

Figure 3.10 – Effet reproduisant le comportement des cellules corticales MT sensibles à une vitesse et orientation particulières

effets Rods (simulant la large sensibilité des bâtonnets de la rétine au spectre lumineux), On-off (reproduisant l’extraction de contraste réalisée par les cellules ganglionnaires "center-surround") ou encore Blur. Ce dernier a la particularité d’être applicable récursivement afin de reproduire l’intégration des signaux sur des champs récepteurs de tailles différentes. L’application de cet effet de flou limitée à la région extrafovéale simule aussi la résolution plus faible, donc l’espace- ment plus grand entre les photorécepteurs, sur cette partie de la rétine.

L’application de cet effet de flou en plusieurs passes permet non seulement d’accélérer les calculs en réutilisant au maximum les résultats intermédiaires, mais fournit aussi un moyen simple d’obtenir des textures multi-résolution. Les processus anticipatifs de plus haut niveau

peuvent exploiter ces textures pour détecter des objets de taille variable, de simples points d’intérêts localisés à des objets occupant une bonne part du champ visuel.

Chaque passe est effectuée en utilisant un programme de complexité constante. Chaque pixel de l’image de sortie est calculé comme une moyenne de 9 pixels voisins en entrée (figure3.11). En négligeant les bordures de l’image, gérées intrinsèquement et sans provoquer d’erreur par les GPU modernes, la complexité peut être facilement approximée. Pour un flou n passes sur une image de w × h pixels, elle est d’environ n × w × h × 32. Ce calcul inclut la génération successives des n textures correspondant aux n niveaux de flou croissant.

Comparée à l’approche directe consistant à moyenner les signaux sur un plus large champ récepteur (voir partie droite de la figure 3.11) et sans même comptabiliser la génération des résolutions intermédiaires, la version multi-passes est bien plus performante. Avec les mêmes pa- ramètres que précédemment, le nombre d’opérations pour effectuer la mise à jour en une passe du nème niveau de flou sur l’ensemble des pixels de l’image est : w × h × (3n)2.

texture Reentering

Shader for level 2 blur Shader for level 1 blur

...

1-pass version

Figure 3.11 – Comparaison des versions 1 passe et 2 passes de l’algorithme de flou. Des dépendances plus complexes sont illustrées par les effets Retina et MT. Ainsi, plusieurs effets peuvent être fusionnés pour simuler l’irrégularité du flux rétinien produit par les photoré- cepteurs. L’effet Retina reproduit ainsi la perte de la couleur en périphérie en utilisant Rods, la densité variable des récepteurs en appliquant Blur. La texture générée à l’instant précédent est également redirigée en entrée pour simuler la persistance rétinienne (figure3.9).

De manière similaire, les effets MT évaluent les mouvements locaux à partir de plusieurs images calculées par un même effet, mais à des temps différents.

3.3.3 Ordonnancement PERT

L’ordonnancement de l’exécution des shaders est calculé par un algorithme PERT. Le graphe des dépendances temporelles est généré par une règle unique, une fois que les entrées de chaque effet ont été correctement configurées. Une dépendance est introduite à chaque fois qu’une tex- ture d’entrée d’un effet est la sortie d’un autre, calculée dans le même cycle de mise à jour. Les dépendances sont représentées par des flèches sur la figure 3.12, dont l’effet cible dépend de la source. Le coût est uniforme et arbitrairement égal à 1, le but étant simplement d’ordonner les calculs pour éviter d’utiliser des textures non définies et de détecter des erreurs de conception dans le graphe.

La règle de construction élimine les liens depuis des textures calculées au cycle d’exécution précédent. Par exemple sur la figure, l’effet MT dépend de On-off uniquement à cause de l’uti-

3.4. Performances