CHAPITRE 1 - ANALYSE ET CONCEPTION DU PROJET


1. Présentation des images IRM


2. Analyse des besoins
2.1. L'existant
2.1.1. Introduction
2.1.2. Schéma de l'architecture existante
2.1.3. Explications des composants de base
2.1.4. Les propriétés communes des plug-ins
2.1.5. Le plug-in TypePlugin manipulant les types de données
2.2. Les besoins fonctionnels
2.2.1. Plug-ins d'action
2.2.2. Plug-ins de visualisation
2.2.3. Plug-ins d'interface
2.2.4. Intégration de python
2.2.5. La ligne de commande
3. Partie algorithmique
3.1. Outils d'action
3.1.1. Les algorithmes de FIT
3.1.1.1. Fit linéaure
3.1.1.2. Fit exponentiel (peu précis)
3.1.2. L'algorithme de baguette magique retenu
4. Système et environnement de programmation





1. Présentation des images IRM

         L'Imagerie par Résonance Magnétique, ou IRM, est une technique de diagnostic médical permettant de visualiser l'intérieur d'un organisme de manière non invasive, c'est-à-dire sans avoir recours à une opération. Il s'agit d'une méthode de plus en plus utilisée par les médecins pour établir un diagnostic, détecter des lésions, malformations ou tumeurs.
L'instrument à IRM est composé d'un aimant qui génère un puissant champ magnétique au sein de l'organisme. Les spins des noyaux des atomes d'hydrogène, qui entrent dans la composition de l'eau, vont réagir à ce champ magnétique un peu comme l'aiguille d'une boussole, et une petite partie d'entre eux va s'orienter vers le pôle magnétique imposé par l'aimant. Lorsque l'on impose une onde radio perpendiculaire aux lignes du champ magnétique durant quelques millisecondes, les spins vont changer d'orientation. La déviation par rapport à la direction du pôle dépend de la durée d'imposition de l'onde. Au moment où l'on stoppe l'onde, les noyaux des atomes d'hydrogène, les protons, sont dans un état instable d'un point de vue énergétique: ils sont excités. Les spins des protons vont ensuite revenir à leur état d'équilibre, majoritairement dans la direction du pôle magnétique. Ce faisant, ils vont émettre un signal sous la forme d'une onde radio, laquelle sera détectée par l'instrument. Les signaux les plus intenses proviennent des zones de l'organisme qui contiennent plus de molécules d'eau, tel le cerveau, par exemple. Un ordinateur pilote l'instrument à IRM, contrôle la durée d'émission de l'onde d'excitation, puis collecte les signaux émis par les protons afin de construire une image.

         Le contraste de l'image construite dépend des différences de densité en eau dans les différents tissus étudiés, sains ou malades. Or ces différences sont naturellement faibles. Pour améliorer la sensibilité et le contraste de l'image, on peut activer spécifiquement les protons des zones du corps à analyser grâce à l'utilisation d'agents de contraste. Ces derniers sont des molécules qui sont injectées in vivo, en général par voie intraveineuse.

         La barrière hematoencéphalique protège les tissus du cerveau de la manière suivante: elle empêche les substances qui transitent par le sang de diffuser dans les tissus. Les tumeurs cancéreuses à l'intérieur du cerveau présentent des failles de cette barrière et sont ainsi plus perméables à la diffusion de molécules chimiques que les tissus sains. Ainsi, les agents de contraste vont diffuser dans les tissus cancéreux du cerveau, et pas ou très peu dans les tissus sains. Ils permettent donc de localiser précisément ces tumeurs.

