11.07.2015 Aufrufe

Praktikum Medizinische Bildverarbeitung in C# ... - Bernd Radig

Praktikum Medizinische Bildverarbeitung in C# ... - Bernd Radig

Praktikum Medizinische Bildverarbeitung in C# ... - Bernd Radig

MEHR ANZEIGEN
WENIGER ANZEIGEN

Erfolgreiche ePaper selbst erstellen

Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.

<strong>Praktikum</strong> <strong>Mediz<strong>in</strong>ische</strong> <strong>Bildverarbeitung</strong> <strong>in</strong> <strong>C#</strong>:„Volume-Render<strong>in</strong>g“Technische Universität München / Lehrstuhl Informatik IX WS 05/06Dr. Michael Roth Prof. Dr. <strong>Bernd</strong> <strong>Radig</strong>Aufgabe 7Blatt 2In Aufgabe 6 haben wir unser Programm um die Darstellung e<strong>in</strong>er Bitmap erweitert,deren Name momentan „hardcodiert“, d.h. im Programm zur Kompilierzeit festgelegt ist. Indieser Aufgabe wird dieser Makel nun behoben, <strong>in</strong>dem die Auswahl des Bildes durch denAnwender des Programms über die graphische Bedienoberfläche geschehen soll.Erweitern Sie Ihre VolumeRender<strong>in</strong>g-Klasse um e<strong>in</strong>e private Methode BuildMenu(),die verantwortlich für den Aufbau der Menüzeile des Programms ist. Das Menübesteht aus den zwei Unterpunkten „Load Image“ und „Quit“, die sich im Hauptmenüunter „File“ bef<strong>in</strong>den.Wenn der Anwender e<strong>in</strong>en Menüpunkt auswählt, sollen entsprechend die MethodenOnLoadImage() oder OnQuit() der Klasse VolumeRender<strong>in</strong>g aufgerufen werden.Letztere Methode beendet das Programm, während OnLoadImage() dem Benutzerüber e<strong>in</strong>en File-Dialog die Auswahl e<strong>in</strong>es neuen Bildes ermöglicht.Der File-Dialog wird von der Klasse OpenFileDialog aus dem NamensraumSystem.W<strong>in</strong>dows.Forms bereitgestellt.Nach dem Laden sollten Sie über e<strong>in</strong>e geeignete Methode der Klasse Form e<strong>in</strong>Neuzeichnen des Fensters auslösen, damit das neue Bild auch dargestellt wird.Da der Benutzer nun <strong>in</strong> der Lage ist, e<strong>in</strong> eigenes Bild zu laden, sollte die Bitmap zumProgrammstart auf null gesetzt werden, (d.h. es wird ke<strong>in</strong> Bild referenziert). Ume<strong>in</strong>en Fehler zu vermeiden, darf <strong>in</strong> OnPa<strong>in</strong>t() natürlich nur dann das Bild dargestelltwerden, wenn auch e<strong>in</strong>es vorhanden ist.Welche Klassen werden für den Aufbau e<strong>in</strong>es Menüs benötigt?Die relevanten Klassen des .NET-Frameworks für diese Aufgabe lauten Ma<strong>in</strong>Menu und MenuItemaus dem Namespace System.W<strong>in</strong>dows.Forms. Ma<strong>in</strong>Menu stellt dabei die Menüzeile dar, welche amoberen Rand e<strong>in</strong>es Form-Applikationsfenster dargestellt wird. MenuItems s<strong>in</strong>d die Unterpunkte, die<strong>in</strong> das Menü e<strong>in</strong>gehängt werden können. E<strong>in</strong> MenuItem selbst kann wiederum e<strong>in</strong> oder mehrereMenuItems enthalten, so dass rekursiv e<strong>in</strong> Menübaum aufgebaut werden kann.Die Dokumentation des .NET-Frameworks enthält Beispielcode, der zeigt wie mit Hilfe dieserKlassen e<strong>in</strong> Menü erstellt werden kann.Seite 1 von 4


