MIN-Fakultät
Fachbereich Informatik
Szenenanalyse und Visualisierung (SAV)
Tutorial-Navigation (Benutzung der VIGRA unter Windows mit Dev-C++)
< 1 Installation Inhaltübersicht

 

2  Das erste VIGRA-Programm: Converter

Dieser Teil des Tutorials geht davon aus, dass Dev-C++ bereits inklusive aller benötigten Pakete installiert ist. Sollte dies nicht der Fall sein, muss zuerst den ersten Teil dieses Tutorials durchgehen.
Wir werden uns nun um unser erstes C++ Projekt kümmern, indem uns die VIGRA massiv unterstützt. Es geht darum einen Konverter zu schreiben, der aus der Kommandozeile aufgerufen werden kann und unter unter Angabe zweier Dateinamen, ein gegebenes Bild unter einem anderen Namen und/oder Format abspeichert. Ein Aufruf des entgültigen Programms könnte dann etwa so aussehen:

> converter lenna_rgb.bmp lenna_rgb.jpg

und würde einer Bitmap (*.bmp) zu JPEG (*.jpg) Konvertierung des Bildes lenna_rgb.bmp entspechen.
Zum Anfang muss erstmal ein neues Projekt in Dev-C++ angelegt werden. Dazu wird in einem Verzeichnis der Wahl ein Unterordner angelegt, zum Beispiel "lesson1". Anschließend muss Dev-C++ gestartet werden und mit dem Menü-Eintrag "File->New->Project" ein neues Projekt erstellt (siehe dieses Bild). Das Projekt sollte ein "empty project" sein und einen geeigneten Namen haben (z.B. converter) wie auf diesem Bild zu sehen ist. Daraufhin fragt Dev-C++ nach einem Speicherort für das neue Projekt. Wir wählen hierbei als Ordner den neu angelegten Ordner und als Dateinamen den gewählten Projektnamen (also z.B. converter.dev).
Was unserem noch leeren Projekt jetzt fehlt sind zwei Dinge:

  • Zum einen müssen wir dem Projekt noch unter dem Menüeintrag "Project->Project Options" (siehe hier) noch mitteilen, dass es die VIGRA-Import/Export-Bibliothek mit linken soll. Um dies zu erreichen, wechseln wir in den Reiter "Parameters" und wählen dort mit "Add Library or Object" die VIGRA-IMPEX Bibliothek aus. Sie findet sich unter "Dev-Cpp\lib\libvigraimpex.a". Nach erfolgreichem Abschluss sollte das Fenster so aussehen und kann nun mit einem Klick auf "OK" geschlossen werden. Nun sind alle Voraussetzungen zur Einbindung der VIGRA erfüllt (die Include-Pfade passen bereits nach Schritt 1), so dass wir uns dem Projekt weiter zuwenden können.
  • Zum anderen sollten wir dafür sorgen, dass unser Projekt überhaupt etwas tut, sprich wir müssen uns darum kümmern, dass durch Quelltext überhaupt ein Programm beschrieben wird. Dazu wird mit dem Menüeintrag "File->New->Source File" dem Projekt eine neue Quelltext-Datei hinzugefügt, die wir unter dem Dateinamen "converter.cxx" im angelegten Projekt-Verzeichnis speichern.

Nun können wir mit dem Quelltext des zu schreibenden Programms beginnen:

01: #include <iostream>
02: #include "vigra/stdimage.hxx"
03: #include "vigra/impex.hxx"
04:
05: using namespace vigra;
06:
07:

Die ersten drei Zeilen binden weitere Pakete ein, die wir in unserem ersten Projekt benötigen werden. Das Include "iostream" enthält dabei die Komponenten für die Stream-basierte Ein- und Ausgabe auf Konsolenebene. Die nächsten beiden Includes stammen aus der VIGRA, wobei das erste für die Repräsentation eines Bildes benötigt wird und das zweite die in der VIGRA enthaltenen Import/Export-Funktionen mitbringt.
Die folgende Zeile 05 stellt sicher dass in dem VIGRA-Namensraum definierte Funktionen und Klassen (wie z.B. vigra::BasicImage<T>) auch ohne Angabe des Namensraums gefunden werden können (es reicht dann z.B. nur BasicImage<T> zu schreiben).

