VigraPLT
Referenz-Handbuch
Version 0.1.0
Benjamin Seppke
25. März 2009
Inhaltsverzeichnis
Einleitung 1
1 Voraussetzungen und Installation 2
2 Verwendete Datenstrukturen 3
2.1 Repräsentation von Bildern 3
2.2 Repräsentation von Matrizen 6
3 Laden und Speichern von Bildern 9
4 Bildverarbeitung mit VigraPLT 10
4.1 Filtern 10
4.2 Bildtransformationen 12
4.3 Morphologische Operationen 14
4.4 Segmentierung 15
4.5 Funktionale Bildverarbeitung 17
5 Anzeige von Bildern 19
6 Beispiele 20
6.1 „Hello Image“ 20
6.2 Filtern mit Gauß 21
6.3 Wasserscheiden-Segmentierung 22
Der Name VIGRA steht für "Vision with Generic Algorithms". Es handelt sich hierbei um eine, hauptsächlich von Ullrich Köthe entwickelte, neuartige C++ Bibliothek zur Bildverarbeitung, die das Hauptaugenmerk auf Generizität und Wiederverwendbarkeit der Algorithmen und Datenstrukturen legt. Dies wird mit mit Hilfe des in C++ enthaltenen Template-Mechanismus' erreicht, der bereits in der wohl bekannten C++ Standard Template Library (STL) zum Einsatz kommt. Die STL - so könnte man sagen - stand Pate für diese Bibliothek.
Dies alles führt schlussendlich dazu, dass sich VIGRA-Komponenten einfach an die eigenen Bedürfnisse anpassen lassen, ohne dabei auf die hohe Geschwindigkeit von C++ verzichten zu müssen. Um noch mehr zu erfahren, bietet sich ein Besuch der VIGRA Homepage an!
Die VIGRA ist eine reine C++ Bibliothek. Dies hat sicherlich einige sehr positive Aspekte, wie z.B. die Geschwindigkeit der Algorithmen, die hervorragende Ausnutzung der Template-Mechanismen und des objektorientierten Programmierstils, der die VIGRA recht verständlich macht.
Dennoch gibt es auch Gründe, die gegen eine Wahl der Sprache C++ sprechen, wie z.B. die fehlende Interaktivität durch die nötigen Code-Compile-Zyklen oder die mäßige Unterstützung von anderen Paradigmen außer dem imperativen und dem OO-Modell. Zudem ist C++ nicht gerade als High-Level-Sprache berühmt, weshalb nach wie vor viele höhere Wissenskonzepte in anderen Sprachen beschrieben werden.
Kurz und knapp zusammengefasst ergibt sich, dass alleine schon der erste Punkt (die fehlende Interaktivität) die Anbindung an eine andere Sprache rechtfertigen kann. Daher wird auch zurzeit an einer verbesserten Python-Schnittstelle der VIGRA gearbeitet.
Da es mit Scheme seit der Version 4.0 recht leicht möglich ist, sogenannten "Foreign-Code", also Code der nicht mit Scheme selbst geschrieben wurde, zu laden, wird diese Schnittstelle (das Foreign-Funktion-Interface: FFI) im Rahmen der VigraPLT ausgenutzt. Sie ermöglicht es, C-konforme Shared Libraries (unter Windows: DLLs, unter MacOSX: dylibs und unter Linux: so) dynamisch und zur Laufzeit an Scheme zu binden, so dass die darin enthaltenen Funktionen benutzt werden können.
Da die VIGRA allerdings nur für den Import- bzw. Export von Bildern eine Shared Library anbietet, musste als erste Zwischenstufe ein C-Wrapper für die VIGRA-Funktionen geschrieben werden (VIGRA_C), die innerhalb der Scheme Umgebung zur Verfügung stehen sollen. An diese dynamische C-Bibliothek werden dann die entsprechenden Scheme Funktionen gebunden, die den Aufruf der eigentlichen C-Routinen vor dem Benutzer verstecken.
Zusammengefasst müssen also folgende Schritte durchgeführt werden, um die VigraPLT zu installieren:
Herunterladen und Entpacken von VigraPLT (inkl. VIGRA_C)
VIGRA_C kompilieren
Die dynamische Bibliothek der VIGRA_C in das Verzeichnis von VigraPLT ablegen
VigraPLT in das „collects“ Verzeichnis von PLT Scheme linken
Unter MacOS X oder Linux z.B. mit
> ln -s
/Path/to/vigraplt
/path/to/scheme/collects/vigraplt
Getestet werden kann die erfolgreiche Installation z.B. mit einem Durchlauf der „examples.ss“ Datei, die im VigraPLT Verzeichnis liegt.
Durch die Anbindung der Datenstrukturen an die C-Schnittstelle, sollte möglichst wenig Overhead entstehen. So sollte ein Bild auch nur ein Mal im Speicher vorhanden sein, und nicht etwa doppelt, um es an die C-Schnittstelle in einer geeigneten Form (kopiert) weiterzugeben. Daher werden in diesem Kapitel die neuen Datenstrukturen beschrieben, die mit der VigraPLT in Scheme eingeführt werden.
Die Repräsentation eines Bildes in dieser Erweiterung beruht intern auf einem „cvector“ vom Typ „float“, da dieser eine einfache Übergabe an die C-Schnittstelle bietet. Leider ist dieser aber nur eindimensional definiert, weshalb er in der Datei „vigraplt.carray.ss“ zunächst auf n Dimensionen erweitert wurde.
Diese Erweiterung ist deshalb wichtig, weil wir ein Bild als zweidimensionalen Datentyp beschreiben möchten, der in der Lage ist, für jeden Pixel einen float (Gleitkommazahl) Wert zu speichern. Das n-dimensionale „carray“ ist für den praktischen Umgang mit Bildern unwichtig, da es spezielle Funktionen für Bilder gibt, welche sich in der Datei „vigraplt.helpers.ss“ finden:
(make-image w h . init-val) → image
Bedingungen:
w, h: Ganzzahlen
init-val: Gleitkommazahl
Beschreibung:
Erstellt ein neues Bild mit Breite w (= width), und Höhe h (= height). Falls angegeben, wird das neue Bild mit mit dem Wert init-val gefüllt.
(image-data image) → cvector
Bedingungen:
image: image
Beschreibung:
Gibt den ein-dimensionalen Vektor der Werte aller Pixel zurück.
(image-width image) → Ganzzahl
Bedingungen:
image: image
Beschreibung:
Gibt die Breite des Bildes zurück.
(image-height image) → Ganzzahl
Bedingungen:
image: mage
Beschreibung:
Gibt die Höhe des Bildes zurück.
(image-ref image x y) → Gleitkommazahl
Bedingungen:
image: image
x, y: Ganzzahlen, wobei 0 ≤ x < (image-width image)
und 0 ≤ y < (image-height image)
Beschreibung:
Gibt den Wert des Pixels des Bildes an der Stelle (x,y) zurück.
(image-set! image x y val) → void
Bedingungen:
image: image
x, y: Ganzzahlen, wobei 0 ≤ x < (image-width image)
und 0 ≤ y < (image-height image)
val: Gleitkommazahl
Beschreibung:
Setzt den Wert des Pixels des Bildes an der Stelle (x,y) auf den übergebenen Wert.
WARNUNG:
Dieses „Umbiegen“ des Bildwertes entspricht nicht dem funktionalen Paradigma und kann zu ungewollten Seiteneffekten führen!
(copy-image image) → image
Bedingungen:
image: image
Beschreibung:
Gibt eine Kopie des übergebenen Bildes zurück.
(image->list image) → list
Bedingungen:
image: image
Beschreibung:
Wandelt ein Bild in eine Liste von Zeilenlisten um und gibt diese zurück.
Beispiel:
0 1 2 '( (0 1 2)
3 4 5 (3 4 5)
6 7 8 → (6 7 8)
9 10 11 (9 10 11)
12 13 14 (12 13 14))
(list->image lst) → image
Bedingungen:
lst: Eine Liste von Listen gleicher Länge
Beschreibung:
Inverse Funktion zu image->list, die eine Liste von Listen wieder in ein image umwandelt.
Die Repräsentation für Matrizen wird zunächst nur für eine einzige Funktion der VigraPLT benötigt, nämlich die affine Transformation eines Bildes. Dennoch ist diese Erweiterung ist deshalb wichtig, um genau diese Funktion benutzbar zu machen.
Matrizen werden genauso wie Bilder repräsentiert, mit dem einzigen Unterschied, dass sie Gleitkommazahlen mit doppelter Genauigkeit als Wertebereich verwenden. Dies bietet sich an, um die Rechengenauigkeit zu erhöhen. Außerdem sind Matrizen meist deutlich „kleiner“ als Bilder, weshalb dies für diesen Fall beim Speicherverbrauch in einem akzeptablem Rahmen bleibt. Die Funktionen orientieren sich ebenfalls an denen die für Bilder zur Verfügung stehen.
(make-matrix r c . init-val) → image
Bedingungen:
r, c: Ganzzahlen
init-val: Gleitkommazahl (doppelte Genauigkeit)
Beschreibung:
Erstellt eine neue Matrix mit r Zeilen (= rows) und c Spalten (=columns). Falls angegeben, wird die neue Matrix mit dem Wert init-val gefüllt.
(matrix-data matrix) → cvector
Bedingungen:
matrix: matrix
Beschreibung:
Gibt den eindimensionalen Vektor der Werte aller Matrixelemente zurück.
(matrix-rows matrix) → Ganzzahl
Bedingungen:
matrix: matrix
Beschreibung:
Gibt die Anzahl der Zeilen der Matrix zurück.
(matrix-cols matrix) → Ganzzahl
Bedingungen:
matrix: matrix
Beschreibung:
Gibt die Anzahl der Spalten der Matrix zurück.
(matrix-ref matrix r c) → Gleitkommazahl (doppelte Genauigkeit)
Bedingungen:
matrix: matrix
r, c: Ganzzahlen, wobei 0 ≤ r < (matrix-rows matrix)
und 0 ≤ c < (matrix-cols matrix)
Beschreibung:
Gibt den Wert der Matrix in Zeile r und Spalte c zurück.
(matrix-set! matrix r c val) → void
Bedingungen:
matrix: matrix
r, c: Ganzzahlen, wobei 0 ≤ r < (matrix-rows matrix)
und 0 ≤ c < (matrix-cols matrix)
val: Gleitkommazahl
Beschreibung:
Setzt den Wert der Matrix in Zeile r und Spalte c auf den übergebenen Wert.
WARNUNG:
Dieses „Umbiegen“ des Matrixelements entspricht nicht dem funktionalen Paradigma und kann zu ungewollten Seiteneffekten führen!
(copy-matrix matrix) → matrix
Bedingungen:
matrix: matrix
Beschreibung:
Gibt eine Kopie der übergebenen Matrix zurück.
(matrix->list matrix) → list
Bedingungen:
matrix: matrix
Beschreibung:
Wandelt eine Matrix in eine Liste von Spaltenlisten um und gibt diese zurück.
(list->matrix lst) → matrix
Bedingungen:
lst: Eine Liste von Listen gleicher Länge
Beschreibung:
Wandelt eine Liste von Listen in eine Matrix um.
(matrix-mult mat1 mat2) → matrix
Bedingungen:
mat1, mat2: matrix
Beschreibung:
Führt eine Matrix-Multiplikation der beiden gegebenen Matrizen durch
Generell können mit der VigraPLT zurzeit nur Grauwertbilder eingelesen und verarbeitet werden. Sollte es nötig werden, so müssten die Farb-Funktionalitäten in einer weiteren Version hinzugefügt werden. Daher muss das zu ladende Bild auch ein Grauwertbild sein.
Die unterstützten Formate sind daran gebunden, mit welchen Einstellungen die VIGRA auf dem System kompiliert wurde. Sind alle benötigten Bibliotheken vorhanden gewesen, wovon hier ausgegangen wird, so sind folgende Formate für das Lesen und Schreiben von Bildern geeignet:
Windows BMP
GIF
JPEG
PNG, PNM
Sun Raster
TIFF (including 32bit integer, float, and double)
Khoros VIFF
HDR (high dynamic range)
Zum Einlesen und Abspeichern bietet die VigraPLT folgende Funktionen (implementiert in der Datei „vigraplt.impex.ss“):
(loadimage filename) → image
Bedingungen:
filename: String
Beschreibung:
Liest das Bild, gegeben durch den Dateinamen, ein und gibt es als image zurück. Falls das Bild nicht eingelesen werden konnte, wird eine Fehlermeldung ausgegeben. Sowohl absolute als auch relative Pfade (zur VigraPLT) sind erlaubt.
(saveimage image filename)
Bedingungen:
image: image
filename: String
Beschreibung:
Speichert das Bild auf der Festplatte ab.
WARNUNG:
Ist es bereits vorhanden, wird es ohne Vorwarnung überschrieben!
Die in diesem Abschnitt beschriebenen Funktionen sind direkt für die Bildverarbeitung anzuwenden. Die Kapitel 4.1 – 4.4 beschreiben Algorithmen die direkt mit Hilfe der VIGRA_C Funktionen und damit sehr schnell ausgeführt werden. In Abschnitt 4.5 sind Scheme-basierte Algorithmen beschrieben, die beim Implementieren eigener funktionaler Algorithmen helfen können, aber von der Geschwindigkeit nicht mit den C-Methoden mithalten können.
Die Operationen, die in diesem Kapitel zusammengefasst sind, finden sich in der Datei „vigraplt.filters.ss“
(gsmooth image sigma) → image
Bedingungen:
image: image
sigma: Gleitkommazahl
Beschreibung:
Führt eine Gaußsche Glättung des Bildes mit einer Stadardabweichung von sigma durch.
(ggradient image sigma) → image
Bedingungen:
image: image
sigma: Gleitkommazahl
Beschreibung:
Erstellt ein Gradientenbetragsbild des Bildes. Dafür wird das Bild mit einer einfach abgeleiteten Gausskurve mit einer Stadardabweichung von sigma gefaltet.
(laplacianofgaussian image scale) → image
Bedingungen:
image: image
scale: Gleitkommazahl
Beschreibung:
Führt eine Laplacian of Gaussian (LoG) Transformation des Bildes auf der Skala scale durch
(gsharpening image sharpening_factor scale) → image
Bedingungen:
image: image
sharpening_factor, scale: Gleitkommazahl
Beschreibung:
Führt eine Gaußsche Schärfung des Bildes durch
(sharpening image sharpening_factor) → image
Bedingungen:
image: image
sharpening_factor: Gleitkommazahl
Beschreibung:
Führt eine einfache Schärfung des Bildes durch
(nonlineardiffusion image edge_threshold scale) → image
Bedingungen:
image: image
edge_threshold, scale: Gleitkommazahl
Beschreibung:
Führt eine nichtlineare Filterung des Bildes aus, um z.B. nicht-additives Rauschen zu entfernen.
(distancetransform image background_label norm) → image
Bedingungen:
image: image
background_label: Gleitkommazahl
norm: Ganzzahl im Intervall [0,1,2]
Beschreibung:
Führt die Distanztransformation eines Bild durch. Mit „norm“ kann die zu verwendende Distanz-Metrik für die Transformation angegeben werden (0=Schachbrett-, 1=Manhattan- und 2=Euklidische-Distanz).
Die Operationen, die in diesem Kapitel zusammengefasst sind, finden sich in der Datei „vigraplt.imgproc.ss“
(resizeimage image new_width new_height resize_mode) → image
Bedingungen:
image: image
angle: Gleitkommazahl
resize_mode: Ganzzahl im Intervall [0,1,2,3,4]
new_width, new_height: Ganzzahlen > 0
Beschreibung:
Vergrößert ein Bild auf die angegebenen neuen Dimensionen. Dabei kann zusätzlich festgelegt werden, wie das Resampling des Bildes passieren soll:
0 = Nächster Nachbar Interpolation
1 = Bilineare Interpolation
2 = Biquadratische Interpolation
3 = Bikubische Interpolation
4 = Interpolation durch Spline der Ordnung 4.
(rotateimage image angle resize_mode) → image
Bedingungen:
image: image
angle: Gleitkommazahl
resize_mode: Ganzzahl im Intervall [0,1,2,3,4]
Beschreibung:
Dreht ein Bild um den angegebenen Winkel gegen den Uhrzeigersinn. Dabei kann zusätzlich festgelegt werden, wie das Resampling des Bildes passieren soll:
0 = Nächster Nachbar Interpolation
1 = Bilineare Interpolation
2 = Biquadratische Interpolation
3 = Bikubische Interpolation
4 = Interpolation durch Spline der Ordnung 4.
(affinewarpimage image affinematrix resize_mode) → image
Bedingungen:
image: image
affinematrix: matrix (3x3)
resize_mode: Ganzzahl im Intervall [0,1,2,3,4]
Beschreibung:
Führt eine Affine Transformation auf ein Bild aus. Dabei kann zudem festgelegt werden, wie das Resampling des Bildes passieren soll:
0 = Nächster Nachbar Interpolation
1 = Bilineare Interpolation
2 = Biquadratische Interpolation
3 = Bikubische Interpolation
4 = Interpolation durch Spline der Ordnung 4.
(reflectimage image reflect_mode) → image
Bedingungen:
image: image
reflect_mode: Ganzzahl im Intervall [1,2,3]
Beschreibung:
Reflektiert das Bild horizontal, falls reflect_mode = 1,
vertikal, falls reflect_mode = 2,
um beide Achsen, falls reflect_mode =3.
(fouriertransform image) → (real_part_image . imaginary_part_image)
Bedingungen:
image: image
Beschreibung:
Führt eine Fourier Transformation auf dem Bild aus und gibt ein „pair“ bestehend aus real- und komplexwertigen Anteil zurück.
WARNUNG:
Dies erfordert das Vorhandensein der FFTW Bibliothek auf dem System, da die schnelle Fourier Transformation dieser Bibliothek verwendet wird.
Die Operationen, die in diesem Kapitel zusammengefasst sind, finden sich in der Datei „vigraplt.morphology.ss“. Streng genommen könnte man hierunter auch die Distanztransformation zählen, allerdings ist sie aus historischen Gründen in diesem Handbuch wie auch in der VigraPLT in dem Filter-Kapitel beschrieben.
(erodeimage image radius) → image
Bedingungen:
image: image
radius: Ganzzahl
Beschreibung:
Führt die morphologische Operation der Erosion auf dem Bild aus. Dabei kann der Radius / die Stärke der Erosion mit angegeben werden.
(dilateimage image radius) → image
Bedingungen:
image: image
radius: Ganzzahl
Beschreibung:
Führt die morphologische Operation der Dilatation auf dem Bild aus. Dabei kann der Radius / die Stärke der Dilatation mit angegeben werden.
(openingimage image radius) → image
Bedingungen:
image: image
radius: Ganzzahl
Beschreibung:
Führt die morphologische Operation des Öffnens auf dem Bild aus. Dies entspricht einer Erosion gefolgt von einer Dilatation. Dabei kann der Radius / die Stärke der einzelnen Operationen mit angegeben werden.
(closingimage image radius) → image
Bedingungen:
image: image
radius: Ganzzahl
Beschreibung:
Führt die morphologische Operation des Schließens auf dem Bild aus. Dies entspricht einer Dilatation gefolgt von einer Erosion. Dabei kann der Radius / die Stärke der einzelnen Operationen mit angegeben werden.
Die Operationen, die in diesem Kapitel zusammengefasst sind, finden sich in der Datei „vigraplt.segmentation.ss“. Dazu gehören sowohl Kanten-basierte als auch Regionen-ortierte Verfahren. Ausserdem bietet die VigraPLT noch die Möglichkeiten, Regionen aus Binärbildern zu extrahieren und CrackEdge-Bilder zu erstellen.
(labelimage image) → image
Bedingungen:
image: image
Beschreibung:
Diese Funktion führt ein Labeling aus. Dazu werden 4-zusammenhängende Regionen gesucht. Diese bekommen im Ergebnisbild einen eindeutigen Wert zugewiesen.
Beispiel:
0 0 0 0 0 0 0 0
1 0 0 1 1 0 0 2
0 0 0 0 → 0 0 0 0
1 0 1 1 3 0 4 4
1 0 1 1 3 0 4 4
watersheds image) → image
Bedingungen:
image: image
Beschreibung:
Diese Funktion führt eine Wasserscheiden-Transformation auf dem Bild aus. Zurückgeliefert wird ein gelabeltes Regionen Bild, das das Ergebnis der Segmentierung darstellt.
(cannyedgeimage image scale gradient_threshold mark) → image
Bedingungen:
image: image
scale, gradient_threshold, mark: Gleitkommazahlen
Beschreibung:
Diese Funktion führt einen Canny-Kantenfinder auf geg. Skala des Bildes aus. Zurückgeliefert wird ein Bild, in dem alle Canny-Edgel mit „mark“ markiert worden sind.
(differenceofexponentialedgeimage image scale gradient_threshold mark)
→ image
Bedingungen:
image: image
scale, gradient_threshold, mark: Gleitkommazahl
Beschreibung:
Diese Funktion führt einen DoG-Kantenfinder auf geg. Skala des Bildes aus. Zurückgeliefert wird ein Bild, in dem alle gefundenen Kantenpixel mit „mark“ markiert worden sind.
(regionimagetocrackedgeimage image mark) → image
Bedingungen:
image: image
mark: Gleitkommazahl
Beschreibung:
Diese Funktion erstellt aus einem gegeben Regionenbild mit Größe (w, h) ein Bild der Größe (2*w-1, 2*h-1) in dem Kanten zwischen den Regionen explizit mit „mark“ eingezeichnet wurden.
Beispiel: 1 1 1 # 2
1 1 2 1 # # # 2
1 3 2 → 1 # 3 # 2
4 3 3 # # 3 # #
4 # 3 3 3
Die Operationen, die in diesem Kapitel zusammengefasst sind, finden sich in der Datei „vigraplt.helpers.ss“. Sie sollen den Einstieg in die funktionale Bildverarbeitung erleichtern und werden sicher in Zukunft durch zahlreiche weitere Funktionen ergänzt.
(image-map func . images) → image
Bedingungen:
func: Funktion mit Signatur: (Gleitkommazahl 1, … 2, …, n) → Gleitkommazahl
image: Liste: (image 1, … , 2 , … , n)
Beschreibung:
Diese Funktion ist analog zu dem in Scheme vorhandenen „map“ für Listen. Sie wendet eine gegebene Funktion auf den Wert jedes Pixels jedes übergebenen Bildes an und liefert das Ergebnis in einem neuen Bild zurück, ohne weitere Seitenefekte zu verursachen.
(image-map! func . images) → image
Bedingungen:
func: Funktion mit Signatur: (Gleitkommazahl 1, … 2, …, n) → Gleitkommazahl
image: Liste: (image 1, … , 2 , … , n)
Beschreibung:
Diese Funktion ist analog zu dem in Scheme vorhandenen „map!“ für Listen. Sie wendet eine gegebene Funktion auf den Wert jedes Pixels jedes übergebenen Bildes an und speichert das Ergebnis in dem ersten übergebenen Bild, also in-place!
WARNUNG:
Hierbei wird das erste übergebene Bild verändert, was zu ungewollten Seiteneffekten führen kann, und vermieden werden sollte!
(image-reduce func image seed) → image
Bedingungen:
func: Funktion mit Signatur: (Gleitkommazahl1, …2) → Gleitkommazahl
image: image
seed: Gleitkommazahl
Beschreibung:
Diese Funktion ist analog zu dem in Scheme vorhandenen „reduce“ für Listen. Sie reduziert das Bild mittels der gegebenen Funktion und eines „seed“-Wertes auf einen Wert. Dabei wird das ursprüngliche Bild nicht verändert.
(image-for-each-index func image)
Bedingungen:
func: Funktion mit Signatur: Ganzzahl, Ganzzahl → void
image: image
Beschreibung:
Diese Funktion ruft die übergebene Funktion für jede Pixelposition, die es in dem übergebenen Bild gibt, auf.
Zur Anzeige der Ergebnisbilder ist es selten sinnvoll, diese immer und immer wieder abzuspeichern und dann in einem externen Bildbetrachter anzuschauen. Stattdessen bietet die VigraPLT einen einfachen Bildbetrachter, der die Bilder die aktuell in Scheme vorhanden sind anzeigen kann.
Dieser muss leider einigen Overhead erzeugen, um das Bild mit den GUI-Mitteln von DrScheme anzuzeigen, weshalb es bei großen Bildern vermutlich recht lange dauern wird sie zu laden. Generell stellen große Bilder aber kein Problem dar, da der Viewer Scrollbalken einblendet sobald das Bild größer als die Auflösung des Monitors ist.
Eine Zoomfunktion ist leider zur Zeit noch nicht enthalten. Dafür wird aber der Wert des aktuellen Pixels in der Statusleiste angezeigt, wenn man mit der Maus über das Bild fährt.
Zum Aufrufen des Viewers genügt eine Funktion (implementiert in „vigraplt.viewer.ss“):
(show-image image . Windowtitle) → void
Bedingungen:
image: image
windowtitle: optional: String
Beschreibung:
Diese Funktion zeigt das Bild mit dem Viewer an. Falls gewünscht, kann dem Fenster ein String als Titel zugewiesen werden.
In diesem Kapitel sind einige kleine Bespiele erläutert, die den Einstieg in die Programmierung mit VigraPLT erleichtern sollen. Die Beispiele sind von einfach bis anspruchsvoller geordnet und sicherlich nur als kleiner Einstieg in das Themengebiet zu verstehen.
Dieses Beispiel soll zunächst darstellen, wie man ein Bild laden, anzeigen, das Maximum aller Intensitätswerte herausfinden und unter einem anderen Format wieder abspeichern kann. Als erstes müssen wir die VigraPLT einbinden:
> (require vigraplt/vigraplt)
Jetzt können wir ein Bild laden:
> (define myImage (loadimage
(build-path vigraplt-path "blox.gif")))
Danach ist das Bild in myImage vorhanden! Wir können es uns also ansehen, zum Beispiel mit dem eingebauten Viewer:
> (show-image myImage „Blox-Bild“)
Der Viewer sollte jetzt erscheinen und das Bild anzeigen. Wenn wir uns nun für den maximalen Intensitätswert interessieren, so könnten wir nach dem hellsten Fleck im Viewer suchen, und mit der Maus darüber fahren, um den Intensitätswert zu erhalten.
Aber ist der per Hand ermittelte Wert tatsächlich der höchste aller vorkommenden Werte? Um dies zu prüfen kann z.B. die einbaute image-reduce Funktion verwendet werden:
> (define image-maximum (image-reduce max myImage 0.0))
Wenn wir nun
> image-maximum
eingeben, erhalten wir den höchsten aller Intensitätswerte. Soll das unveränderte Bild abgespeichert werden, genügt:
> (saveimage myImage (build-path vigraplt-path "blox.gif"))
Damit wird das Bild automatisch korrekt im PNG-Format abgespeichert, obwohl wir es als GIF gelesen hatten.
Dieses Beispiel soll zeigen, wie man die Bildverarbeitungs-Funktionen der VigraPLT einsetzt. Wir führen dazu einige Gaußsche Filter aus.
Als erstes müssen wir die VigraPLT einbinden:
> (require vigraplt/vigraplt)
Jetzt können wir ein Bild laden:
> (define myImage (loadimage
(build-path vigraplt-path "blox.gif")))
und einen ersten Filter durchlaufen lassen, um das Bild zu glätten:
> (define smoothImage (gsmooth myImage 1.0))
Um sich das Ergebnis anzuzeigen, kann wieder der Viewer verwendet werden:
> (show-image smoothImage „Blox-Bild geglättet mit sigma=1.0“)
Falls man nicht immer ein neues Symbol definieren möchte, z.B. um sich nur kurz Zwischenergebnisse anzuschauen, dann funktioniert selbstverständlich auch:
> (show-image (gsmooth myImage 1.0)
„Blox-Bild geglättet mit sigma=1.0“)
Um ein Gefühl für die Ergebnisse der Algorithmen zu bekommen, bietet es sich an, die verschiedenen Verfahren einmal mit unterschiedlichen Parametern aufzurufen, und sich anschließend die Auswirkungen der Parameterwahl zu erklären.
So könnte man sich zum Beispiel auch anschauen, welches Ergebnisbild
> (define mysteriousImage (ggradient myImage 1.0))
liefert, und wie sich die Änderung des Parameters hier bemerkbar macht. Die Ergebnisse oder Zwischenbilder lassen sich jederzeit auch abspeichern, z.B. mit:
> (saveimage mysteriousImage
(build-path vigraplt-path „myterious.png“))
Dieses Beispiel soll zeigen, wie die Wasserscheiden-Transformation, die in der VigraPLT enthalten ist, als Segmentierungsmethode eingesetzt werden kann.
Dafür müssen wir als erstes die VigraPLT einbinden:
> (require vigraplt/vigraplt)
Jetzt können wir ein Bild laden:
> (define myImage (loadimage
(build-path vigraplt-path "blox.gif")))
und dieses mithilfe der Wasserscheiden-Transformation segmentieren. Dabei gibt es jedoch zu beachten, dass die eigentliche Transformation nicht auf dem Bild selbst, sondern auf einem Gradientenbild ausgeführt werden sollte. Daher erzeugen wir das Regionenbild mit:
> (define regionImage (watersheds (ggradient myImage 0.7)))
In dem so erzeugten Regionen-Bild sind die Regionen einfach von oben nach unten durchnummeriert. Öffnet man es im Viewer mit:
> (show-image regionImage)
Dann sieht man kaum mehr als einen Farbverlauf, der durch oben beschriebene Nummerierung zustande kommt. Um das Ergebnisbild anschaulicher zu gestalten, könnte man nun zum Beispiel Kanten zwischen den Regionen explizit einzeichnen.
Dies würde einer CrackEdge-Repräsentation entsprechen, die glücklicherweise bereits in der VigraPLT eingebaut ist:
> (show-image (regionimagetocrackedgeimage regionImage 0.0))
Sehr viel schöner wäre es natürlich, wenn die jeweiligen Regionen mit dem Mittelwert aller enthaltenen Pixelintensitäten des ursprünglichen Bildes gefüllt wären. Dazu müssen die Intensitätswerte Regions-weise addiert und die Größe der Region gespeichert werden. Zunächst finden wir die Anzahl der Regionen heraus, und erstellen uns Vektoren für die Regionsstatistiken:
> (define region_count (inexact->exact
(+ (image-reduce max regionImage 0)
1)))
> (define region_sizes (make-vector region_count))
> (define region_colors (make-vector region_count))
Auch wenn dies nicht funktional geschieht, so entscheiden wir uns hier aus Gründen der Effizienz für die Vektor-Manipulations-Variante. Leider muss man in der Bildverarbeitung oft Kompromisse eingehen, möchte man funktional programmieren.
Es wird jetzt für jeden Pixel im Regionsbild die Regionsnummer herausgesucht. Dann wird in beiden Vektoren die Statistik der Region aktualisiert, sprich die Größe der Region wird um einen erhöht und der Farbwert aufsummiert:
> (image-for-each-index
(lambda (x y)
(let ((region_id (inexact->exact
(image-ref regionImage x y)))
(region_color (inexact->exact
(image-ref myImage x y))))
(begin
(vector-set! region_sizes region_id
(+ 1 (vector-ref region_sizes region_id)))
(vector-set! region_colors region_id
(+ region_color (vector-ref region_colors
region_id))))))
regionImage)
In den Vektoren stehen jetzt die Intensitätswerte bzw. die Größe der Regionen. Mit einem einfachen Map erzeugen wir daraus ein Regionen-Bild, bei dem jede Region mit dem mittleren Intensitätswert derselben gefüllt ist:
> (define meanColorImage
(image-map
(lambda (col)
(let ((color_id (inexact->exact col)))
(exact->inexact (/ (vector-ref region_colors
color_id)
(vector-ref region_sizes
color_id)))))
regionImage))
Nun haben wir statt der Regions-Nummer ein Bild, in dem jede Region mit dem mittleren Farbwert gefüllt ist. Betrachten wir nun
> (show-image
(regionimagetocrackedgeimage meanColorImage 0.0))
so erhalten wir ein ansprechendes Ergebnis! Dieses können wir natürlich auch abspeichern, wenn das gewollt ist:
> (save-image
(regionimagetocrackedgeimage meanColorImage 0.0)
(build-path vigraplt-path "nice-blox-watersheds.gif"))