MediPy – Plate-forme de développement logiciel pour

publicité
MediPy – Plate-forme de développement logiciel
pour la neuro-imagerie
Julien Lamy <[email protected]>
Laboratoire d'imagerie et de neurosciences cognitives, équipe Imagerie in vivo
Université de Strasbourg
Introduction
●
Historique
●
●
●
Développement d'algorithmes de traitement d'images
médicales depuis une quinzaine d'années, collaboration
avec l'équipe TIM du LSIIT
Naissance de la plate-forme Medimax
Medimax
●
●
●
C/C++, Gtk+ v.1, contient les travaux de nombreux
chercheurs et doctorants
Difficilement portable (Linux seulement)
Plat de spaghetti : dépendances croisées, code dupliqué,
pas d'utilisation de bibliothèques externes, …
Introduction
●
MediPy
●
●
Refonte totale de Medimax (Python/C++)
●
Python : facilité de la syntaxe pour les nouveaux arrivants
●
C++ : performances
Utilisation de bibliothèques tierces reconnues (ITK, VTK,
NumPy, …)
●
Plate-forme portable
●
Modularité, indépendance traitement-visualisation
●
Distribution du logiciel sous licence libre (CeCILL-B)
Plan de la présentation
●
●
MediPy – l'application
●
Visualisation
●
Traitement
MediPy – la plate-forme de développement
●
Structures de données
●
Création d'un plugin
●
Compilation
●
Application dérivées
●
Redistribution
MediPy – l'application
Visualisation & traitement
MediPy – l'application
Entrées & sorties
●
●
Images
●
Formats classiques 2D : JPEG, PNG, BMP, …
●
Formats spécifiques imagerie médicale : DICOM, NIfTI, NRRD, …
●
Formats spécifiques constructeurs : SMIS, Bruker, …
Surfaces
●
VRML (surface uniquement)
●
VTK
Entrées & sorties – DICOM
●
Lecture d'un DICOMDIR ou d'une liste de fichiers
●
Présentation hiérarchique (patient, étude, série)
●
Utilisation de GDCM
Visualisation
●
●
Images
●
2D ou 3D (visualisation de coupes dans le volume 3D)
●
« Image » au sens large : visualisation de spectres HR-MAS
Surfaces
●
Fonctionalités basiques
●
Plan de coupe
●
Pseudo-texture
Visualisation – Images
●
Multiplanaire ou une seule coupe
Visualisation – Images
●
Spectre HR-MAS (iso-contours)
Visualisation – 2D
●
Plusieurs calques avec table de couleurs
Visualisation – 2D
●
Annotations
Visualisation 2D
●
Plusieurs images synchronisées
Visualisation – Objets 3D
●
Plusieurs objets colorisés
Visualisation – Objets 3D
●
Pseudo-texture en fonction d'une profondeur dans une image
●
Plans de coupe
Traitement
●
●
Fournis par des plugins
(e.g. débruitage,
morphologie)
Accessibles
●
●
Depuis l'interface
graphique (pour la mise
au point d'une chaîne de
traitements)
Depuis des scripts Python
(pour les traitement par
lots)
Traitement – Interface Graphique
●
Plugins répertoriés dans l'arborescence en haut à gauche
●
Interface de la fonction en bas à gauche
Traitement – Script
●
Script Python avec appel direct des fonctions de MediPy
●
Exemple de traitement d'un lot d'images :
import
import
import
import
os
sys
medipy.io
medipy.morphology
root = sys.argv[1]
for dir in os.listdir(root) :
image = medipy.io.load(
os.path.join(root, dir, "image.nii"))
result = medipy.morphology.grayscale_dilate(
image, "ball", 3)
medipy.io.save(image, "result.nii")
MediPy – la plate-forme de développement
Structures de données, plugins, applications, redistribution
Briques logicielles
●
●
Langages : Python (2.5, 2.6), C++
Traitement : ITK/WrapITK, NumPy, SciPy, VTK,
Cython, OpenMP, FSL (en cours)
●
Visualisation : VTK, wxPython
●
Déploiement : SCons, py2exe, WiX
Structures de données
●
●
Deux principaux types d'objet
●
Image
●
Objet 3D
Image : découplage traitements/visualisation
●
●
●
Traitement : « image » = une image
Visualisation : « image » = piles d'images (calques) + mode
de visualisation + annotations + outils + …
Objet 3D : plus simple, traitement = visualisation
Image (traitement)
●
Image
●
●
●
●
●
données n-dimensionnelles (numpy.ndarray)
transformation linéaire espace pixel ↔ espace réel
Préel = direction*taille_pixels*Ppixel+origine
●
direction : matrice n×n
●
taille_pixels, origine : en mm, vecteur de taille n
dimensionnalité des données : e.g. un tableau de dimension
3 est il une image 3D de scalaires ou une image 2D de
vecteurs ?
méta-données : identifiant du patient, paramètres de
séquence IRM, …
C++ : utilisation des classes itk::Image et itk::VectorImage
Image (traitement)
●
Compatible avec NumPy/SciPy :
result.data = numpy.add(image1, image2)
●
Pont de/vers ITK, sans recopie des données, transfert
optionnel de la propriété des données :
from medipy.itk import (medipy_image_to_itk_image,
itk_image_to_medipy_image)
itk_input = medipy_image_to_itk_image(input, False)
filter = itk.GrayscaleErodeImageFilter[...].New(...)
itk_output = filter()[0]
output = itk_image_to_medipy_image(itk_output, None, True)
Image (visualisation)
●
●
Visualisation d'une image : coupes, calques, couleurs,
annotations, outils, …
Trois classes principales
●
Calque : Layer, dont dérivent ImageLayer et ContourLayer
●
●
●
Données, table de couleur, opacité, coordonnées pixels ou physiques
Coupe 2D : Slice
●
Ensemble de calques (position synchronisée)
●
Matrice de projection, curseur, outils
●
vtkRenderer
Image : widget wxPython
●
Ensemble de coupes (position, zoom, calques, etc. synchronisés)
●
vtkRenderWindowInteractor
Objet 3D
●
Basé sur un vtkDataSet
●
Lien optionnel avec une image
●
Texturage de plans de coupe
●
Pseudo-texture
Création d'un plugin
●
●
Un plugin peut ajouter
●
Fonctions de traitement
●
Outils
●
Autres (duck-punching)
Plugin ↔ paquet Python
Création d'une fonction
●
Deux aspects
●
●
Traitement
●
Bibliothèques utilisables
●
Ponts entre les représentations
Interface graphique
●
Définition de l'interface graphique reliée à une fonction
●
Représentation graphique des paramètres
●
Contraintes sur les valeurs
Création d'une fonction – Traitements
●
●
●
Bibliothèques utilisables
●
ITK : C++, Python (WrapITK)
●
NumPy, SciPy : Python, C++
●
Pont en cours vers FSL (C++, open source mais non libre)
Ponts
●
medipy.base.Image ↔ itk.Image ↔ itk::Image
●
medipy.base.Image ↔ numpy.ndarray ↔ itk::Image
Possibilité de tout mélanger dans une fonction, les
ponts opèrent tous dans les deux sens
Création d'une fonction – GUI
●
Lien fort entre la fonction et son interface graphique
●
●
Utilisation de la docstring
Syntaxe simple
●
XML
def erode(input, shape, radius) :
""" Gray-scale erosion of an image.
<gui>
<item name="input" type="Image" label="Input"/>
<item name="shape" type="Enum" label="Shape"
initializer="('ball', 'box','cross')"/>
<item name="radius" type="Int" label="Radius"
initializer="1"/>
<item name="output" type="Image" label="Output"
initializer="output=True" role="return"/>
</gui>
"""
Création d'une fonction – GUI
●
Éléments XML
<gui><item name="input" type="Image" label="Input"/></gui>
●
●
●
gui : contient la description de l'interface graphique
item : décrit un des paramètres (ou une des valeurs de retour)
de la fonction.
Attributs de l'élément item :
●
name : nom du paramètre de la fonction
●
type : type du contrôle utilisé pour représenter ce paramètre
●
label : nom affiché
●
role : input, output ou return, sémantique du paramètre (optionnel)
●
initializer : expression pour initialiser le contrôle (optionnel)
●
tooltip : optionnel
Création d'une fonction – GUI
●
Types de contrôles et
paramètres
●
Bool : valeur
●
Enum : valeur, liste de choix
●
●
●
●
Int, Float, FloatInterval :
valeur, intervalle
String : valeur
File, Directory : valeur, filtre de
noms, lecture ou écriture
Image, Object3D : valeur, liste
de choix, création d'un nouvel
objet
Création d'une fonction – GUI
●
Dépendance entre contrôles
●
●
Syntaxe : ${nom_du_parametre}
Exemple : limiter un entier à la dynamique
d'une image
<gui>
<item name="input" type="Image" label="Input"/>
<item name="value" type="Int" label="Value"
initializer="range=(${input}.data.min(),
${input}.data.max())"/>
<item name="output" type="Image" label="Output"
role="output" initializer="output=True" />
</gui>
Création d'un outil
●
●
Outil (e.g. position, contraste, zoom)
●
Sur la visu 2D ou 3D
●
Clavier (appui sur une touche) ou souris (clic, glissement)
●
Classe dérivant de KeyboardTool ou MouseTool
Fonctions communes clavier et souris :
●
select : sélection de l'outil (e.g. affiche un dialogue)
●
deselect : déselection de l'outil
Création d'un outil
●
●
Fonctions outils clavier :
●
press
●
release
Fonctions outils souris :
●
start_interaction
●
dispatch_interaction
●
stop_interaction
Création d'un plugin
●
●
Paquet Python classique
Présence d'un module api.py décrivant les fonctions
exportées :
from
from
from
from
●
●
binary import erode as binary_erode
binary import dilate as binary_dilate
grayscale import erode as grayscale_erode
grayscale import dilate as grayscale_dilate
Intégration automatique des fonctions déclarées dans
le fichier api.py dans le menu
Chemin de recherche des plugins : variable
d'environnement MEDIPY_PLUGINS_PATH
Compilation
●
Utilisation de SCons
●
Utilisation de variant_dir par défaut
●
Un SConstruct par répertoire
●
Builders spécifiques :
●
CythonModule("my_module", ["foo.pyx", "bar.pyx"])
●
VTKPythonModule("my_module", ["vtkFoo", "vtkBar"])
●
WrapITKPythonModule
Compilation – WrapITK
●
Builder plus complexe, dû aux templates C++
●
Très fortement inspiré du processus CMake
●
Instanciations de chaque classe :
>>> get_instantiations("itk::Image",
["float", "short"], [2, 3])
[('Image', 'float', 2), ('Image', 'float', 3),
('Image', 'short', 2), ('Image', 'short', 3)]
●
Appel du builder
env.WrapITKPythonModule(
"my_module", [["itk::Foo", foo_instantiations],
["itk::Bar", bar_instantiations]])
Applications dérivées
●
●
Facilité de réaliser des applications dérivées
●
Inclusion d'un nombre restreint de fonctions
●
GUI spécifique
Exemples
●
Lecture randomisée d'images, annotation de lésions de SEP
●
Planificateur de TMS robotisée
Applications dérivées
Applications dérivées
Applications dérivées
●
Classes simplifiant la réalisation d'applications dérivées
●
●
Recherche des resources dans l'application courante ou dans
MediPy
Simplification de la gestion des fichiers XRC, création
automatique des membres correspondant aux widgets
class MainFrame(medipy.gui.base.Frame):
class UI(medipy.gui.base.UI):
pass
def __init__(self, parent=None, *args, **kwargs):
self.ui = MainFrame.UI()
xrc_file = medipy.base.find_resource("my_file.xrc")
medipy.gui.base.Frame.__init__(
self, xrc_file, ui=self.ui, self.ui.controls,
parent, *args, **kwargs)
Applications dérivées
class MainFrame(medipy.gui.base.Frame):
class UI(medipy.gui.base.UI):
def __init__(self):
self.t1_image = None
self.flair_image = None
self.slice = None
self.lesions = None
self.next_image = None
self.controls = ["t1_image", "flair_image", "slice",
"lesions", "next_image"]
medipy.gui.base.UI.__init__(self)
def __init__(self, parent=None, *args, **kwargs):
pass
Redistribution
●
Pour l'instant, seulement sous Windows
●
Deux étapes
●
●
Création d'une version redistribuable (choix des plugins,
dépendances, intégration de l'interpréteur Python)
Création d'un installeur
Redistribution
●
Création d'une version redistribuable
●
Utilisation de py2exe
●
Prise en compte des composants et des plugins à inclure
import os.path
import shutil
from medipy.deployement import setup
includes = ["itk", "medipy.itk", "medipy.gui.control",
"medipy.segmentation"]
setup.setup("TMSPlanification","tms_planification.py", includes)
Redistribution
●
Création d'un installeur
●
Utilisation de WiX
●
Enrobage Python autour de heat, candle et light
from medipy.deployement import build_msi
build_msi("MyKillerMediPyApplication")
Conclusion
●
●
●
●
MediPy : logiciel de traitement d'images médicales et
plate-forme de développement
●
Traitement d'images
●
Visualisation
●
Création d'application spécialisées
Licence CeCILL-B (BSD-like)
Disponible sur Google Code :
http://code.google.com/p/medipy/
Fonctionne sous Linux et Windows
Perspectives
●
●
●
Portage sur MacOS
Amélioration de la visu 2D pour les données nonscalaires (IRMf, DTI)
Connexion aux sources de données (PACS, XNAT,
Shanoir, …)
Merci de votre attention !
Téléchargement