08: int main(int argc, char ** argv)
09: {
10:    if(argc != 3)
11:    {
12:        std::cout << "Usage: " << argv[0] << " infile outfile" << std::endl;
13:        std::cout << "(supported formats: " << impexListFormats() << ")" << std::endl;
14:       return 1;
15:    }
16:

Die Main Funktion wird immer dann aufgerufen, wenn das Programm aufgerufen wird. Die dem Programm übergebenen Paramter werden im einem Array von char* gespeichert, und argc gibt an mit wievielen Argumenten das Programm aufgerüfen wurde. Dabei ist das erste Argument argv[0] immer gleich dem Programmnamen, also der ausfühbaren Datei. Da unser Konverter zudem noch zwei Dateinamen annehmen soll, wir geprüft ob drei Argumente übergeben wurden. Ist dies nicht der Fall, so wird eine Aufrufhilfe auf die Konsole ausgegeben. hier fällt besonders die Funktion "impexListFormats()" auf, die alle verfügbaren Import/Export-Formate der verwendeten VIGRA-IMPEX-Bibliothek ausgibt. Im Anschluss daran wird mit einem Fehlerwert (1) quittiert.

17:    try
18:    {
19:        ImageImportInfo info(argv[1]);
20:
21:        if(info.isGrayscale())
22:        {
23:            BImage in(info.width(), info.height());
24:
25:            importImage(info, destImage(in));
26:            exportImage(srcImageRange(in), ImageExportInfo(argv[2]));
27:        }

Das "try" in Zeile 17 leitet die Fehlerbehandlung ein. Wenn immer Zugriffe auf das Dateisystem des Rechners gebraucht werden, ist dies sinnvoll, da dem Programm ja evt. auch ein Dateiname einer Datei übergeben werden könnte, die gar nicht existiert. Darauf folgt das ImageImportInfo des VIGRA, welches gegeben ein Dateiname, Bildinformationen des zugrundeliegenden Bildes sammelt und repräsentiert. In unserem Beispiel ist der Dateiname der erste übergebene Parameter ("argv[1]"). Eine dieser Informationen ist zum Beispiel ob sich um ein Farb- oder Grauwertbild handelt, die im folgenden If-Block abgefragt wird. Farbbilder werden in der VIGRA anders repräsentiert, deswegen werden wir uns zunächst dem Fall der Grauwertbilder zuwenden.
In Zeile 23 wird ein vigra::BasicImage vom Typ BYTE (abgekürzt BImage) erstellt, das "in" heißt und die passende Größe besitzt (diese ist ebenfalls in der ImageImportInfo enthalten.
Anschließend wird das Bild mit importImage importiert und anschließend mit ExportImage wieder exportiert. Dabei wird für der Export der zweite übergebene Parameter ("argv[2]") benutzt.

28:        else
29:        {
30:            vigra::BRGBImage in(info.width(), info.height());
31:
32:            importImage(info, destImage(in));
33:            exportImage(srcImageRange(in), vigra::ImageExportInfo(argv[2]));
34:        }
35:    }
36:    catch (vigra::StdException & e)
37:    {
38:        std::cout << e.what() << std::endl;
39:        return 1;
40:    }
41:    return 0;
42:}

Im oben beschriebenen Else-Block findet das Importieren und Exportieren ganz analog für RGB-Bilder statt, die in der VIGRA als BasicImage vom Typ RGBValue repräsentiert werden und mit BRGBImage abgekürzt werden können.
Anschließend wird der eventuell geworfene Fehler bei der Verarbeitung abgefangen und auf der Konsole ausgegeben. Ist dieser Fall nicht eingetreten, so ist das Programm erfolgreich durchgelaufen, was mit der Rückgabe von "0" widergegeben wird.
Das war es auch schon, das erste Beispiel... Jetzt noch in Dev-C++ die Aufrufparameter unter "Excecute->Parameters" festlegen und mit "Excecute->Compile&Run" das Programm starten!