(d'après Fabrice YERLY)



Figure 1 - IRM et salle d'analyse des réalisations

2. Analyse des besoins
2.1. L'existant

2.1.1. Introduction

        Une structure générale du logiciel basée sur un système de noyau - plug-in nous a été fournie. Il nous a fallu comprendre cette architecture plutôt complexe, dont nous allons essayer de vous présenter les particularités.

        L'architecture mise en place allège le noyau, qui ne fait que lancer les différents plug-ins. Ainsi, les plug-ins devront trouver un moyen de communiquer directement entre eux.

2.1.2. Schéma de l'architecture existante




Figure 2 - Diagramme de classe général de l'existant.

2.1.3. Explications des composants de base

  • Le Kernel ou noyau répertorie les différents plug-ins présents dans un répertoire plugins/ et instancie tous les plug-ins IO et Type. Il possède des pointeurs sur le PluginManager ainsi que le DataManager.

  • Le PluginManager contient la liste des plug-ins chargés. Il est capable de créer ou détruire un plug-in.

  • Le DataManager contient la liste des objets ouverts quels qu'ils soient. Ils sont de type dérivé de la classe AnyData (voir schéma ci-dessous).


    Figure 3 - Diagramme de classes des styles de données (existant).

            La classe Generic2DimageData permet d'instancier des images de type _2DimageData pour trois types de données : signedShort, float et unsignedChar.

            La classe virtuelle MRI3DImageData permet de manipuler des images IRM, qui sont instanciées par deux classes FloatMRI3DimageData et SignedShortMRI3DimageData suivant leur codage.

  • Parameter permet de typer les paramètres (tous types de données) passer aux plug-ins ainsi que leurs valeurs de retour.

    Les différentes familles de paramètres utilisées sont :
  • les données auxiliaires : P_DOUBLE, P_FLOAT, P_STRING, P_INT…
  • les données à manipuler par leur index dans le DataManager : P_DATA_ID
  • les références vers les managers : P_DATA_MANAGER, P_PLUGIN_MANAGER
  • le type d'utilisation : P_RUN_MODE
  • la valeur de retour d'un appel de plug-in : P_STATUS
  • un type général : P_POINTER, pour manipuler tout type d'objet.

    Remarque : La classe Exception : fournie avec l'architecture initiale, elle était destinée à faire communiquer les plug-ins entre eux, mais nous avons finalement opté pour une autre solution. C'est pourquoi, cette classe n'est pas utilisée à ce stade du développement.



  • 2.1.4. Les propriétés communes des plug-ins

    Chaque nouveau plug-in implanté devra hériter d'une des classe de type de plugin implémentant l'interface Plugin (voir Figure 2).

    Il y a initialement cinq types de plug-ins (livrés sous forme de canevas) :

  • TYPE : permet d'instancier les différents types de données.
  • INPUT/OUTPUT : ouvre ou sauvegarde les données dans des fichiers. En l'état actuel, seuls les fichiers de type REC/PAR (format médical propriétaire de PHILIPS) pour les données IRM et PGM pour les images sont reconnus.
  • ACTION : contient tous les traitements que l'on peut appliquer aux données. Il s'agit de processus de traitement de données qui modifient les données en entrée ou créent de nouvelles données.
  • VISUALISATION : prépare les données, soit pour les sauvegarder, soit pour les afficher.
  • INTERFACE qui contiendra tous les composants graphiques du logiciel, l'interface principale et les boîtes de dialogue permettant de récupérer des paramètres d'action. En considérant l'interface comme un plug-in, elle se détache du noyau, ce qui la rend optionnelle et permet d'utiliser le logiciel en ligne de commande. Cela permet également la possibilité aux développeurs de choisir leur propre A.P.I. graphique (GTK, QT, Motif,…) pour l'interfaçage du logiciel.
  • 2.1.5. Le plug-in TypePlugin manipulant les types de données

    Ce projet nécessite la mise en place de différents types de données tels que l'on peut le voir sur le diagramme de classe de la figure 4.




    Figure 4 - Diagramme de classes des types de données (existant).

    Il s'agit des plug-ins Type qui servent à instancier les données à manipuler.

    2.2. Les besoins fonctionnels
    Nous allons à présent décrire simplement ce que souhaite le client.

    2.2.1. Plug-ins d'action

  • Traitement FIT

            Il permet l'approximation d'un nuage de points en 2 dimensions (provenant de mesures notamment) à l'aide de fonctions types qui peuvent être polynomiales ou exponentielles paramétrées.
            L'utilisateur définit le type de fonctions qu'il désire utiliser. L'algorithme détermine alors quels sont les paramètres qui permettent d'approcher le mieux le nuage de points. Par exemple, on possède un ensemble de relevés de température que l'on a reporté sur un graphique, cela forme alors un nuage de point (Figure 5). On désire ensuite trouver une relation entre ces points à l'aide d'une fonction polynomiale de degré un (Figure 6).




    Figure 5 - Relevé de température.




    Figure 6 - Approximation par fonction linéaire.

  • Sélection de régions d'intérêt (à la manière d'une " baguette magique ").

  •         On veut proposer deux types de sélection de régions. Pour le premier type, on veut pouvoir sélectionner une région 2D à l'intérieur d'une coupe à l'image de logiciels tel que Gimp ou Photoshop. Voici quelques captures des résultats obtenus avec notre outil.




    Figure 7 - Image originale.



    On sélectionne une zone grise de l'image, et on obtient les images suivantes :

    Figure 8 - Image obtenue avec une tolérance à 20% (à gauche) de l'intervalle du type constituant la donnée, puis 10% (à droite).

    2.2.2. Plug-ins de visualisation

    Afin de répondre au critère de généricité du logiciel, les plug-ins de visualisation servent d'intermédiaire entre les données du DataManager et leur affichage ou leur sauvegarde. Ces plug-ins servent à préparer les données pour qu'elles soient utilisables pour un plug-in Input/Output donné ou pour un plug-in Interface. Dans cette optique, les outils à développer sont les suivants :



    2.2.3. Plug-ins d'interface

    Il s'agit ici de développer le système de fenêtrage graphique de l'application. Les outils à développer sont les suivants :


  • Affichage des graphiques 1D.

  • Affichage d'une image 2D.

  • Affichage d'une coupe 2D d'une donnée IRM avec possibilité de naviguer dans la donnée 3D.

  • Affichage 3D par l'intermédiaire d'une fenêtre graphique affichant du code OPENGL.

  • Composants d'interface classique : barre de menu, boîte de dialogue pour récupérer les paramètres des actions, zone d'affichage graphique, ...


    2.2.4. Intégration de python

    Il est prévu d'intégrer un interpréteur de scripts au sein du logiciel. Cette intégration doit permettre la création et l'utilisation de scripts afin d'automatiser des traitements sur les données. Ces scripts seront aussi bien disponibles en ligne de commande, que dans un menu de l'interface graphique suivant son mode d'exécution. Plusieurs langages de scripts existent (Python, TCL, …), un choix doit être fait.

    Le langage Python a été choisi car il devient relativement populaire et ses sources sont libres. De plus, l'analyse syntaxique n'est pas à la charge du développeur car elle est intégrée au langage. Enfin, il semble que cette démarche ait été envisagée dans d'autres logiciels, nous disposons donc d'un existant en la matière.


    2.2.5. La ligne de commande

    Le logiciel doit pouvoir se lancer en ligne de commande. Il s'agit d'appliquer une suite d'opérations depuis l'ouverture d'un ou plusieurs fichiers jusqu'à leur sauvegarde.
    Ces opérations sont transparentes pour l'utilisateur.
    Ceci implique que l'utilisateur pourra accéder aux différentes fonctionnalités au moyen de paramètres passés lors du lancement du programme en ligne de commande.

    Par exemple :
    On veut quantifier 10 fichiers de données IRM sur 256 couleurs. Pour cela, il n'est pas nécessaire de lancer le logiciel en mode graphique, et d'ouvrir et sauver 10 fois les fichiers. On préférera lancer un script automatisant le traitement en lui fournissant la liste des fichiers à traiter.

  • 3. Partie algorithmique

    Nous allons à présent décrire les recherches effectuées et algorithmes utilisés pour nos outils.

    3.1. Outils d'action

    3.1.1. Les algorithmes de FIT

    Le But des algorithmes qui vont suivre est d'approximer au mieux un nuage de points.

    3.1.1.1. Fit linéaire

    Nous disposons de valeurs initiales et nous cherchons une droite qui approche ces valeurs.


    Figure 9 - Schéma d'un Fit linéaire.

    Nous souhaitons minimiser une combinaison raisonnable des distances, représentées en orange dans le schéma ci-dessus. Une combinaison raisonnable de ces distances serait par exemple d'en faire leur somme. Une autre idée est de faire la somme des carrés de ces distances ce qui évite de devoir travailler avec des valeurs absolues qui seraient nécessaire avec la simple somme des distances. La ligne qui minimise cette dernière somme est aussi appelée " best fit line " aux données initiales.

    On peut formaliser cela de la façon suivante :


    N points initiaux : (x1, y1), (x2, y2), . . . , (xn, yn).

    Fonction Fit recherchée : y = m.x + b

    Pente = m =



    b =

    Avec :
    xy = x1y1 + x2y2 +...+ xnyn
    x = x1 + x2 + . . . + xn
    y = y1 + y2 + . . . + yn
    x2 = x12 + x22+ . . . + xn2

    L'algorithme implanté dans notre outil reprend les calculs des valeurs m et p.
    Il reste un dernier élément à évaluer. Il s'agit de la précision du résultat obtenu. Pour calculer cette précision, il existe un coefficient dit de corrélation. Il est compris entre -1 et 1. Plus sa valeur est proche de ces bornes, plus l'erreur est minimisée. La formule de ce coefficient est la suivante :
    r =


    3.1.1.2. Fit exponentiel (peu précis)

    Il est également possible d'approximer un nuage de points par une courbe exponentielle de la forme : y = aebx.
    L'idée es de convertir la courbe exponentielle en une forme d'équation linéaire, ce qui permettrait de réutiliser l'algorithme expliqué précédemment. On peut effectuer ce passage à l'aide des logarithmes.
    y = aebx
    ln(y) = ln(aebx) on applique la fonction ln de chaque coté de l'équation
    ln(y) = ln(a) + ln(ebx) propriétés du logarithme
    ln(y) = ln(a) + bx.
    On applique ensuite deux changements de variable :
    u = ln(y) et c = ln(a)

    On obtient donc une fonction linéaire : u = bx + c
    On peut alors résoudre cette fonction linéaire avec l'algorithme précédemment expliqué.
    Il suffit ensuite de refaire un changement de variable pour obtenir a.
    a = ec
    Cette méthode, bien que correcte, engendre toutefois une trop grosse marge d'erreur pour l'utilisation que notre client envisage. Il reste donc à modifier cet algorithme.

    3.1.2. L'algorithme de baguette magique retenu

    Nous avons appliqué l'algorithme de " Region growing ". Le but est d'explorer un voisinage 4-connexe (dans un ordre donné : droite, haut, gauche, bas) dans le cas de la baguette magique 2D.
    On dispose d'une pile Fifo, qui va accumuler la liste des points à explorer.

    Début : On ajoute le pixel dans les pixels sélectionnés
    Pour chaque point du voisinage 4-connexe de ce pixel

    Tant que pile Fifo non vide
    Faire

    Si ( le point n'a pas encore été sélectionné et qu'il vérifie la tolérance )
    On ajoute le nouveau point dans la pile Fifo
    On récupère le point situé au sommet de la queue

    Exemple :


    Figure 10 - Parcours du voisinage pour l'algo de baguette magique 2D.

    Pour la baguette magique 3D, il suffit juste d'étendre le voisinage de test de l'algorithme précédent, àun voisinage 6-connexe (voir schéma ci-dessous).


    Figure 11 - Voisinage exploré pour la baguette magique 3D.

    4. Système et environnement de programmation

    Nous avons développé notre application sur le système Linux (noyau 2.4).
    Au cours de ce projet, nous avons commencé par travailler sur l'environnement de développement kylix version 3, qui aurait dû nous permettre de construire notre interface graphique. Nous avons eu de nombreux problèmes concernant la stabilité de cet environnement sur système Debian. Ainsi, nous avons finalement modifié notre cahier des charges et utilisé Kdevelop et la bibliothèque Qt version 1.3. Le véritable changement a été de se familiariser avec une bibliothèque graphique qui n'était pas prévue initialement.
    Enfin, nous avons utilisé Gcc version 2.95, et OpenGl 1.2.

    Après avoir détaillé les principaux composants à intégrer au logiciel, nous allons maintenant vous présenter nos travaux effectués. Ils consistent dans un premier temps à modifier l'architecture afin de valider le système noyau/plug-in tel qu'il était demandé, puis d'implémenter les différents algorithmes et enfin de développer la partie graphique d'interaction avec l'utilisateur.



    retour au sommaire            chapitre 2: Dossier de programmation