Hochschule Bremerhaven Medizinische Bildverarbeitung SS 17— MT-B 6 Eine sehr kurze Einführung in Python und SimpleITK Teil 1 richard rascher-friesenhausen [email protected] Dies ist eine sehr, sehr kurze Einführung zu (I)Python und den Möglichkeiten, vermittels des Moduls SimpleITK zwei- und dreidimensionale Grauwertbilder zu erzeugen und zu bearbeiten. Python ist eine interpretierte objektorientierte Programmiersprache. D.h. insbesondere, dass man sie direkt und ohne Übersetzer und Binder interaktiv verwenden kann. (Anders als bei C++ oder Java.) Ihr wird nachgesagt, eine leicht verständliche und erlernbare Syntax zu besitzen. Und es gibt viele vorgefertigte Module, die einem eine Menge Programmierarbeit für spezielle Anwendungen abnehmen. Python kann frei aus dem Internet heruntergeladen werden. Die in dieser Veranstaltung verwendete Distribution findet man bei www.anaconda.com mit allen hier verwendeten Modulen. Die Programmiersprache ist gut dokumentiert und es findet sich jede Menge Hilfe zu Python frei im Internet. Ich empfehle insbesondere das offizielle Python-Tutorial: http://www.python.org/doc/current/tut/tut.html auf englisch. Wir verwenden im weiteren die IPython Umgebung, weil wir dort auch interaktiv Grafiken darstellen lassen können. Eine Alternative dazu ist die vollständigen Entwicklungsumgebungen Spyder (enthält IPython als Python-Konsole im unteren rechten Fenster). Die Bildverarbeitung wird mittels des Moduls SimpleITK durchgeführt. Informationen dazu findet man unter http://www.simpleitk.org/ auf englisch. Das Modul gehört nicht zur Anaconda-Distribution und muss auf dem eigenen Rechner über den Konsolen-Befehl easy_install SimpleITK nachinstalliert werden. Um die Bilder einfach aus Python heraus mit SimpleITK darstellen zu können, wird auch noch das Programm Fiji bzw. ImageJ benötigt, welches man frei unter https://fiji.sc/ bzw. http://www.imagej.org beziehen kann. 1 Erste Python Schritte Rufen Sie IPython über das Windows-Startmenu auf. Suchen Sie dazu den Eintrag Anaconda in der Startleiste und wählen sie den Eintrag IPython aus. Damit starten Sie eine kommandozeilenorientierte Entwicklungsumgebung für Python mit eingebauten Grafikfähigkeiten. Oder Sie verwenden das IPython Fenster in Spyder. ImageTutorial 1 1 prof. dr. richard rascher-friesenhausen Hochschule Bremerhaven Medizinische Bildverarbeitung SS 17— MT-B 6 Es öffnet sich ein Fenster, in dem der Python Interpreter auf Eingaben wartet. Diese werden hinter dem Prompt In [x]: eingetippt und mit der Eingabetaste abgeschlossen. Python 3.5.1 |Anaconda 4.0.0 (64-bit)| (default, Feb 16 2016, 09:49:46) [MSC v.1900 64 bit (AMD64)] Type "copyright", "credits" or "license" for more information. IPython 4.1.2 – An enhanced Interactive Python. ? -> Introduction and overview of IPython’s features. %quickref -> Quick reference. help -> Python’s own help system. object? -> Details about ’object’, use ’object??’ for extra details. In [1]: Die IPython Umgebung kann man verlassen mittels In [1]: exit Ok, jetzt wieder die IPython Umgebung neu starten. Oder in Spyder im Menu Consoles eine neue IPython-Konsole öffnen. Und dann spielen wir einige einfache Berechnungen durch: In [1]: 1+1 Out[1]: 2 In [2]: -42+27 Out[2]: -15 Python antwortet mit einer Ausgabe hinter dem Out[x]: Prompt und fordert zu neuen Eingaben auf. In [3]: 1./2. Out[3]: 0.5 Will man ‚schwierige‘ Mathematik rechnen, so benötigt man die üblichen mathematischen Funktionen und Konstanten. Diese stellt einem das Modul pylab zusammen mit Grafikfunktionen direkt zur Verfügung. Deshalb importieren wir den vollständigen Inhalt von pylab über In [4]: from pylab import * Dies ist zwar kein guter Python-Stil, aber für unsere Zwecke recht nützlich. Alternativ könnte man auch import numpy as np import matplotlib.pyplot as plt verwenden und den entsprechenden Befehlen ein np. bzw. plt. voranstellen. ImageTutorial 1 2 prof. dr. richard rascher-friesenhausen Hochschule Bremerhaven Medizinische Bildverarbeitung SS 17— MT-B 6 An mathematischen Funktionen stehen zur Verfügung: ’acos’, ’asin’, ’atan’, ’atan2’, ’ceil’, ’cos’, ’cosh’, ’degrees’, ’e’, ’exp’, ’fabs’, ’floor’, ’fmod’, ’frexp’, ’hypot’, ’ldexp’, ’log’, ’log10’, ’modf’, ’pi’, ’pow’, ’radians’, ’sin’, ’sinh’, ’sqrt’, ’tan’, ’tanh’ Man kann bspw. jetzt Wurzeln ziehen oder trigonometrische Funktionen aufrufen: In [5]: sqrt(4.) Out[5]: 2.0 In [6]: 2.0**2 Out[6]: 4.0 Oben bedeutet ** das Potenzieren. In [7]: for x in [0., pi/6., pi/4., pi/3., pi/2., pi]: print(x, cos(x), sin(x)) 0 1.0 0.0 0.523598775598 0.866025403784 0.5 0.785398163397 0.707106781187 0.707106781187 1.0471975512 0.5 0.866025403784 1.57079632679 6.12303176911e-017 1.0 3.14159265359 -1.0 1.22460635382e-016 Oben haben wir schon ein Beispiel für eine Python-Kontrollstruktur, nämlich die for Schleife. Darüber hinaus wird auch mit einer Variablen gearbeitet, x. Mit pylab und den eingebauten Vektorfunktionen würde man obige Schleife auch vermeiden können, nämlich über x = array([0., pi/6., pi/4., pi/3., pi/2., pi]) y1 = cos(x) y2 = sin(x) Die Funktionen werden elementweise auf den Vektor x angewendet. Man kann Variablen anlegen durch Vergabe eines Namens und Zuweisung eines Wertes. Etwa In [8]: x = 42 In [9]: x Out[9]: 42 In [10]: y = 0.815 In [11]: y Out[11]: 0.81499999999999995 ImageTutorial 1 3 prof. dr. richard rascher-friesenhausen Hochschule Bremerhaven Medizinische Bildverarbeitung SS 17— MT-B 6 In [12]: s = ’Hallo’ In [13]: s Out[13]: ’Hallo’ Hier wurde den Variablen x, y und s eine ganze Zahl, ein Dezimalzahl und ein String zugewiesen und wieder abgefragt. Man kann insbesondere auch erkennen, dass manche Zahlen im Binärsystem mit eingeschränkter Stellenzahl nicht exakt darstellbar sind. Neben diesen einfachen Datentypen benötigen wir in Python noch sehr häufig den Typ der Liste, bei dem die Elemente in eckigen Klammern eingefasst werden. Sollten in Liste nur Zahlen vorkommen, auf denen später gerechnet wird, dann verwendet man array. In [14]: l = [x, y, s] In [15]: l[0] Out[15]: 42 In [16]: l[1] Out[16]: 0.81499999999999995 In [17]: l[2] Out[17]: ’Hallo’ Es ist möglich, eigene Funktionen in Python zu definieren. Machen wir das mal vor für eine Quadratfunktion: In [18]: def quadrat(x): ...: return x*x ...: In [19]: quadrat(4) Out[19]: 16 In [20]: y = quadrat(-1.2) In [21]: y Out[21]: 1.4399999999999999 In [22]: quadrat(’hi’) –––––––––––––––––––––––––––––––––––– exceptions.TypeError ..... TypeError: can’t multiply sequence by non-int ImageTutorial 1 4 prof. dr. richard rascher-friesenhausen Hochschule Bremerhaven Medizinische Bildverarbeitung SS 17— MT-B 6 Oben steht die Definition der Funktion quadrat und einige Aufrufe dieser Funktion. Ein Aufruf mit einem String geht schief! 2 Python Programdateien Sobald man also jetzt ans Programmieren kommt, ist es sinnvoll, die Python-Befehle in eine eigene Datei abzulegen. Verwenden Sie den Editor von Spyder, um die folgenden Befehlszeilen einzugeben. (Aber jeder andere ASCII-Editor tut es auch.) 1 def quadrat(x): 2 return x*x 4 x = 12.0 5 y = quadrat(x) 6 z = quadrat(y) 8 print x, y, z eins.py Speichern Sie den Inhalt in einer Datei eins.py in Ihrem Heimatverzeichnis (bspw. unter dem Verzeichnis c:~\mbv oder auf dem Desktop). Sie können nun dieses Skript ablaufen lassen, indem Sie mit In [23]: cd ~ in Ihr Heimatverzeichnis wechseln und dann mit In [24]: run eins.py das Skript starten. Wenn keine Fehler mehr vorhanden sind, bekommen Sie den Ausdruck 12.0 144.0 20736.0 In Spyder können Sie aus dem Editor heraus mit F5 ebenfalls das Skript starten. 3 Das SimpleITK Modul In Python gibt es verschiedene Bibliotheken, die auf Bildern arbeiten PIL, scikit-image, openCV, . . . Für die medizinische Bildverarbeitung existiert mit ITK (Insight Segmentation and Registration Toolkit) eine große Sammlung von Algorithmen, die nativ in C++ codiert sind. Viele Teile davon sind auch für Python verfügbar und können mit dem Modul itk in ein Pythonprogramm importiert werden. Als einfacheres Interface zu ITK wurde für Python das Modul SimpleITK geschrieben, welches wir im Weiteren verwenden werden. ImageTutorial 1 5 prof. dr. richard rascher-friesenhausen Hochschule Bremerhaven Medizinische Bildverarbeitung SS 17— MT-B 6 SimpleITK ist nicht in der Anaconda-Distribution von Python enthalten und muß nachinstalliert werden (siehe erste Seite). SimpleITK kann 2D- und 3D-Bilder pixelweise bearbeiten und bietet eine große Menge ausgefeilter Algorithmen der medizinischen Bildverarbeitung an. Es fehlt leider eine eingebaute Darstellungsmöglichkeit für die Bilder. Stattdessen wird das externe Programm ImageJ oder Fiji dafür verwendet (siehe erste Seite). Jedes Pythonprogramm, welches die SimpleITK-Objekte nutzen will, muss das Modul importieren über import SimpleITK as sitk Ein in einer Datei existierendes Bild kann in Python eingelesen werden über den Befehl img = sitk.ReadImage(’clown.png’) Dazu muss natürlich die Datei clown.png im aktuellen Arbeitsverzeichnis liegen. Man kann nun das Bild (ein Objekt der Klasse sitk.Image) nach einigen seiner Eigenschaften befragen, etwa die Dimension print("Dimension:", img.GetDimension()) Dimension: 2 Es handelt sich also um ein 2D-Bild mit einer Breite und einer Höhe: print("Width, Height:", img.GetWidth(), img.GetHeight()) Width, Height: 320 200 Wir haben es mit einem Bild mit 320 Spalten und 200 Zeilen zu tun. Die Spalten- und Zeilenzählung beginnt bei 0! Eine ähnliche Ausgabe hätten wir auch mit dem Befehl print("Size:", img.GetSize()) Size: (320, 200) erhalten. Wir werden nun die ganze Spalte x = 42 des Bildes auf Weiß, also 255, setzen. Das Bild wird koordinatenweise angesprochen, wobei die erste Koordinate, die x Koordinate, für die Spalten steht und zweite Koordinate, die y Koordinate, für die Zeile. Der Programmcode dazu verläuft nun wie folgt x = 42 for y in range(img.GetHeight()): img[x,y] = 255 Und danach kann man sich das neue Bild anschauen vermittels sitk.Show(img) Es öffnet sich ein ImageJ-Fenster, in dem unser Bild dargestellt wird. ImageTutorial 1 6 prof. dr. richard rascher-friesenhausen Hochschule Bremerhaven Medizinische Bildverarbeitung SS 17— MT-B 6 Den Wert in einem Pixel erhalten wir über print("img[10,23]=", img[10,23]) Damit ist es also möglich, existierende Bilder zu lesen, zu manipulieren und anzuschauen. Wir können das Bild für spätere Analysen auch speichern: sitk.WriteImage(img, ’myclown.png’) Auf der Festplatte sollte sich jetzt im aktuellen Verzeichnis eine neue Datei myclown.png befinden, in der das von uns veränderte Bild gespeichert ist. Man kann auch eigene Bilder neu erzeugen. Ein schwarzes Bild mit gegebener Breite w und Höhe h und dem Datentyp unsigned integer 8 bit (passt zu Grauwerten von 0 bis 255) kann wie folgt angelegt werden w, h = 100, 80 Img = sitk.Image(w, h, sitk.sitkUInt8) Und nun kann man über eine Doppelschleife über alle Pixel die Grauwerte setzen, die man haben möchte import random for x in range(Img.GetWidth()): for y in range(Img.GetHeight()): Img[x,y] = random.randint(0, 255) sitk.WriteImage(Img, ’random.png’) Ok, das soll für die ersten Schritte mit SimpleITK erst einmal reichen. ImageTutorial 1 7 prof. dr. richard rascher-friesenhausen Hochschule Bremerhaven Medizinische Bildverarbeitung SS 17— MT-B 6 Einladen des Moduls SimpleITK import SimpleITK as sitk Erzeugen eines sitk.Image Objektes aus einer Bilddatei: img = sitk.ReadImage(dateiname) dateiname: Name einer existierenden Bilddatei, String Erzeugen eines sitk.Image-Objektes mit gegebener Dimension: img = sitk.Image(breite, hoehe, sitk.sitkUInt8) breite: Anzahl der Spalten des Bildes, Integer größer Null hoehe: Anzahl der Zeilen des Bildes, Integer größer Null Erzeugen einer Kopie eines schon angelegten Bildobjektes: img = sitk.Image(bild) bild: Bildobjekt der Klasse sitk.Image Anzeigen eines Bildobjektes: sitk.Show(img) Speichern eines Bildeobjektes: sitk.WriteImage(img, dateiname) dateiname: Name der neuen Bilddatei, String Auslesen der Breite eines Bildobjektes: breite = img.GetWidth() Auslesen der Höhe eines Bildobjektes: hoehe = img.GetHeight() Auslesen eine Pixels eines Bildobjektes: g = img[x,y] x: Spaltenindex des Pixels, Integer y: Zeilenindex des Pixels, Integer g: Grauwert des Pixels, Integer Setzen eines Pixels eines Bildobjektes: img[x,y] = g x: Spaltenindex des Pixels, Integer y: Zeilenindex des Pixels, Integer g: Grauwert des Pixels, Integer Für weitere Informationen zu den Methoden eines sitk.Image-Objektes siehe http://www.itk.org/SimpleITKDoxygen/html/classitk_1_1simple_1_1Image.html. ImageTutorial 1 8 prof. dr. richard rascher-friesenhausen