Bildverarbeitung mit PLT Scheme und der VIGRA = VIGRAPLT
Aufbau der Schnittstelle
Da es mit PLT Scheme seit Version 4.0 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. Diese ermöglicht es, C-konforme Shared Libraries (unter Windows: DLLs, unter MacOSX: dylibs) dynamisch zur Laufzeit an Lisp zu binden, so dass die enthaltenen Funktionen benutzt werden können.
Da die VIGRA allerings nur für 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-Biblitohek werden dann die entsprechenden Scheme Funktionen gebunden, die den Aufruf vor dem Benutzer verschatten.
Verwendete Datenstrukturen
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.
Repräsentation von Bildern
Die Repräsentation eines Bildes in dieser Erweiterung ist durch eine Liste von Bändern (Farbkanälen) gegeben. Jedes einzelne Band beruht wiederum 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.
Repräsentation von Matrizen
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.
Die folgende Tabelle zeigt noch einmal übersichtlich alle Funktionsnamen, die diese Schnittstelle PLT Scheme über die VIGRA_C bereitstellt:
![]() |
||||
vigraplt.impex |
vigraplt.imgproc |
vigraplt.filters |
vigraplt.segmentation |
vigraplt.morphology |
loadimage saveimage |
resizeimage-band resizeimage rotateimage-band rotateimage affinewarpimage-band affinewarpimage reflectimage-band reflectimage fouriertransform-band fouriertransform |
convolveimage-band convolveimage separableconvolveimage-band separableconvolveimage gsmooth-band gsmooth gaussiangradient-band gaussiangradient ggradient-band ggradient laplacianofgaussian-band laplacianofgaussian gsharpening-band gsharpening sharpening-band sharpening nonlineardiffusion-band nonlineardiffusion distancetransform-band distancetransform |
labelimage-band labelimage watersheds-band watersheds cannyedgeimage-band cannyedgeimage differenceofexponentialedgeimage-band differenceofexponentialedgeimage regionimagetocrackedgeimage-band regionimagetocrackedgeimage |
erodeimage-band erodeimage dilateimage-band dilateimage openingimage-band = (dilateimage-band (erodeimage-band band)) openingimage = (dilateimage (erodeimage img)) closingimage-band = (erodeimage-band (dilateimage-band band)) closingimage = (erodeimage (dilateimage img)) |
Außerdem gibt es noch in Scheme geschriebene Hilfsfunktionen, die den Umgang mit Bildern in der funktionalen Programmierung erleichtern sollen:
vigraplt.helpers |
||
Image |
Array |
Matrix |
Construction:make-image Accessors: image-data, image-width, image-height, image-ref, image-set! Conversion: copy-image,image->list, list->image Functional support: image-map, image-map!, image-reduce, image-for-each-index |
Construction:make-array Accessors: array-data, array-width, array-height, array-ref, array-set! Conversion: copy-array,array->list, list->array Functional support: array-map, array-map!, array-reduce, array-for-each-index |
Construction: make-matrix Accessors: matrix-data, matrix-rows, matrix-cols, matrix-ref, matrix-set! Conversion: copy-matrix,matrix->list, list->matrix Functions: matrix-mult |
Anwendungsbeispiele
Einbindung der VIGRAPLT in PLT Scheme (dafür muss die VIGRAPLT im "collects" Verzeichnis liegen):
> (require vigraplt/vigraplt)
Anschließend kann man zum Beispiel ein beliebiges Bild laden (hier: "blox.gif"):
> (define img (loadimage (build-path vigraplt-path "blox.gif")))
Das Bild mit einem Gaussfilter mit sigma=3 glätten und das geglättete Bild in img2 ablegen:
> (define img2 (gsmooth img 3.0))
Das geglättete Bild in den diskretisierten Frequenzraum überführen:
> (define img3 (fouriertransform img2))
Mit den Bild-Hilfsfunktionen lässt sich z.B. leicht ein Schwellenwert-Algorithmus schreiben:
> (define (threshold image t) (image-map (lambda (x) (if (> x t) 1.0 0.0)) image))
Auch ein Bild anhand einer Bildmaske auszuschneiden ist schnell mit den Bild-Hilfsfunktionen zu erreichen:
> (define (mask_image image mask) (image-map (lambda (value mask) (if (> mask 0.0) value 0.0)) image mask))
Download & Installation
Aktuelle Version 0.5.0
Das aktuelle Paket (Version 0.5.0) kann hier heruntergeladen werden. Es beinhaltet im Ordner vigraplt die VIGRAPLT Anbindung und im Unterordner vigra_c die nötigen VIGRA_C Dateien (siehe oben).Dieses Paket beinhaltet nicht die VIGRA! Diese muss bereits auf dem System installiert sein.
Außerdem ist noch das Referenzhandbuch für Version 0.5.0 als PDF verfügbar (OpenOffice Document-Format, HMTL-Format, Alle Formate und Beispiele als ZIP). Es beinhaltet eine ausführliche Beschreibung der Verfahren und weitere Beispiele (Hello Image-Beispiel, Filter-Beispiel, Segmentierungs-Beispiel).
Installationshinweise für MacOS X:
Erstellen der dynamischen Bibliothek (libvigra_c.dylib)
Dazu muss das Makefile im Unterordner vigra_c ausgeführt werden. Nach erfolgreichem Aufruf von "make" und anschließend "make install" sollten zwei Dateien "libvigra_c.dylib" "libvigra_c.so" im VIGRAPLT-Verzeichnis befinden. Anschließend muss noch das vigraplt Verszeichnis in das PLT Scheme "collects" Verzeichnis gelinkt werden, damit das oben angegebene "require" in PLT Scheme funktioniert.
Installationshinweise für Linux:
Erstellen der dynamischen Bibliothek (libvigra_c.so)
- Das Makefile im Ordner "vigraplt/vigra_c" so anpassen, dass der Pfad zur VIGRA korrekt gesetzt ist.
- make linux
- make install
- Anschließend muss noch das vigraplt Verszeichnis in das PLT Scheme "collects" Verzeichnis gelinkt werden, damit das oben angegebene "require" in PLT Scheme funktioniert.
Installationshinweise für Windows:
Entweder die vorkompilierte Version hier herunterladen und die enthaltene "vigraimpex.dll" in das Windows System-Verzeichnis kopieren (z.B. Windows\System32) oder
Erstellen der dynamischen Bibliothek (vigra_c.dll)
Dazu befindet sich im Unterordner "vigra_c\win32-msvc2005" ein Visual Studio Projekt. Hier müssen eventuell noch die Pfade, die zur VIGRA führen, angepasst werden. Danach kann man mit "Projekt erstellen" die DLL erzeugen. Nach erfolgreichem Aufruf sollte sich eine Datei namens "vigra_c.dll" im Release-Verzeichnis befinden. Diese muss nun noch ins "vigraplt" Verzeichnis kopiert werden. Anschließend muss noch das vigraplt Verszeichnis in das PLT Scheme "collects" Verzeichnis gelinkt werden, damit das oben angegebene "require" in PLT Scheme funktioniert.
Ältere Versionen
Bekannte Bugs der VIGRAPLT:
Leider hat sich einer kleiner Bug in die VIGRAPLT eingeschlichen, der mit der nächsten Version behoben werden wird. Bis dahin kann man den Bug selbst fixen, indem man in der Datei "vigraplt.helpers.ss" die Funktion list->image wie folgt ändert:
50: ; list -> image conversion 51: (define (list->image lst) 52: (list->carray lst _float))
Der gleiche Bug betrifft auch die Matrix zu Listen Konvertierungsfunktionen in derselben Datei:
156: ; list -> matrix conversion 157: (define (list->matrix lst) 158: (list->carray lst _double))
Außerdem führt die labelimage-Funktion eine Komponentennummerierung auf Grund der 8er-Zusammenhangskomponenten durch, und benutzt somit nicht wie im Handbuch beschrieben den 4er-Zusammenhang!
Das ältere Paket (Version 0.1.0) kann hier heruntergeladen werden. Es beinhaltet im Ordner vigraplt die VIGRAPLT Anbindung und im Unterordner vigra_c die nötigen VIGRA_C Dateien (siehe oben).
Außerdem ist noch das Referenzhandbuch für Version 0.1.0 verfügbar. Es beinhaltet eine ausführliche Beschreibung der Verfahren und weitere Beispiele.Dieses Paket beinhaltet nicht die VIGRA! Diese muss bereits auf dem System installiert sein.
Installationshinweise für MacOS X:
Erstellen der dynamischen Bibliothek (vigra_c.dylib)
Dazu muss das Makefile im Unterordner vigra_c ausgeführt werden. Nach erfolgreichem Aufruf sollte sich eine Datei namens "vigra_c.dylib" im VIGRAPLT-Verzeichnis befinden. Anschließend muss noch das vigraplt Verszeichnis in das PLT Scheme "collects" Verzeichnis gelinkt werden, damit das oben angegebene "require" in PLT Scheme funktioniert.
Installationshinweise für Linux:
Erstellen der dynamischen Bibliothek (vigra_c.so)
Das Erstellen einer Linux-Bibliothek wird zur Zeit noch nicht direkt unterstützt, es sollte jedoch kein Problem sein die Anpassungen zu tun, die dafür nötig sind:
- Das Makefile im Ordner "vigraplt/vigra_c" so anpassen, dass ein C-kompatibles shared object file im Ordner vigraplt erzeugt wird.
- Die vigraplt.cl Datei musss nun nur noch so angepasst werden, dass sie auch nach dieser Datei sucht, falls das Betriebssystem ein Linux ist. Dies müsste in Zeile 2-4 ergänzt werden.
- Anschließend muss noch das vigraplt Verszeichnis in das PLT Scheme "collects" Verzeichnis gelinkt werden, damit das oben angegebene "require" in PLT Scheme funktioniert.
Installationshinweise für Windows:
Entweder die vorkompilierte Version hier herunterladen oder
Erstellen der dynamischen Bibliothek (vigra_c.dll)
Dazu befindet sich im Unterordner "vigra_c\win32-msvc2005" ein Visual Studio Projekt. Hier müssen eventuell noch die Pfade, die zur VIGRA führen, angepasst werden. Danach kann man mit "Projekt erstellen" die DLL erzeugen. Nach erfolgreichem Aufruf sollte sich eine Datei namens "vigra_c.dll" im Release-Verzeichnis befinden. Diese muss nun noch ins "vigraplt" Verzeichnis kopiert werden. Anschließend muss noch das vigraplt Verszeichnis in das PLT Scheme "collects" Verzeichnis gelinkt werden, damit das oben angegebene "require" in PLT Scheme funktioniert.
Weitere Meilensteine:
- Einbindung weiterer VIGRA-Funktionen