SommerAkademie 2011 Mathematik für die Medizin Eine sehr kurze Einführung in Python und MyImage richard rascher-friesenhausen [email protected] Dies ist eine sehr, sehr kurze Einführung zu Python und den Möglichkeiten, vermittels des Moduls MyImage zweidimensionale Grauwertbilder 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.pythonxy.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 Python-Tutorial (auf englisch): http://docs.python.org/tutorial/ Und auf deutsch findet man eine ältere Version unter http://starship.python.net/crew/gherman/publications/tut-de/tut-de-21.pdf Wir verwenden im weiteren die Python-Entwicklungsumgebung ‚IDLE‘. Daneben gibt es auch noch die alternativen Entwicklungsumgebungen ‚Spyder‘ und ‚Eclipse‘. 1 Erste Python Schritte Aufgabe Ruft ‚IDLE‘ über das Windows-Startmenu auf. Sucht dazu den Eintrag PythonXY in der Startleiste und wählt darin den Eintrag ‚IDLE‘ aus. Es öffnet sich das Fenster der Python-Shell in dem der Python Interpreter auf Eingaben wartet. Diese werden hinter dem Prompt >>> eingetippt und mit der Eingabetaste abgeschlossen. Danach wertet Python die Eingabe aus und liefert das zugehörige Ergebnis auf die Konsole zurück. Arbeitszettel 1 1 prof. dr. richard rascher-friesenhausen SommerAkademie 2011 Mathematik für die Medizin Wir spielen jetzt einige einfache Berechnungen durch: >>> 1 + 1 2 >>> -42 + 27 -15 >>> Python antwortet mit einer Ausgabe des Rechenergebnisses auf einer neuen Zeile und fordert zu neuen Eingaben auf. Bisher haben wir mit ganzen Zahlen gerechnet. Und haben dabei auch stets ein ganzahliges Ergebniss erhalten. Hier muss man bei der Division vorsichtig sein: >>> 1/2 0 Es wird auch ganzzahlig dividiert! Will man mit Dezimalzahlen arbeiten, so muss man das Python explizit sagen und den Zahlen einen Dezimalpunkt spendieren: >>> 1./2. 0.5 Will man ‚schwierige‘ Mathematik rechnen, so benötigt man die üblichen mathematischen Funktionen und Konstanten. Diese sind nicht direkt eingebaut sondern müssen ‚nachgeladen‘ werden. Das Modul math stellt einem folgende Funktionen und Konstanten zur Verfügung: ’acos’, ’acosh’, ’asin’, ’asinh’, ’atan’, ’atan2’, ’atanh’, ’ceil’, ’copysign’, ’cos’, ’cosh’, ’degrees’, ’e’, ’exp’, ’fabs’, ’factorial’, ’floor’, ’fmod’, ’frexp’, ’fsum’, ’hypot’, ’isinf’, ’isnan’, ’ldexp’, ’log’, ’log10’, ’log1p’, ’modf’, ’pi’, ’pow’, ’radians’, ’sin’, ’sinh’, ’sqrt’, ’tan’, ’tanh’, ’trunc’ Diese werden alle nachgeladen über >>> from math import * Man kann bspw. jetzt Wurzeln ziehen: >>> sqrt(4.) 2.0 >>> 2.0**2 4.0 Oben bedeutet ** das Potenzieren. Aufgabe Arbeitszettel 1 Wie kann man mit der **-Schreibweise auch die Wurzel ziehen? 2 prof. dr. richard rascher-friesenhausen SommerAkademie 2011 Mathematik für die Medizin Mit der Funktion help kann man Python befragen, was eine Funktion bedeutet, etwa >>> help(sqrt) Help on built-in function sqrt in module math: sqrt(...) sqrt(x) Return the square root of x. Aufgabe Bekommt heraus, was die Funktion pow berechnet und wie. Eine formatierte Tabelle einiger trigonometrischer Funktionen bekommen wir über >>> for x in [0.,pi/6.,pi/4.,pi/3.,pi/2.,pi]: print "%f, %+f, %f" % (x, cos(x), sin(x)) 0.000000, 0.523599, 0.785398, 1.047198, 1.570796, 3.141593, +1.000000, +0.866025, +0.707107, +0.500000, +0.000000, -1.000000, 0.000000 0.500000 0.707107 0.866025 1.000000 0.000000 Beachtet die Einrückung des print Befehls. Wir haben hier ein Beispiel für eine PythonKontrollstruktur, nämlich die for Schleife. Darüberhinaus wird auch mit einer Variablen x gearbeitet. Man kann Variablen anlegen durch Vergabe eines Namens und Zuweisung eines Wertes. Etwa >>> x = 42 >>> print x 42 >>> y = 0.815 >>> print y 0.815 >>> s = "Hallo" >>> print s Hallo Hier wurde den Variablen x, y und s eine ganze Zahl, ein Dezimalzahl und ein String zugewiesen und wieder abgefragt. Neben diesen einfachen Datentypen benötigen wir in Python noch sehr häufig den Typ der Liste: Arbeitszettel 1 3 prof. dr. richard rascher-friesenhausen SommerAkademie 2011 Mathematik für die Medizin >>> L = [x, y, s] >>> print L [42, 0.81499999999999995, ’Hallo’] >>> Hier kann man erkennen, dass das Binärsystem eines Computer nicht alle Dezimalzahlen exakt darstellen kann. An einzelne Listenelemente kommt man über einen Index, der bei Null beginnt. >>> print L[0] 42 >>> print L[1] 0.815 >>> L[1] = 47.11 >>> print L[1] 47.11 >>> print L[2] Hallo Es ist möglich, eigene Funktionen in Python zu definieren. Machen wir das mal vor für eine Quadratfunktion: >>> def quadrat(x): return x*x >>> print quadrat(4) 16 >>> y = quadrat(-1.2) >>> print y 1.44 Oben steht die Definiton der Funktion quadrat und einige Aufrufe dieser Funktion. Ein Aufruf mit einem String geht schief! >>> print quadrat(’hi’) Traceback (most recent call last): File "<pyshell#35>", line 1, in <module> print quadrat(’hi’) File "<pyshell#31>", line 2, in quadrat return x*x TypeError: can’t multiply sequence by non-int of type ’str’ Aufgabe Lest das Tutorial zu Python von der Python-Dokumentations-Webseite http://docs.python.org/ und arbeitet es einmal bis Abschnitt 8 durch. Arbeitszettel 1 4 prof. dr. richard rascher-friesenhausen SommerAkademie 2011 Mathematik für die Medizin 2 Python Programdateien Sobald man also jetzt ans Programmieren kommt, ist es sinnvoll, die Python-Befehle in eine eigene Datei abzulegen. Öffnet dazu in der IDLE ds Menu ‚File‘ und wählt ‚New Window‘ aus. Es öffnet sich ein neues Fenster, dsa einem jetzt als ASCII-Editor dient. Gebt darin jetzt die folgenden Zeilen Python-Code ein (ohne Zeilennummerierung) 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 Speichert den Inhalt in einer Datei eins.py in Eurem Heimatverzeichnis in einem Unterverzeichnis python. (Bspw. C:\Users\richard\Documents\Python) Da kommen dann auch alle weiteren Python-Programme hinein. Wir können nun dieses Skript ablaufen lassen, indem wir in dem Menu ‚Run‘ und Run Module auswählen, oder die Taste F5 drücken. Die Ergebnisse werden im dem Fenster der Python Shell ausgegeben. Sollten noch Syntaxfehler in dem Programm stecken, so werden diese ebenfalls (in Rot) im dem Fenster der Python Shell ausgegeben. Arbeitszettel 1 5 prof. dr. richard rascher-friesenhausen SommerAkademie 2011 Mathematik für die Medizin Aufgabe Schreibt eine Funktion c2f(), die eine Temperatur in Celsius umrechnet nach Fahrenheit und eine Funktion f2c(), die umgekehrt eine Temperatur in Fahrenheit umrechnet nach Celsius. Testet beide Funktionen aus. 3 Das MyImage Modul In Python gibt es verschiedene Bibliotheken, die auf Bildern arbeiten. Da ist zum einen das Image Modul, das eine ausgereifte Sammlung von Objekten zur Manipulation von 2D-Bildern zur Verfügung stellt. Für die medizinische Bildverarbeitung existiert mit ITK 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. Beide angesprochenen Module sind in der Python(x,y)-Distribution enthalten bzw. können nachgeladen werden. Als eine weitere sehr einfache Alternative steht mit dem Modul MyImage ein Bilderklasse und einige sinnvolle Funktionen zur Verfügung, um pixelweise Bildverarbeitung auf 2DGrauwertbildern zu implementieren. Jedes Pythonprogramm, welches die MyImage-Objekte nutzen will, muss die Objekte importieren, also from MyImage import * In der Klasse MyImage (Vorsicht! Gleicher Name wie das Modul.) stecken nun die Bildobjekte. Ein Bild aus einer Datei, bevorzugt .png (Portable Newtork Graphic), lässt sich wie folgt einlesen img = MyImage(’clown.png’) Dazu muss natürlich die Datei clown.png im aktuellen Arbeitsverzeichnis liegen. Und dann schauen wir uns das Bild einmal an mit img.show() Es öffnet sich ein neues Fenster mit unserem Bild. Arbeitszettel 1 6 prof. dr. richard rascher-friesenhausen SommerAkademie 2011 Mathematik für die Medizin Man kann nun das Bild nach einigen seiner Eigenschaften befragen, etwa nach seiner Breite und Höhe: print img.getWidth(), img.getHeight() 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 img.getSize() (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 die zweite Koordinate, die y Koordinate, für die Zeile. Der Programmcode dazu verflä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 img.show() Damit ist es also möglich, existierende Bilder zu lesen, zu manipulieren, anzuschauen und auch wieder zu speichern: img.save(’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. Ein schwarzes Bild mit gegebener Breite w und Höhe h kann wie folgt neu angelegt werden w, h = 100, 80 Img = MyImage(w, h, 0) Arbeitszettel 1 7 prof. dr. richard rascher-friesenhausen SommerAkademie 2011 Mathematik für die Medizin und danach pixelweise verändert werden. Beipielsweise lassen sich darauf 100 zufällige Pixelpositionen mit zufälligen Grauwerten zwischen 0 (schwarz) und 255 (weiß) belegen. Der Zufall wird durch das Modul random zur Verfügung gestellt: import random for i in range(100): x = random.randrange(0,w) y = random.randrange(0,h) g = random.randrange(0,256) Img[x,y] = g Aufgabe links. Erzeugt ein 256 × 256 Grauwertbild wie in der unten stehenden Abbildung 256 256 100 256 100 256 Die beiden Grauwerte sollen 0 (Schwarz) und 255 (Weiss) sein. Speichert das Bild unter quadrat.png ab. Wie kann man einen Kreis (mit Radius 50) wie in der Abbildung rechts erzeugen? Speichert diesen unter circle.png ab. Aufgabe Erzeugt ein 512 × 512 Bild mit vertikalen Grauwertstreifen der Stärke 50, 100, 150, 200 und jeweiliger Breite von 128 Pixel. Speichert das Bild unter dem Namen stripes1.png ab. Verändert die Grauwerte zu 20, 40, 60 und 80 und speichert unter stripes2.png ab. Arbeitszettel 1 8 prof. dr. richard rascher-friesenhausen SommerAkademie 2011 Mathematik für die Medizin Erzeugen eines Bildobjektes aus einer Bilddatei: img = MyImage(dateiname) dateiname: Name einer existierenden Bilddatei, String Erzeugen eines Bildobjektes mit konstantem Grauwert und gegebener Dimension: img = MyImage(breite, hoehe, wert) breite: Anzahl der Spalten des Bildes, Integer größer Null hoehe: Anzahl der Zeilen des Bildes, Integer größer Null wert: Konstanter Grauwert des Bildes, Integer zwischen 0 und 255 Erzeugen einer Kopie eines schon angelegten Bildobjektes: img = MyImage(bild) bild: Bildobjekt der Klasse MyImage Anzeigen eines Bildobjektes: img.show() Speichern eines Bildeobjektes: img.save(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 MyImage-Objektes siehe man direkt in der Python-Datei MyImage.py nach. Arbeitszettel 1 9 prof. dr. richard rascher-friesenhausen