1 <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head><title>Algorithmes rapides sur GPU</title><meta name="generator" content="Hovercraft! 1.0 http://regebro.github.com/hovercraft"></meta><meta name="author" content="Gilles Perrot"></meta><link rel="stylesheet" href="css/hovercraft.css" media="all"></link><link rel="stylesheet" href="css/impressConsole.css" media="all"></link><link rel="stylesheet" href="css/highlight.css" media="all"></link><link rel="stylesheet" href="css/zulug5.css" media="all"></link><script type="text/javascript" src="https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script></head><body class="impress-not-supported"><div id="impress"><div class="step" step="0" id="titre" data-x="0" data-y="0"><h1 id="traitement-d-images-sur-gpu">TRAITEMENT D'IMAGES SUR GPU</h1><h2 id="algorithmes-parralleles-rapides-pour-le-filtrage-et-la-segmentation-des-images-bruitees-sur-gpu">Algorithmes parrallèles rapides pour le filtrage et la segmentation des images bruitées sur GPU.</h2><h3 id="gilles-perrot">Gilles Perrot</h3><h3 id="universite-de-franche-comte-institut-femto-st">Université de Franche-Comté, Institut FEMTO-ST</h3><h3 id="departement-disc-equipe-and">Département DISC - équipe AND</h3></div><div class="step" step="1" data-x="1600" data-y="0"><h1 id="plan-de-la-presentation">PLAN DE LA PRÉSENTATION</h1><ol><li>Introduction - cadre des travaux<ul><li>Les GPUs (Graphical Processing Units)</li><li>Généralités sur le traitement d'image. Nos axes de recherche.</li></ul></li><li>La segmentation des images<ul><li>Généralités. Travaux de référence.</li><li>Parallélisation GPU d'un algorithme de segmentation de type <em>snake</em>.</li></ul></li><li>Le filtrage des images<ul><li>Généralités. Travaux de référence.</li><li>Optimisation pour GPU des filtres médian et de convolution.</li><li>Conception d'un algorithme parallèle de réduction de bruit par recherche des lignes de niveaux.</li></ul></li><li>Synthèse et conclusion.</li></ol></div><div class="step" step="2" data-x="3200" data-y="0"><h1 id="introduction">INTRODUCTION</h1></div><div class="step" step="3" data-x="4800" data-y="0"><h1 id="id1">INTRODUCTION</h1><h2 id="les-gpus-ou-processeurs-graphiques">Les GPUs ou <em>Processeurs graphiques</em>.</h2><img src="img/gpucpu1.png" alt="" width="" height="400px"></img><ul><li>Processeurs <em>classiques</em> <strong>CPU</strong> : exécution <strong>séquentielle</strong><ul><li>Quelques unités de calcul ( les cœurs).</li></ul></li><li>Processeurs <em>graphiques</em> <strong>GPU</strong> : exécution <strong>massivement parallèle</strong><ul><li>Des centaines, voire millier, d'unités de calcul, regroupées en quelques SMs (<em>Streaming Multiprocessors</em>).</li></ul></li></ul></div><div class="step" step="4" data-x="6400" data-y="0"><h1 id="id2">INTRODUCTION</h1><h2 id="id3">Les GPUs ou <em>Processeurs graphiques</em>.</h2><ul><li>La multiplication des cœurs dans les GPUs se fait au détriment des fonctions de contrôle et de cache.</li><li>Seule la mémoire <em>globale</em> est accessible par l'ensemble des fils d'exécution (les <em>threads</em>) et ses performances sont faibles.</li><li>L'accès efficace aux différents types de mémoires est contraignant.</li><li>Les échanges de données entre le GPU et son hôte CPU sont pénalisants.</li><li>Il est important de concevoir un partage équilibré des ressources au sein de chaque SM, pour permettre un niveau de parallélisme élevé, et donc d'envisager de bonnes performances.</li><li>La mise au point n'est pas aisée lorsque des centaines de milliers de threads concourent à l'exécution d'une tâche.</li></ul></div><div class="step" step="5" data-x="8000" data-y="0"><h1 id="id4">INTRODUCTION</h1><h2 id="le-traitement-des-images">Le traitement des images</h2><ul><li>Beaucoup d'applications sont basées sur l'analyse ou la visualisation d'images numériques.</li><li>Les capteurs numériques et les conditions d'acquisition sont à l'origine de perturbations (bruits) qui dégradent l'image de la scène idéale et peuvent en fausser ou compliquer l'interprétation.</li><li>La réduction de bruit demeure un thème important, car les hautes résolutions sont souvent obtenues à faible flux de photons, dont les variations engendrent du bruit.</li><li>La segmentation représente aussi un enjeu crucial, mais aucun algorithme universel n'a encore été élaboré.</li></ul><div class="notes"><ul><li>on recense plus de 4000 algorithmes de segmentation</li><li>La segmentation intervient dans beaucoup d'applications : du tracking à la détection ou à l'extraction de caractéristiques diverses.</li><li>Mais aujourd'hui encore, une bonne segmentation est celle qui permet d'extraire ce que l'on attend => l'algorithme dépend du problème.</li></ul></div></div><div class="step" step="6" data-x="9600" data-y="0"><h1 id="id5">INTRODUCTION</h1><h2 id="id6">Le traitement des images</h2><ul><li>L'accroissement des capacités de calcul a suivi l'augmentation des résolutions d'images.</li><li>Les traitements envisagés sur les images sont de plus en plus évolués ( traitements de haut niveau ) et requièrent souvent un temps de calcul accru.</li><li>L'architecture parallèle particulière des GPUs a permis d'améliorer considérablement les performances de certaines classes d'algorithme et fait espérer des accélérations importantes pour d'autres.</li></ul><p><strong>Nos travaux sont une contribution à cette recherche de performance.</strong></p><div class="notes"><ul><li>La croissance des capacités de calcul des GPUs à été beaucoup plus forte que celle des CPUs.</li></ul></div></div><div class="step" step="7" data-x="11200" data-y="0"><h1 id="id7">INTRODUCTION</h1><h2 id="traitements-d-images-de-haut-niveau">Traitements d'images de haut niveau</h2><ol><li><strong>Pré-traiter</strong> et effectuer les traitements de haut niveau sur des images <em>améliorées</em>.<ul><li>permet, <em>a priori</em>, de réduire le coût des traitements de haut niveau.</li><li>les prétraitements ont eux aussi un coût, en temps de calcul et potentiellement en information.</li></ul></li><li><strong>Ne pas pré-traiter</strong> et effectuer les traitements de haut niveau sur les images bruitées.<ul><li>permet de ne pas subir la perte d'information occasionnée par le pré-traitement.</li><li>les traitements de haut niveau sont, <em>a priori</em>, plus coûteux.</li></ul></li></ol><div class="notes"><p>Certains algo (LNIV) peuvent être considérés comme pré-traitement ou comme haut-niveau selon le point de vue et la classe d'algorithme.</p></div></div><div class="step" step="8" data-x="12800" data-y="0"><h1 id="id8">INTRODUCTION</h1><h2 id="axes-des-travaux-presentes">Axes des travaux présentés</h2><p><strong>Segmentation : accélérer le traitement de haut niveau</strong></p><blockquote><ul><li>La segmentation consiste à identifier des zones homogènes dans une image.</li><li>Algorithme de segmentation d'images bruitées (fortement) par contours actifs, appartenant à la classe communément appelée <em>snakes</em>.</li></ul></blockquote><p><strong>Filtrage : accélérer les pré-traitements</strong></p><blockquote><p>Réduction de bruit additif gaussien, suivant deux méthodes de conception :</p><blockquote><ul><li>algorithme original, conçu spécifiquement pour GPU, conjointement à son implémentation.</li><li>algorithmes existants, où l'effort de conception ne peut porter que sur l'implémentation : filtres médian et de convolution.</li></ul></blockquote></blockquote></div><div class="step" step="9" data-x="14400" data-y="0"><h1 id="id9">INTRODUCTION</h1><h2 id="images-traitees">Images traitées</h2><ul><li>Nous nous sommes focalisés sur les <em>images naturelles</em> :</li></ul><blockquote><ul><li>réalisées en lumière naturelle, en intérieur aussi bien qu'en extérieur,</li><li>prises avec un dispositif standard (CMOS, CCD).</li></ul></blockquote><ul><li>Les traitements que nous présentons ici opèrent sur des images en
2 niveau de gris (8 ou 16 bits).</li></ul><div class="notes"><p>Toutefois, la plupart des algorithmes que nous proposons s'étend simplement à d'autres types d'images, comme les images en couleur ou celles issues des imageries ultrasonore ou RADAR à ouverture synthétique.</p></div></div><div class="step" step="10" data-x="16000" data-y="0"><h1 id="la-segmentation-des-images">LA SEGMENTATION DES IMAGES</h1><p>Segmentation par contour actif</p></div><div class="step" step="11" data-x="17600" data-y="0"><h1 id="segmentation-par-contour-actif">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id10">Introduction</h2><ul><li>Le domaine médical recèle la quasi totalité des implémentations GPU d'algorithmes de segmentation.</li><li>Nombre d'entre elles concernent des traitements effectués en 3D par nécessité, où l'emploi du GPU s'impose assez naturellement.</li><li>La segmentation par contour actif regroupe des méthodes itératives tendant à faire converger, par déformation successive, une courbe paramétrique (contour) selon un critère d'homogénéité pré-établi :</li></ul><blockquote><ul><li>La classe d'algorithmes la plus implémentée est celle des <strong>level-set</strong>, essentiellement dans sa variante <em>bande étroite</em>.</li><li>La classe des <strong>snakes</strong> n'est implémentée qu'au travers la variante GVF (Gradient Vector Flow).</li></ul></blockquote><img src="img/l7-gvf.png" alt="" width="600px" height=""></img>À gauche : Level-set, évolution du contour, en rouge. À droite : visualisation du champ de force d'un <em>snake</em> GVF.</div><div class="step" step="12" data-x="19200" data-y="0"><h1 id="id11">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="travaux-de-reference-level-set">Travaux de référence (level-set)</h2><p>L'implémentation de Roberts <em>et al.</em> du <em>level-set</em> à <em>bande étroite</em> est actuellement la plus performante et parvient à segmenter des images d'IRM</p><blockquote><ul><li>3D, de 256x256x256 pixels, sur GTX280, en <strong>11 000 ms</strong></li></ul></blockquote><img src="img/brain3D.png" alt="" width="800px" height=""></img>À gauche : évolution du contour pour une <em>tranche</em> avec, en bleu, les zones actives. À droite : visualisation en 3D de la segmentation complète.</div><div class="step" step="13" data-x="20800" data-y="0"><h1 id="id12">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="travaux-de-reference-snake">Travaux de référence (snake)</h2><ul><li>À notre connaissance, aucune publication ne décrit d'implémentation de <em>snake</em> polygonal ou de <em>snake</em> orienté région.</li><li>La référence est l'implémentation <em>snake GVF</em> de Smistad <em>et al.</em> qui parvient à segmenter des images d'IRM</li></ul><blockquote><ul><li>2D, de 512x512 pixels, sur C2070, en <strong>41 ms</strong>.</li><li>3D, de 256x256x256 pixels, sur C2070, en <strong>7151 ms</strong></li></ul></blockquote><img src="img/brain3D-gvf.png" alt="" width="600px" height=""></img>À gauche : une image 2D d'IRM. À droite : visualisation en 3D de la segmentation complète.</div><div class="step" step="14" data-x="22400" data-y="0"><h1 id="id13">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="snake-polygonal-oriente-region-principe"><em>Snake</em> polygonal orienté région (principe)</h2><table cellpadding="0" cellspacing="0" class="columns"><tbody><tr><td><img src="img/snake-modele.png" alt="" width="350px" height=""></img></td><td><ul><li>L'objectif est de déterminer le contour le plus <em>vraisemblable</em> (nombre et positions des nœuds).</li><li>Le critère de vraisemblance généralisée est, dans le cas gaussien :$$GL = \frac{1}{2}\left[ n_B.log\left(\sigma_B^2\right) + n_T.log\left(\sigma_T^2\right)\right]$$</li></ul></td></tr></tbody></table><ul><li>Les deux régions, intérieure et extérieure (T et B), sont prises en compte dans l'évaluation du contour. Cela permet d'extraire des formes aux contours mal définis, en raison d'un fort niveau de bruit par exemple.</li><li>Les variances \(\sigma^2\) doivent être calculées pour chaque état du contour, ce qui est <strong>très coûteux</strong>.</li></ul></div><div class="step" step="15" data-x="24000" data-y="0"><h1 id="id14">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id15"><em>Snake</em> polygonal orienté région (principe)</h2><ul><li>Chesnaud <em>et al.</em> ont montré comment réaliser le calcul des variances par une <strong>sommation 2D</strong> le long du contour, au lieu d'une classique sommation 3D sur la surface des régions concernées.</li><li>Cette optimisation algorithmique implique de <strong>pré-calculer</strong> les trois images cumulées$$S_1(i,j)=\sum_{x=0}^jx \text{ , } S_x(i,j)=\sum_{x=0}^jI(i,x) \text{ et } S_x^2(i,j)=\sum_{x=0}^jI(i,x)^2$$</li><li>Les valeurs des éléments de ces images cumulées permettent de calculer la <strong>contribution</strong> de chaque pixel du contour, puis de chaque segment, aux calculs des variances.</li></ul></div><div class="step" step="16" data-x="25600" data-y="0"><h1 id="id16">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="snake-polygonal-oriente-region-algo-cpu"><em>Snake</em> polygonal orienté région (algo CPU)</h2><img src="img/cochons-it0-it1.png" alt="" width="" height="300px"></img><p><strong>Itération 1</strong></p><blockquote><ol><li>Le contour initial est rectangulaire ( 4 nœuds )</li><li>On déplace successivement les 4 nœuds jusqu'à ce que plus aucun nouveau déplacement ne provoque l'amélioration du critère.</li></ol></blockquote></div><div class="step" step="17" data-x="27200" data-y="0"><h1 id="id17">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id18"><em>Snake</em> polygonal orienté région (algo CPU)</h2><img src="img/cochons-it21-it22.png" alt="" width="" height="300px"></img><p><strong>Itération 2</strong></p><blockquote><ol><li>Ajout de nœuds au milieu des segments suffisamment grands.</li><li>On recommence à évaluer les déplacements successifs des nœuds.</li></ol></blockquote></div><div class="step" step="18" data-x="28800" data-y="0"><h1 id="id19">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id20"><em>Snake</em> polygonal orienté région (algo CPU)</h2><img src="img/cochons-it4-it5.png" alt="" width="" height="300px"></img><p><strong>Itérations 4 et 5</strong></p></div><div class="step" step="19" data-x="30400" data-y="0"><h1 id="id21">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id22"><em>Snake</em> polygonal orienté région (algo CPU)</h2><img src="img/im014.png" alt="" width="" height="400px"></img>Image de 512x512 : contour final de 256 nœuds en 14ms.<ul><li>Les résultats de segmentation dépendent des paramètres de la séquence d'optimisation (pas des déplacements, contour initial, seuil d'ajout des nœuds)</li></ul></div><div class="step" step="20" data-x="32000" data-y="0"><h1 id="id23">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id24"><em>Snake</em> polygonal orienté région (algo CPU)</h2><img src="img/snakegpu1.png" alt="" width="" height="400px"></img>Image de 4000x4000 : contour final de 447 nœuds en 700ms.</div><div class="step" step="21" data-x="33600" data-y="0"><h1 id="id25">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="parallelisation-du-snake-polygonal-sur-gpu">Parallélisation du <em>Snake</em> polygonal sur GPU</h2><p>Identification des fonctions coûteuses</p><img src="img/algosnake1.png" alt="" width="" height="500px"></img></div><div class="step" step="22" data-x="35200" data-y="0"><h1 id="id26">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id27">Parallélisation du <em>Snake</em> polygonal sur GPU</h2><p>Détail de la fonction de calcul du critère GL</p><img src="img/algosnake2b.png" alt="" width="" height="500px"></img></div><div class="step" step="23" data-x="36800" data-y="0"><h1 id="id28">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id29">Parallélisation du <em>Snake</em> polygonal sur GPU</h2><img src="img/snake-pairimpair.png" alt="" width="800px" height=""></img><div class="notes"><ul><li>Pour un nœud et un pas de déplacement donnés, on évalue <strong>en parallèle</strong> 8 positions voisines, soit 16 segments distincts.</li><li>Pour éviter les oscillations et <em>coller</em> à l'algorithme séquentiel, on distingue les nœuds d'indices pairs et impairs.</li><li>On évalue <strong>en parallèle</strong> l'ensemble des déplacements éventuels de tous les nœuds de même parité.</li></ul></div></div><div class="step" step="24" data-x="38400" data-y="0"><h1 id="id30">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id31">Parallélisation du <em>Snake</em> polygonal sur GPU</h2><p><strong>Structure des données</strong> (nœuds pairs)</p><img src="img/snake-segments-pairs.png" alt="" width="800px" height=""></img><div class="notes"><ul><li>règle 1 thread par pixel</li></ul></div></div><div class="step" step="25" data-x="40000" data-y="0"><h1 id="id32">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id33">Parallélisation du <em>Snake</em> polygonal sur GPU</h2><p><strong>Obtention du critère</strong></p><ul><li>Parallélisation : 1 thread par pixel.</li><li>Une seule taille de segment : la taille du plus long.</li><li>Bourrage avec des threads inactifs pour les segments plus courts.</li><li>Calcul réalisé en 3 étapes par 3 fonctions parallèles GPU (<em>kernels</em>)</li></ul><blockquote><ol><li>Calcul des coordonnées des pixels. Lecture des paramètres de chaque pixel dans les images cumulées. Sommes partielles, par bloc, des contributions des segments.</li><li>Calcul final des contributions des segments par sommation des résultats du <em>kernel</em> précedent.</li><li>Calcul des valeurs du critère pour chaque contour évalué. Sélection du meilleur contour.</li></ol></blockquote></div><div class="step" step="26" data-x="41600" data-y="0"><h1 id="id34">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id35">Parallélisation du <em>Snake</em> polygonal sur GPU</h2><p><strong>Propriétés de l'implémentation</strong></p><blockquote><ul><li>Conservation des données en mémoire GPU.</li><li>Les images cumulées sont calculées en parallèle.</li><li>Abandon de l'algorithme de Bresenham pour la discretisation des segments.</li><li>Trop peu de calculs à effectuer.</li><li>Pas de coalescence possible dans les accès à la mémoire globale.</li><li>Emploi de la mémoire partagée.</li></ul></blockquote><div class="notes"><ul><li>Un seul entier est échangé entre le CPU et le GPU à chaque itération.</li><li>image cumulées par une adaptation de la méthode des sommes de préfixes.</li><li>Abandon Bresenham Possible car parcours unidirectionnel du contour.</li><li>Trop peu de calculs ne permet pas de masquer les latences.</li><li>Pas de coalescence possible dans les accès à la mémoire globale car la géométrie des segments varie.</li><li>mémoire partagée à cause des réductions.</li></ul></div></div><div class="step" step="27" data-x="43200" data-y="0"><h1 id="id36">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id37">Parallélisation du <em>Snake</em> polygonal sur GPU</h2><p><strong>Performances de l'implémentation</strong></p><img src="img/perfs-snake.png" alt="" width="600px" height=""></img><img src="img/perfs-snake-img.png" alt="" width="600px" height=""></img></div><div class="step" step="28" data-x="44800" data-y="0"><h1 id="id38">SEGMENTATION PAR CONTOUR ACTIF</h1><h2 id="id39">Parallélisation du <em>Snake</em> polygonal sur GPU</h2><p><strong>Conclusion</strong></p><ul><li>Première et seule implémentation à ce jour.</li><li>Performances intéressantes pour les grandes images. 1OO MP en moins de 0,6 seconde.</li><li>Temps de calcul très dépendant du contenu de l'image.</li><li>Le GPU n'est pas employé de manière optimale : réductions, threads inactifs, non coalescence.</li><li>Le GPU apporte un gain important sur les premières itérations, quand les segments sont grands.</li><li>Initialisation optionnelle par maximum de vraisemblance. Accélération jusqu'à x15 avec de petites cibles.</li></ul></div><div class="step" step="29" data-x="46400" data-y="0"><h1 id="le-filtrage-des-images">LE FILTRAGE DES IMAGES</h1><p>Filtre médian - Filtres de convolution - Filtre par lignes de niveaux</p></div><div class="step" step="30" data-x="48000" data-y="0"><h1 id="id40">LE FILTRAGE DES IMAGES</h1><h2 id="filtre-median">Filtre médian</h2></div><div class="step" step="31" data-x="49600" data-y="0"><h1 id="id41">LE FILTRAGE DES IMAGES</h1><h2 id="filtre-median-principe">Filtre médian : principe</h2><img src="img/median-principe.png" alt="" width="600px" height=""></img><p>La valeur de sortie d'un pixel est la <strong>médiane</strong> des valeurs de son voisinage.</p><ul><li>Bonne réduction de bruits gaussien et <em>poivre & sel</em></li><li>Valeurs de sortie appartenant au voisinage.</li><li>Opération de sélection coûteuse (tri).</li><li>Usages fréquents avec des petites fenêtres (de 3x3 à 7x7).</li><li>Quelques applications avec de grandes fenêtres (au delà de 21x21).</li></ul></div><div class="step" step="32" data-x="51200" data-y="0"><h1 id="id42">LE FILTRAGE DES IMAGES</h1><h2 id="filtre-median-usage">Filtre médian : usage</h2><table cellpadding="0" cellspacing="0"><thead><tr><th><img src="img/airplane_sap25.png" alt="" width="" height=""></img></th><th><img src="img/airplane_sap25_med5.png" alt="" width="" height=""></img></th><th><img src="img/airplane_sap25_med3_it2.png" alt="" width="" height=""></img></th></tr></thead><tbody><tr><td><p>Bruit <em>poivre & sel</em> 25%</p></td><td><p>Médian 5x5</p></td><td><p>Médian 3x3 - 2 passes</p></td></tr></tbody></table></div><div class="step" step="33" data-x="52800" data-y="0"><h1 id="id43">LE FILTRAGE DES IMAGES</h1><h2 id="filtre-median-gpu-travaux-de-reference">Filtre médian GPU : Travaux de référence</h2><ul><li>Sanchez <em>et al.</em> ont proposé le <strong>PCMF</strong> et l'ont comparé, sur C2075, avec les implémentations GPU de référence pour une image 8 bits de 512x512 (débit max. <strong>80 MP/s</strong>) :</li></ul><blockquote><ul><li><strong>ArrayFire</strong>, bibliothèque commerciale, débit max. <strong>185 MP/s</strong></li><li><strong>BVM</strong> parallélisé par Kachelrieß, débit max. <strong>110 MP/s</strong></li></ul></blockquote><img src="img/compar-median2.png" alt="" width="500px" height=""></img><div class="notes"><ul><li>PCMF : Parallel (Complementary Cumulative Derivative Function) Median Filter (histogrammes cumulatifs)</li><li>CTMF : CPU à temps constant</li></ul></div></div><div class="step" step="34" data-x="54400" data-y="0"><h1 id="id44">LE FILTRAGE DES IMAGES</h1><h2 id="id45">Filtre médian GPU : Travaux de référence</h2><p>Emploi de la <strong>mémoire partagée</strong> pour pré-charger les valeurs utiles à chaque bloc de threads.</p><img src="img/shmemhalo.png" alt="" width="800px" height=""></img></div><div class="step" step="35" data-x="56000" data-y="0"><h1 id="id46">LE FILTRAGE DES IMAGES</h1><h2 id="optimisation-du-filtre-median-gpu">Optimisation du filtre médian GPU</h2><p>Transferts des données optimisés</p><blockquote><p>CPU \(\rightarrow\) GPU texture :KERNEL: GPU globale \(\rightarrow\) CPU non paginée</p><img src="img/transferts-mem.png" alt="" width="650px" height=""></img></blockquote><div class="notes"><p>On gagne de 13 à 43 % sur les temps de transfert.</p></div></div><div class="step" step="36" data-x="57600" data-y="0"><h1 id="id47">LE FILTRAGE DES IMAGES</h1><h2 id="id48">Optimisation du filtre médian GPU</h2><p>Débits maximums effectifs, en MP/s, pour des images en 8 et 16 bits, incluant les transferts optimisés (C2070).</p><blockquote><img src="img/debit-max-2070.png" alt="" width="300px" height=""></img></blockquote><p><strong>Rappel :</strong> PCMF : 80 MP/s - BVM : 110 MP/s - ArrayFire : 185 MP/s</p><div class="notes"><p>ça laisse environ 80ms pour faire un tri de 9 valeurs sur une image de 4096x4096</p></div></div><div class="step" step="37" data-x="59200" data-y="0"><h1 id="id49">LE FILTRAGE DES IMAGES</h1><h2 id="id50">Optimisation du filtre médian GPU</h2><p><strong>Sélection de la médiane</strong></p><blockquote><ul><li>Emploi exclusif des <strong>registres</strong> pour charger les valeurs utiles.</li><li>Limitations à 63 registres par thread et 32 K par bloc de threads.</li><li>Envisageable pour les médians de petite taille (jusqu'à 7x7 avec 1 thread/pixel).</li><li>Exploitation des recouvrements entre fenêtres de pixels voisins.</li></ul></blockquote></div><div class="step" step="38" data-x="60800" data-y="0"><h1 id="id51">LE FILTRAGE DES IMAGES</h1><h2 id="id52">Optimisation du filtre médian GPU</h2><p><strong>Sélection de la médiane</strong> (par oubli)</p><table cellpadding="0" cellspacing="0" class="columns"><tbody><tr><td><p>Bonnes performances envisagées :</p><blockquote><ul><li>Économie de registres.</li><li>Évite le tri complet.</li></ul></blockquote></td><td><img src="img/forgetful_selection.png" alt="" width="" height="500px"></img></td></tr></tbody></table></div><div class="step" step="39" data-x="62400" data-y="0"><h1 id="id53">LE FILTRAGE DES IMAGES</h1><h2 id="id54">Optimisation du filtre médian GPU</h2><p><strong>Exploitation des recouvrements</strong></p><img src="img/recouvrement5.png" alt="" width="800px" height=""></img><p><strong>Intérêt :</strong> Économie de registres - chaque thread traite 2 pixels.</p><div class="notes"><ul><li>chaque thread utilise plus de registres</li><li>mais sur un bloc, en adaptant la taille du bloc, on économise k+1 registres par paire de pixels.</li></ul></div></div><div class="step" step="40" data-x="64000" data-y="0"><h1 id="id55">LE FILTRAGE DES IMAGES</h1><h2 id="id56">Optimisation du filtre médian GPU</h2><p><strong>Masquage des latences</strong></p><ul><li>Accès à la mémoire globale : 2 pixels par thread.</li><li>Instruction Level Parallelism (ILP) : Ordre des instructions minimisant l'interdépendance.<img src="img/bitonic.png" alt="" width="" height="300px"></img>Identification des extrema dans le vecteur initial d'un médian 5x5</li></ul><div class="notes"><ul><li>au delà de 2 pixels par thread, le gain sur les latences est compensé par la perte sur le calcul / niveau de parallèlisme.</li><li>ILP maximisée en appliquant une méthode simple; utilisée par ex. dans la technique des réseaux de tri bitoniques.</li></ul></div></div><div class="step" step="41" data-x="65600" data-y="0"><h1 id="id57">LE FILTRAGE DES IMAGES</h1><h2 id="performances-du-filtre-median-gpu-propose-prmf">Performances du filtre médian GPU proposé (PRMF)</h2><img src="img/perf-median.png" alt="" width="650px" height=""></img></div><div class="step" step="42" data-x="67200" data-y="0"><h1 id="id58">LE FILTRAGE DES IMAGES</h1><h2 id="id59">Performances du filtre médian GPU proposé (PRMF)</h2><p>Image 512x512</p><blockquote><img src="img/comp512.png" alt="" width="" height="200px"></img></blockquote><p>Image 4096x4096</p><blockquote><img src="img/comp4k.png" alt="" width="" height="200px"></img></blockquote></div><div class="step" step="43" data-x="68800" data-y="0"><h1 id="id60">LE FILTRAGE DES IMAGES</h1><h2 id="le-filtre-median-gpu">Le filtre médian GPU</h2><p><strong>Conclusion</strong></p><blockquote><ul><li>Pas d'utilisation de la mémoire partagée.</li><li>Débit global amélioré de x7 à x10, proche du maximum.</li><li>Débit de calcul atteignant <strong>5,3 GP/s</strong>.</li><li>Médian jusqu'au 9x9 sur C2070, 21x21 sur K40.</li><li>Création d'une application web générant les codes sources.</li><li>Utilisé pour le pré-traitement d'images de cristallographie au synchrotron <strong>SPring-8</strong> (Japon).</li></ul></blockquote><img src="img/SPring8.png" alt="" width="" height="200px"></img></div><div class="step" step="44" data-x="70400" data-y="0"><h1 id="id61">LE FILTRAGE DES IMAGES</h1><h2 id="les-filtres-de-convolution">Les filtres de convolution</h2></div><div class="step" step="45" data-x="72000" data-y="0"><h1 id="id62">LE FILTRAGE DES IMAGES</h1><h2 id="les-filtres-de-convolution-generalites">Les filtres de convolution : généralités</h2><p><strong>Principe</strong></p><blockquote>$$I_{out}(x, y) = \left(I_{in} * h\right) = \sum_{(i < H)} \sum_{(j < L)}I_{in}(x-j, y-i)h(j,i)$$</blockquote><p><strong>Usage, selon les valeurs du masque h</strong></p><blockquote><ul><li>réduction de bruit,</li><li>détection de bords,...</li></ul></blockquote><div class="notes"><ul><li>selon h --> convo séparable ou non séparable</li></ul></div></div><div class="step" step="46" data-x="73600" data-y="0"><h1 id="id63">LE FILTRAGE DES IMAGES</h1><h2 id="les-filtres-de-convolution-gpu">Les filtres de convolution GPU</h2><p>Le fabricant Nvidia propose la plus rapide des implémentations connue :</p><p>Convolution <strong>non séparable</strong> sur image de 2048x2048, masque h de 5x5, sur <strong>GTX280</strong>.</p><ul><li>Débit global : <strong>945 MP/s</strong>.</li><li>Débit de calcul : <strong>3,00 GP/s</strong></li></ul></div><div class="step" step="47" data-x="75200" data-y="0"><h1 id="id64">LE FILTRAGE DES IMAGES</h1><h2 id="id65">Les filtres de convolution GPU</h2><p>Exploitation des recouvrements</p><blockquote><ul><li>un seul accès mémoire par pixel, mémorisation en registre.</li><li>mise à jour de tous les calculs concernés</li></ul></blockquote><img src="img/convoOverlap2.png" alt="" width="400px" height=""></img><p>Application des techniques présentées pour le filtre médian :</p><ul><li>Optimum à 8 pixels par thread.</li><li>Débit global : <strong>966 MP/s</strong>.</li><li>Débit de calcul : <strong>3,47 GP/s</strong></li></ul><p>Sur <strong>C2070</strong>, nos débits sont de <strong>1666 MP/S</strong> et <strong>5280 MP/s</strong>. Les débits maximum atteignent <strong>2140 MP/s</strong> et <strong>8540 MP/s</strong> (4090x4096, masque 3x3)</p></div><div class="step" step="48" data-x="76800" data-y="0"><h1 id="id66">LE FILTRAGE DES IMAGES</h1><h2 id="id67">Les filtres de convolution GPU</h2><p>Convolution <strong>séparable</strong> sur C2070.</p><p>Implémentation Nvidia (mémoire partagée)</p><blockquote><ul><li>Débit global max : <strong>1933 MP/s</strong>.</li><li>Débit de calcul max : <strong>6000 MP/s</strong></li></ul></blockquote><p>Notre implémentation</p><blockquote><ul><li>Optimum à 8 pixels par thread.</li><li>Une convolution 1D en mémoire partagée, l'autre en registres. Copie intermédiaire en mémoire globale (cache 1D rapide).</li><li>Débit global : <strong>2028 MP/s</strong>.</li><li>Débit de calcul : <strong>7626 MP/s</strong></li><li>Le gain est obtenu sur la convolution 1D en registres.</li></ul></blockquote></div><div class="step" step="49" data-x="78400" data-y="0"><h1 id="id68">LE FILTRAGE DES IMAGES</h1><h2 id="id69">Les filtres de convolution GPU</h2><p><strong>Conclusion</strong></p><blockquote><ul><li>Amélioration limitée des débits globaux en raison de la prépondérance des temps de transfert.</li><li>Amélioration sensible sur les débits de calcul (de 17 à 33 %).</li><li>Le traitement 1D est jusqu'à 66% plus rapide. Applicable à d'autres signaux 1D.</li></ul></blockquote></div><div class="step" step="50" data-x="80000" data-y="0"><h1 id="id70">LE FILTRAGE DES IMAGES</h1><h2 id="filtre-par-recherche-des-lignes-de-niveaux">Filtre par recherche des lignes de niveaux</h2></div><div class="step" step="51" data-x="81600" data-y="0"><h1 id="id71">LE FILTRAGE DES IMAGES</h1><h2 id="id72">Filtre par recherche des lignes de niveaux</h2><p><strong>Motivations :</strong></p><blockquote><ul><li>Les algorithmes qui débruitent le mieux sont lents (BM3D).</li><li>Les images naturelles sont décomposables en un ensemble de lignes de niveaux ( iso-niveau de gris ).</li><li>Concevoir un algorithme GPU original et son implémentation.</li></ul></blockquote></div><div class="step" step="52" data-x="83200" data-y="0"><h1 id="id73">LE FILTRAGE DES IMAGES</h1><h2 id="id74">Filtre par recherche des lignes de niveaux</h2><p><strong>Principe</strong></p><blockquote><ul><li>Estimation locale, par maximum de vraisemblance, des lignes de niveaux.</li><li>Réduction de bruit par moyennage le long de la ligne estimée.</li><li>Les lignes de niveaux estimées sont modélisées par des lignes brisées nommées <strong>isolines</strong>.</li><li>Les segments des lignes brisées sont choisis parmi des motifs pré-établis (32 motifs).<img src="img/P5Q1.png" alt="" width="500px" height=""></img></li></ul></blockquote></div><div class="step" step="53" data-x="84800" data-y="0"><h1 id="id75">LE FILTRAGE DES IMAGES</h1><h2 id="id76">Filtre par recherche des lignes de niveaux</h2><p><strong>Principe (étape 1)</strong></p><blockquote><ul><li>En chaque pixel, recherche du motif maximisant la log-vraisemblance ( \(n=6, \sigma^2 =\) variance )</li></ul>$$-\frac{n}{2}log\left(2\pi\right) - \frac{n}{2}log\left(\sigma^2\right) - \frac{n}{2}$$<ul><li>Mémorisation des paramètres des motifs sélectionnés dans deux matrices \(I_{\Theta}\) et \(I_{\Sigma}\).</li></ul><img src="img/lniv-mv.png" alt="" width="500px" height=""></img></blockquote></div><div class="step" step="54" data-x="86400" data-y="0"><h1 id="id77">LE FILTRAGE DES IMAGES</h1><h2 id="id78">Filtre par recherche des lignes de niveaux</h2><p><strong>Principe (étape 2)</strong></p><blockquote><ul><li>Allongement itératif des segments sous condition GLRT.</li></ul>$$(n_{s_1s_2}+n_{s_3})\left[log\left(\widehat{\sigma_{s_1s_2}}^2\right) - log\left(\widehat{\sigma_{s_3}}^2\right) \right]$$<img src="img/pipd-detail.png" alt="" width="900px" height=""></img></blockquote></div><div class="step" step="55" data-x="88000" data-y="0"><h1 id="id79">LE FILTRAGE DES IMAGES</h1><h2 id="id80">Filtre par recherche des lignes de niveaux</h2><p><strong>Principe (étape 3)</strong></p><blockquote><p>Compensation de la non robustesse de sélection des motifs dans les zones homogènes.</p><blockquote><ul><li>identification des zones homogènes avec un détecteur de bords.</li><li>Application d'un filtre moyenneur dans ces zones.</li></ul></blockquote><img src="img/detecteur.png" alt="" width="400px" height=""></img></blockquote><div class="notes"><ul><li>Sous-ensembles de pixels n'ayant pas d'intersection --> MV</li><li>Utilisation des motifs des segments pour gain de temps.</li></ul></div></div><div class="step" step="56" data-x="89600" data-y="0"><h1 id="id81">LE FILTRAGE DES IMAGES</h1><h2 id="id82">Filtre par recherche des lignes de niveaux</h2><p><strong>Résultats</strong></p><blockquote><p>Sur l'ensemble d'images de S. Lansel (DenoiseLab, Université Stanford)</p><ul><li>Amélioration moyenne du rapport Signal sur bruit: <strong>+7,1 dB</strong></li><li>Indice de similarité structurelle : <strong>+30%</strong></li><li>Temps de calcul : <strong>7 ms</strong></li></ul><p>Comparaison avec BM3D</p><ul><li>Amélioration moyenne du rapport Signal sur bruit: <strong>+9,5 dB</strong></li><li>Indice de similarité structurelle : <strong>+36%</strong></li><li>Temps de calcul : <strong>4300 ms</strong></li></ul></blockquote></div><div class="step" step="57" data-x="91200" data-y="0"><h1 id="id83">LE FILTRAGE DES IMAGES</h1><h2 id="id84">Filtre par recherche des lignes de niveaux</h2><table cellpadding="0" cellspacing="0"><tbody><tr><td><img src="img/zoom_noisy.png" alt="" width="" height=""></img></td><td></td><td><img src="img/zoom_mean5.png" alt="" width="" height=""></img></td></tr><tr><td><p>Bruit gaussien \(\sigma=25\)</p></td><td></td><td><p>Moyennage 5x5</p></td></tr><tr><td><img src="img/zoom_pipdh.png" alt="" width="" height=""></img></td><td></td><td><img src="img/zoom_bm3d.png" alt="" width="" height=""></img></td></tr><tr><td><p>PI-PD</p></td><td></td><td><p>BM3D</p></td></tr></tbody></table></div><div class="step" step="58" data-x="92800" data-y="0"><h1 id="id85">LE FILTRAGE DES IMAGES</h1><h2 id="id86">Filtre par recherche des lignes de niveaux</h2><p><strong>Synthèse - conclusion</strong></p><blockquote><ul><li>Rapport qualité/temps élevé.</li><li>Traitement d'images HD à 20 fps.</li><li>Artefacts en marche d'escalier. Réduits par la méthode de Buades <em>et al.</em> (+1 dB, +0,2 ms pour 512x512).</li><li>Extension aux images couleurs et autres types de bruits (multiplicatif).</li><li>Algorithme original sans implémentation de référence séquentielle. Conception GPU dès l'origine.</li></ul></blockquote></div><div class="step" step="59" data-x="94400" data-y="0"><h1 id="conclusion-generale-perspectives">CONCLUSION GÉNÉRALE - PERSPECTIVES</h1><ul><li>Trois types de conception mis enœuvre.</li><li>Le portage efficace d'algorithme peut s'avérer très complexe, voire sans intérêt.</li><li>L'emploi de la mémoire partagée n'apporte pas les meilleures performances en cas de recouvrements.</li><li>L'écriture de code performant est fastidieuse et les codes non paramétriques.</li><li>Création d'un programme générateur.</li><li>Beaucoup de traitements peuvent bénéficier des techniques proposées.</li><li>Les évolutions de l'architecture laissent entrevoir de nouvelles possibilités.</li><li>Extension à d'autres domaines.</li></ul><div class="notes"><ul><li>certaines ardeurs ont été refroidies</li></ul></div></div></div><div id="hovercraft-help"><table><tr><th>Space</th><td>Forward</td></tr><tr><th>Left, Down, Page Down</th><td>Next slide</td></tr><tr><th>Right, Up, Page Up</th><td>Previous slide</td></tr><tr><th>P</th><td>Open presenter console</td></tr><tr><th>H</th><td>Toggle this help</td></tr></table></div><script type="text/javascript" src="js/impress.js"></script><script type="text/javascript" src="js/impressConsole.js"></script><script type="text/javascript" src="js/hovercraft.js"></script></body></html>