Wie kann man e<strong>in</strong>en Menüpunkt mit dem Aufruf e<strong>in</strong>er Methode verb<strong>in</strong>den?Die aufzurufende Methode muss zunächst e<strong>in</strong>e ganz spezielle Form besitzen, sonst kann sie nicht als„Eventhandler“ für e<strong>in</strong>en Menüpunkt verwendet werden, z.B.:protected void OnQuit( object sender, EventArgs args ){this.Close();}Die Parameterliste folgt der Konvention des .NET-Frameworks für Eventhandler, die Bedeutung derParameter ist für dies Aufgabe jedoch nicht wichtig, so dass wir sie ignorieren können.Derartige Methoden kann man nun bei der Erzeugung e<strong>in</strong>es Menüpunkts als zusätzlichen Parameterverwenden, z.B.:quit = new MenuItem( "Quit" , new EventHandler( OnQuit ) );Dabei wird e<strong>in</strong> neuer Event-Handler erzeugt, der e<strong>in</strong>e Referenz auf e<strong>in</strong>e Methode besitzt, die späterbeim E<strong>in</strong>treten des entsprechende Ereignisses aufgerufen wird.Aufgabe 8Nicht immer erfolgt das E<strong>in</strong>lesen e<strong>in</strong>es Bildes so gutartig wie <strong>in</strong> Ihren ersten Tests <strong>in</strong>Aufgabe 7. Probieren Sie e<strong>in</strong>mal das Bild „corrupt.jpg“ e<strong>in</strong>zulesen, das Sie auf denWWW-Seiten des <strong>Praktikum</strong>swww9.<strong>in</strong>.tum.de/praktika/praktCSharpMedBV.WS05/f<strong>in</strong>den.Versuchen Sie herauszuf<strong>in</strong>den, was die Fehlermeldungen bedeuten, die Ihr Programmbei diesem Test ausgibt und verh<strong>in</strong>dern Sie das abrupte Beenden Ihres Programms imFehlerfall!Wie fängt man Exceptions (Ausnahmen) <strong>in</strong> <strong>C#</strong>?Eigentlich ganz analog zu JAVA oder C++, durch try-catch-(f<strong>in</strong>ally)-Blöcke:try{}catch( IOException e ){


Aufgabe 9<strong>Mediz<strong>in</strong>ische</strong> Bilddaten werden <strong>in</strong> der Regel nicht im BMP- oder JPEG-Formatgespeichert, weil diese zusätzliche Informationen wie „Name des Patienten“, „Datum derAufnahme“ ... enthalten können, die von den e<strong>in</strong>fachen Bildformaten nicht unterstützt werden.Es existieren deshalb eigene Formate, von denen DICOM-3 (Digital Imag<strong>in</strong>g andCOmmunications <strong>in</strong> Medic<strong>in</strong>e <strong>in</strong> der dritten Version des Formats) der Standard ist.Auf den WWW-Seiten www9.<strong>in</strong>.tum.de/praktika/praktCSharpMedBV.WS05/ f<strong>in</strong>denSie den Quellcode zu e<strong>in</strong>er Klasse DicomStream, welche die Funktionalität zumLesen von Bilddaten aus DICOM-Dateien bereitstellt, sowie e<strong>in</strong>ige Testbilder imDICOM-Format.Fügen Sie DicomStream zu Ihrem Projekt h<strong>in</strong>zu und nützen Sie die bereitgestellteFunktionalität zum Aufbau e<strong>in</strong>er Bitmap aus den Bilddaten e<strong>in</strong>er DICOM-Datei, stattder Erzeugung aus e<strong>in</strong>er JPEG-Datei.Die Dokumentation des Quellcodes von DicomStream zeigt Ihnen, wie es geht.Wie kann man e<strong>in</strong>en Pixel <strong>in</strong> der Bitmap mit e<strong>in</strong>em Grauwert setzen?Mit der Methode SetPixel() der Klasse Bitmap können Sie e<strong>in</strong>zelnen Pixeln Ihrer Bitmap e<strong>in</strong>e Farbeals Objekt der Klasse Color zuweisen. Color verwendet die übliche RGB-Darstellung von Farben,bei der Rot-, Grün und Blauanteile der Farben durch jeweils e<strong>in</strong> Byte gespeichert werden.Mit Hilfe der Methode Color.FromARGB(red,green,blue) können Sie e<strong>in</strong>e Farbe aus RGB-Wertenerzeugen. Wenn alle drei Farbanteile gleich s<strong>in</strong>d, entsteht e<strong>in</strong>e Graustufe.FromArgb() ist dabei e<strong>in</strong>e statische Methode der Klasse Color, man braucht deshalb ke<strong>in</strong> Objektdafür. Es reicht die Angabe der Klasse, damit der Compiler auch die richtige Methode f<strong>in</strong>det:Color me<strong>in</strong>eFarbe = Color.FromArgb(i,i,i);Aufgabe 10Die Verwendung der Klasse Bitmap als Bildklasse ist ungünstig, weil wir im Verlauf des<strong>Praktikum</strong>s Bilder mit weiteren Informationen, wie z.B. der Bildauflösung speichern wollen.Daneben benötigen wir auch e<strong>in</strong>en schnelleren Zugang zu den Bilddaten als er überSetPixel() oder GetPixel() möglich wäre.In dieser Aufgabe wird deshalb e<strong>in</strong>e eigene Klasse für Bilder entwickelt, welche diebisher verwendete Bitmap-Klasse <strong>in</strong>nerhalb des <strong>Praktikum</strong>-Programms ersetzen wird.Fügen Sie Ihrem Projekt e<strong>in</strong>e neue Klasse DicomImage h<strong>in</strong>zu, die folgendeFunktionalität bereitstellt:• Das Bild wird als zweidimensionales Array mit Elementen vom Typ bytegespeichert. byte[,] data; ist z.B. e<strong>in</strong> derartiges Array.• Die Größe des Bildes kann über die Properties Width und Height ermitteltwerden.• Es gibt e<strong>in</strong>en Konstruktor DicomImage(str<strong>in</strong>g filename), der unterVerwendung der Klasse DicomStream e<strong>in</strong> DICOM-Bild aus e<strong>in</strong>er Dateiausliest.• Wir benötigen zusätzlich e<strong>in</strong>e weitere Methode Bitmap GetBitmap(), die dasBild als e<strong>in</strong>e Bitmap zurückliefert, die wir dann wieder mit Hilfe derMethoden des .NET-Frameworks darstellen können.Seite 3 von 4


