Il Medical Imaging Interaction Toolkit (MITK) è un software open source per costruire applicazioni interattive di elaborazione di immagini mediche, sviluppato dal Deutsches Krebsforschungszentrum (DKFZ) di Heidelberg e distribuito con licenza BSD. La versione corrente è MITK 2016.03, uscita in questi giorni; il progetto rilascia versioni stabili ogni pochi mesi, con la nomenclatura AAAA.MM. Qui guardo come è organizzato il codice e dove cade il confine tra ciò che il toolkit dà già pronto e ciò che chi lo usa deve aggiungere.
Contesto
MITK nasce nel 2003 in un gruppo di lavoro orientato all’oncologia — segmentazione di masse, pianificazione di interventi al fegato — e la prima descrizione della sua architettura è l’articolo del 2005 su Medical Image Analysis, che fissava già l’idea di fondo: estendere l’Insight Toolkit (ITK) e il Visualization Toolkit (VTK) con un livello di interazione e un modello dati comune, invece di riscrivere da capo segmentazione e rendering. ITK e VTK, nati alla fine degli anni Novanta nell’ambito del Visible Human Project e poi mantenuti da Kitware, coprono rispettivamente l’analisi (filtri, registrazione, segmentazione algoritmica) e la visualizzazione (pipeline di rendering 2D e 3D). MITK non li rimpiazza: ci lavora sopra.
Il copyright è del DKFZ e la licenza è di tipo BSD. Per chi valuta il toolkit pensando a un prodotto, è il primo dato che pesa: non c’è vincolo di copyleft, quindi se ne può derivare software commerciale chiuso senza l’obbligo di ridistribuire le proprie modifiche.
Architettura
Sotto MITK 2016.03 c’è uno stack di librerie collaudate: ITK per l’analisi, VTK per il rendering, Qt per l’interfaccia C++, DCMTK per l’I/O DICOM (Digital Imaging and Communications in Medicine), il Common Toolkit (CTK) per i componenti condivisi tra progetti di imaging e i CppMicroServices come implementazione C++ del modello a servizi di ispirazione OSGi (Open Services Gateway initiative).
Sopra queste dipendenze, il cuore di MITK è il DataStorage: un unico repository che tiene in memoria tutti gli oggetti caricati. Ogni oggetto — un volume di immagini, una superficie, un point set, una segmentazione — vive dentro un DataNode, e ogni DataNode si porta dietro un insieme arbitrario di proprietà (colore, opacità, visibilità, e qualunque chiave l’applicazione voglia aggiungere). Il DataStorage non è una lista piatta: tiene un grafo di relazioni tra i nodi, così una segmentazione può essere registrata come derivata del volume da cui viene, e una query può risalire alle sorgenti o alle derivazioni di un nodo. Le viste — i tre piani ortogonali (assiale, sagittale, coronale) più la vista 3D — leggono dal DataStorage e si aggiornano quando il modello cambia. È un normale schema Model-View, applicato però in modo coerente fino in fondo: tutte le finestre di rendering osservano lo stesso repository, ed è questo che tiene le viste sincronizzate senza bisogno di codice di sincronizzazione scritto a mano.
Il livello a plugin
Quello che chiamo MitkWorkbench — l’applicazione completa, con i suoi menu, le prospettive e i moduli — poggia su BlueBerry, un framework a plugin che prende il modello a bundle di Eclipse e lo porta in C++ e Qt. Le funzionalità cliniche non stanno nel core: stanno in plugin che dichiarano i propri contributi (viste, voci di menu, toolbar, prospettive) e le proprie dipendenze, e che vengono risolti e attivati a runtime.
Il punto da chiarire, perché manda spesso in confusione, è che BlueBerry non gestisce più da sé la risoluzione dei plugin. Nelle versioni recenti si appoggia al CTK Plugin Framework per la registrazione e l’attivazione dei plugin: una implementazione OSGi-like che CTK fornisce in forma più completa rispetto al vecchio codice di BlueBerry. I CppMicroServices sono un’altra cosa: danno il registro di servizi a grana più fine (un modulo pubblica un servizio, un altro lo consuma) e non c’entrano con la registrazione dei plugin. In concreto: il plugin è l’unità di distribuzione e di ciclo di vita, gestita dal CTK Plugin Framework; il microservizio è l’unità di interazione tra componenti, gestita dai CppMicroServices. Sono due livelli sovrapposti, e conviene tenerli distinti quando si legge il codice o si scrive un modulo nuovo.
Per chi estende il toolkit, questa stratificazione vuol dire che un modulo clinico specifico — mettiamo l’analisi volumetrica di un certo tipo di lesione — si scrive come plugin che si aggancia ai punti di estensione, senza toccare il core e senza ricompilare l’intera applicazione.
Punto critico
La separazione tra registrazione dei plugin (CTK) e registro dei servizi (CppMicroServices) è il dettaglio architetturale che ripaga di più in fase di lettura del codice, e quello su cui si inciampa più spesso. Un modulo MITK può dipendere da un servizio senza dipendere staticamente dal plugin che lo fornisce: la risoluzione avviene a runtime, contro il registro. È un buon disaccoppiamento, ma sposta a runtime errori che un linker intercetterebbe già in fase di compilazione — un servizio non disponibile non è un errore di build, è un riferimento nullo nel momento in cui lo usi. Chi costruisce su MITK deve trattare l’assenza di un servizio come uno stato previsto, non come un caso che non può succedere, e questo vale a maggior ragione quando il software finisce sotto valutazione del rischio.
Implicazioni regolatorie
MITK è un toolkit di sviluppo e di per sé non è un dispositivo medico. La distinzione pesa. Costruirci sopra un prodotto clinico certificato non toglie nessuno degli obblighi del fabbricante: il ciclo di vita del software va condotto secondo la norma IEC 62304, la gestione del rischio secondo la ISO 14971, la documentazione tecnica è specifica del prodotto finale, e in Europa serve la marcatura CE sotto la Direttiva Dispositivi Medici 93/42/CEE — con il nuovo regolamento, in discussione in sede europea proprio in questo periodo, che ne ridisegnerà gli obblighi.
Partire da una base open source ispezionabile e mantenuta riduce la quantità di codice da scrivere e verificare da zero, ma non riduce la responsabilità: la qualifica del prodotto resta tutta in capo a chi lo immette sul mercato. Una libreria BSD scaricata da un repository pubblico non porta con sé nessuna evidenza di processo spendibile in una pratica di certificazione; quell’evidenza va prodotta a parte, sopra.
Limiti
Lo scripting Python in MITK 2016.03 è limitato rispetto ad altre piattaforme open source di imaging, dove estendere via script è il modo di lavorare più comune: qui la via maestra resta il C++ con il modello a plugin, e questo alza la soglia d’ingresso per chi prototipa. La documentazione architetturale pubblica è disomogenea — la pagina di overview della release cita ITK e VTK ma non mostra lo stack a plugin, e per capire il rapporto tra BlueBerry, CTK e CppMicroServices tocca passare dal wiki, dalle mailing list e dal codice. La comunità è internazionale ma con baricentro tedesco e accademico, e l’adozione fuori dai gruppi di ricerca resta circoscritta: per le workstation diagnostiche di routine gli ospedali continuano a usare i prodotti dei grandi fornitori.
- https://www.mitk.org/
- https://docs.mitk.org/2016.03/index.html
- https://github.com/MITK/MITK
- https://github.com/commontk/CTK
- https://pubmed.ncbi.nlm.nih.gov/15896995/
- https://itk.org/
- https://vtk.org/
- https://www.commontk.org/
- https://www.dkfz.de/
- https://www.noze.it/insights/mitk-dkfz-imaging-toolkit/
Immagine di copertina: Edificio moderno del Deutsches Krebsforschungszentrum (DKFZ) a Heidelberg sotto un cielo limpido, con facciata a fasce orizzontali — foto di Rudolf Stricker, licenza libera con attribuzione — https://commons.wikimedia.org/wiki/File:Heidelberg_DKFZ_Neuenheimer_Feld_20120501.jpg