Verwenden Sie nun den Konstruktor der Klasse DicomImage und GetBitmap()zur Erzeugung der Bitmap für die Darstellung <strong>in</strong> VolumeRender<strong>in</strong>g undentfernen Sie den bisher dafür verantwortlichen Code.Wie kann man das Array erzeugen?Um das Array für die Bilddaten byte[,] data verwenden zu können, muss es erst mit Hilfe der new-Anweisung erzeugt werden. Dies geschieht ähnlich zu der Erzeugung normaler Arrays:data = new byte[ , ] ;Was s<strong>in</strong>d Properties und wie kann man eigene Properties def<strong>in</strong>ieren?Properties stellen im wesentlichen e<strong>in</strong>e elegantere Schreibweise für den Zugriff auf die Attributee<strong>in</strong>es Objekts dar, s<strong>in</strong>d also e<strong>in</strong> Ersatz für die set- und get-Methoden,die Sie vielleicht von der Java-Programmierung gewohnt s<strong>in</strong>d (Stichwort: Datenkapselung).E<strong>in</strong>e Property wird def<strong>in</strong>iert durch: {get { return ; }}set { = value ; } // value ist e<strong>in</strong> <strong>C#</strong>-Schlüsselwort!oder etwas konkreter <strong>in</strong> e<strong>in</strong>em Beispiel:// Variable für die <strong>in</strong>terne Speicherung der Breite...private <strong>in</strong>t width ;//… und die zugehörige Propertypublic <strong>in</strong>t Width{get { return width ; }set { width = value ; }}Zugriffe auf Width werden dann automatisch auf den get- oder den set-Block abgebildet:obj.Width = 5 ;<strong>in</strong>t andereVar = obj.Width ;// Führt set mit value = 5 aus// holt sich den Wert über get aus dem ObjektMacht es S<strong>in</strong>n, dass der Anwender die Properties Width und Height der KlasseDicomImage verändern kann?Ne<strong>in</strong>, denn Width und Height s<strong>in</strong>d nur dazu gedacht, die Größe des Bildes zu ermitteln. DieseProperties sollten deshalb als schreibgeschützt def<strong>in</strong>iert werden. Dies geschieht, <strong>in</strong>dem man e<strong>in</strong>fachden set{...}-Fall der Property weglässt.Aufgabe 11Sowohl mit byte[,] array1; als auch mit byte[][] array2; lassen sich <strong>in</strong> <strong>C#</strong>zweidimensionale Arrays def<strong>in</strong>ieren.Was ist der Unterschied zwischen diesen beiden Varianten?Seite 4 von 4

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!