Aus Linux-Magazin 04/2009

Perl automatisiert Bildverarbeitung mit Gimp

© Andybahn, Photocase.com

Das Fotomanipulationsprogramm Gimp hilft nicht nur dabei, Fotos optisch aufzubrezeln, es beherrscht auch den umgekehrten Fall: Aus brandneuen Digitalbildern macht es nostalgisch angehauchte Fotos mit dem typischen Gelbstich.

100 Jahre alte Schwarz-Weiß-Bilder fallen durch eine gelbliche Tönung auf. Besonders an den ursprünglich schwarzen Stellen hat der Zahn der Zeit genagt und sie braun gefärbt, aber auch die helleren Töne weisen einen leichten Gelbstich auf. Als ich vor Kurzem aus meinem Domizil, dem bunten Amerika, einen Abstecher in meine alte Heimat Deutschland unternahm, kam mir die Idee, einige auf der Reise mit der Digitalkamera aufgenommene Farbbilder (Abbildung 1) spaßeshalber in Schwarz-Weiß umzuwandeln und künstlich zu altern (Abbildung 2). Die so genannte Sepia-Tönung alter Fotografien rührt laut Wikipedia [4] von einem Pigment her, das sich ab dem späten 19. Jahrhundert in Fotografien findet. Man gewann es aus einem im Ärmelkanal heimischen Fisch, der mit lateinischem Namen Sepia officinalis heißt.

Abbildung 1: Dies ist das mit einer modernen Digitalkamera aufgenommene Originalfoto, das der hier entwickelte Filter verfremden soll.

Abbildung 1: Dies ist das mit einer modernen Digitalkamera aufgenommene Originalfoto, das der hier entwickelte Filter verfremden soll.

Abbildung 2: Ergebnis: Das mit Gimp künstlich gealterte Schwarz-Weiß-Foto mit Gelbstich. Dank des Skripts lassen sich ganze Bildserien so bearbeiten.

Abbildung 2: Ergebnis: Das mit Gimp künstlich gealterte Schwarz-Weiß-Foto mit Gelbstich. Dank des Skripts lassen sich ganze Bildserien so bearbeiten.

Neue Fotos – fischgelb

Um diesen Effekt auch bei neuen Digitalaufnahmen zu erzielen, versetzt der Bildkünstler vor allem die dunklen Teile eines Bildes mit einem hellen Gelb-Braun-Ton (Abbildung 3). Die Bildteile mittlerer Helligkeit sind weniger betroffen und helle Stellen fast überhaupt nicht.

Abbildung 3: Sepia ist ein heller Gelb-Braun-Ton mit dem RGB-Wert [162,138,101]. Der Name stammt von einem Fisch, aus dem man ein Pigment gewann.

Abbildung 3: Sepia ist ein heller Gelb-Braun-Ton mit dem RGB-Wert [162,138,101]. Der Name stammt von einem Fisch, aus dem man ein Pigment gewann.

Es reicht also nicht, einem Bild die Farbinformationen zu entziehen und es anschließend gelblich einzufärben – der täuschend nachgemachte Effekt erfordert subtilere Maßnahmen. Eric Jeschke hat auf [3] eine Reihe von Gimp-Operationen zusammengestellt, die verblüffend echt aussehende Vorkriegsbilder produzieren. Mit dem Perl-Modul »Gimp« vom CPAN lassen sich die Einzelschritte in ein Perl-Skript packen, das der Nostalgiefreund ohne nennenswerten Arbeitsaufwand auf ganze Fotoreihen loslassen kann.

Durch die Brust ins Auge

Das Skript »sepiafy« in Listing 1 nimmt auf der Kommandozeile eine Bilddatei entgegen, unterwirft sie einer Reihe von Transformationen und spuckt anschließend ein künstlich gealtertes Schwarz-Weiß-Bild mit Gelbstich aus. Der Aufruf »sepiafy bild.jpg« erzeugt die Ergebnisdatei »bild-sepia.jpg«. Die lässt sich anschließend mit einem Image-Viewer wie zum Beispiel »eog« (Eye of Gnome, [7]) betrachten.

Listing 1:
»sepiafy«

01 #!/usr/bin/perl
02 use warnings;
03 use strict;
04
05 use Gimp qw(:auto);
06 use Gimp::Fu;
07 use Getopt::Std;
08 use Log::Log4perl qw(:easy);
09
10 Log::Log4perl->easy_init($DEBUG);
11 DEBUG "Starting up";
12
13 my $menu =
14     "<Toolbox>/Xtns/Perl-Fu/Sepiafy";
15
16 my $file = $ARGV[0];
17 die "No file"
18       unless defined $file;
19
20 register(
21   "perl_fu_sepiafy",   # Name
22   "Sepia Toning",      # Explain
23   "",                  # Help
24   "",                  # Author
25   "",                  # Copyright
26   "",                  # Date
27   $menu,               # Menu
28   "*",                 # Images accepted
29   [ undef ],           # No parameters
30   \&sepiafy            # Function
31 );
32
33 exit main();
34
35 ###########################################
36 sub sepiafy {
37 ###########################################
38
39   my $img = gimp_file_load(
40       RUN_NONINTERACTIVE, $file, $file);
41
42   die "Can't load $file" unless $img;
43
44   my $layer = image_get_active_layer($img);
45
46   DEBUG "Desaturate";
47   $layer->desaturate_full(2);
48     # 2: Average
49
50   my $sepia_mask = $layer->layer_copy(1);
51     # 1: Add Alpha Channel
52   $sepia_mask->layer_set_mode(COLOR_MODE);
53
54     # Insert layer above active layer
55   $img->image_add_layer($sepia_mask, -1);
56
57   gimp_context_set_foreground(
58                        [162, 138, 101] );
59   $sepia_mask->drawable_fill(0);
60     # 0: FOREGROUND-FILL
61
62   DEBUG "Adding layer mask";
63   my $layer_mask =
64          $sepia_mask->layer_create_mask(0);
65            # 0: White mask
66   $sepia_mask->layer_add_mask(
67                              $layer_mask );
68
69   $layer->edit_copy();
70
71   my $float = $layer_mask->edit_paste(0);
72     # 0: Clear selection 1: Paste behind it
73   $float->invert();
74   $float->floating_sel_anchor();
75
76   DEBUG "Flattening image";
77   $img->flatten();
78   $layer = $img->get_active_layer;
79
80   $layer->curves_spline(HISTOGRAM_VALUE,
81                   [0,0, 58, 36, 255, 255]);
82
83   $file =~ s/./-sepia./g;
84   DEBUG "Saving $file";
85   gimp_file_save(
86     RUN_NONINTERACTIVE,
87     $img,
88     $layer,
89     $file,
90     $file);
91
92   return $img;
93 }

Wie schon einmal in [5] erläutert, verlangen Gimp-Skripte zunächst einige bürokratische Verwaltungsmaßnahmen, damit sie Kontakt mit dem Bildverarbeitungsprogramm aufnehmen können. Die in Zeile 20 aufgerufene Funktion »register()« definiert einen Namen, einen Menü-Eintrag und noch weitere, in der Kommandozeilenversion eigentlich unnütze Angaben wie Autor und Hilfetext. Die Zeile 33 ruft schließlich mit »main()« das Gimp-Programm auf, das wiederum, wegen des Eintrags in Zeile 30, die ab Zeile 36 definierte Funktion »sepiafy()« startet. Also von hinten durch die Brust direkt ins Auge!

Farben aussaugen

Die Funktion »gimp_file_load()« in Zeile 39 lädt Bilddateien in allen von Gimp unterstützten Formaten von der Festplatte und wandelt sie in das von Gimp intern genutzte Format um. Schlägt der Ladevorgang fehl, zum Beispiel weil die angegebene Datei nicht vorhanden oder unlesbar ist, liefert »gimp_file_load()« den Wert »undef« zurück und der anschließende Test in Zeile 42 bricht das Programm sofort ab.

Um Manipulationen am Bild auszuführen, ist zunächst jener Bereich zu bestimmen, auf den sie sich beziehen sollen, das so genannte Drawable. Im vorliegenden Fall ist es der gerade aktive (und bislang einzige) Layer im Gimp-Image. Die Funktion »image_get_active_layer()«, die als Argument die Bildreferenz »$img« erhält, welche zuvor von der Ladefunktion zurückgeliefert wurde, gibt danach ein Handle auf den zu bearbeitenden Bild-Layer zurück.

Dessen Methode »desaturate_full()« lässt aus den Bilddaten alle Farbinformationen verschwinden. Der Parameter »2« legt dabei fest, dass das Verfahren »DESATURATE-AVERAGE« zum Einsatz kommen soll. Weitere mögliche Werte wären die Methoden »DESATURATE-LIGHTNESS« (Wert »0«) oder »DESATURATE-LUMINOSITY« (Wert »1«).

Alle diese Methoden wandeln die Farben aufgrund ihrer Helligkeit oder ihrer Leuchtkraft in Grauwerte um, liefern dabei aber jeweils leicht unterschiedliche Ergebnisse. Übrig bleibt ein Graustufenbild (Abbildung 4), dem noch der helligkeitsbasierte Gelbstich fehlt.

Abbildung 4: Nach dem Aufruf der Funktion »desaturate_full()« verschwinden alle Farbinformationen und es bleibt ein Schwarz-Weiß-Bild.

Abbildung 4: Nach dem Aufruf der Funktion »desaturate_full()« verschwinden alle Farbinformationen und es bleibt ein Schwarz-Weiß-Bild.

Dazu legt »sepiafy« mit der Funktion »layer_copy()« eine Kopie des Original-Layers des Bildes an (»$sepia_layer«), um dem Skript Angaben über Bildhöhe und Breite und anderen Krimskrams zu ersparen. Der Parameter »1« stellt sicher, dass der neue Layer einen so genannten Alphachannel kreiert, der später zum Anlegen einer Layer-Maske nötig ist.

Nicht nur Grau in Grau

Zeile 52 legt mit »COLOR_MODE« fest, wie der neue Layer den alten überlagern soll, um ein Gesamtbild zu erzeugen. Ein anschließender Aufruf von »image_add_layer()« fügt den neu erzeugten, aber herrenlosen Layer im Layer-Dialog über dem des gerade bearbeiteten Bildes ein. Der Parameter »-1« gibt dafür an, dass er im Layer-Dialog ganz oben zu liegen kommt.

Wozu der neue Layer »$sepia_layer«? Das Skript füllt ihn mit der RGB-Farbe [162,138,101], dem gelb-braunen Sepia-Ton, und legt dann eine Layer-Maske helligkeitsabhängig auf den Original-Layer. Das Füllen mit der via »gimp_context_set_foreground()« gesetzten Vordergrundfarbe erledigt die Methode »drawable_fill()« in Zeile 59. Der Parameter »0« steht für das Verfahren »FOREGROUND-FILL«.

Wäre es das Ziel, den Sepia-Ton gleichmäßig auf das Original zu applizieren, könnte das Skript hier die Layer zusammenfalten und aufhören, denn der in Zeile 52 eingestellte »COLOR_MODE« würde die Farbinformationen der beiden Layer sanft vermischen (Abbildung 5).

Abbildung 5: Gleichmäßig applizierte Gelbtöne färben nicht nur die dunklen Bildstellen, sondern auch die hellen.

Abbildung 5: Gleichmäßig applizierte Gelbtöne färben nicht nur die dunklen Bildstellen, sondern auch die hellen.

Da »sepiafy« aber dunkle Stellen stärker vergilben will als helle, kommt noch eine so genannte Layer-Maske zum Einsatz. Sie gibt an, wie der Gelbstich-Layer mit dem Original-Layer des Bildes interagiert. Zeile 64 erzeugt die Maske. Der Parameter »0« steht für »ADD-WHITE-MASK«, also eine Maske, deren Pixel zunächst alle weiß sind. Der anschließende Aufruf von »layer_add_mask()« fügt die neu erzeugte Maske zum Layer »$sepia _mask« hinzu.

Maskenball

Wie genau funktionieren eigentlich Masken in Gimp? Masken selektieren Bildteile, ganz genau so, wie man mit dem Selektionstool beispielsweise ein Rechteck in einem Bild selektiert, das Gimp daraufhin mit den “wandernden Ameisen” darstellt. Diese Selektionsinformation speichert Gimp als Schwarz-Weiß-Bild, dessen weiße Regionen selektierte Bildteile repräsentieren und dessen dunkle Pixel unselektierte. Wählt der User also ein Rechteck in der Bildmitte aus, ist die zugehörige Maske ein schwarzes Bild mit einem weißen Rechteck in der Mitte. Im Gegensatz zu Selektionen mit der Maus können Masken außerdem noch Grauwerte definieren, die zugehörigen Bildteile sind dann unterschiedlich stark selektiert.

Diese Grauwertbilder lassen sich nun auf sehr elegante Weise als Bildfilter verwenden. Statt mühsam Bildteile von Hand zu selektieren, definiert der User ein Maskenbild, und Gimp selektiert automatisch die Teile des Originalbilds, an denen das Maskenbild helle Pixel aufweist.

Um die Transparenz eines Layers zu definieren, erlaubt es Gimp außerdem, zu jedem Layer eine Layer-Maske zu definieren. Dieses Grauwertbild lässt an seinen weißen Stellen die Bildwerte des Layers zu 100 Prozent durchscheinen, während die schwarzen Maskenpixel den Layer hundertprozentig transparent machen, ihn also deaktivieren. An den grauen Pixeln der Layer-Maske appliziert Gimp den Wert des Layers zu einem entsprechenden Bruchteil.

Abbildung 6 zeigt den Layer-Dialog mit einem testweise eingetragenen dicken schwarzen Kreis auf weißem Hintergrund als Layer-Maske im Sepia-Layer, der Überlagerungsmodus des Layers ist auf »Normal« eingestellt. Wie in Abbildung 7 sichtbar, lässt Gimp das Originalbild so im Schwarzteil der Maske unangetastet, während er im Weißteil die Sepia-Farbe ohne Rücksicht auf die Bildinformation aufträgt. Dies ist zweifellos noch nicht die richtige Strategie, aber mit einem Graustufenbild als Maske kommt man der Sache schon näher.

Abbildung 6: Eine Layer-Maske mit einem dicken schwarzen Kreis in der Mitte ...

Abbildung 6: Eine Layer-Maske mit einem dicken schwarzen Kreis in der Mitte …

Abbildung 7: ... lässt das Bild im Schwarzteil der Maske unangetastet, appliziert aber den Sepia-Ton vollständig auf jene Teile des Bildes, an denen die Maske weiß ist.

Abbildung 7: … lässt das Bild im Schwarzteil der Maske unangetastet, appliziert aber den Sepia-Ton vollständig auf jene Teile des Bildes, an denen die Maske weiß ist.

Original als Maske

Wie also muss nun die Maske aussehen, damit eine zum Verwechseln ähnliche Sepia-Färbung des Originalbilds zustande kommt, also an dessen dunklen Stellen die Schleusen öffnet und an dessen hellen Stellen dicht macht? Ist ein Pixel des Original-Layers schwarz, muss die Maske dort weiß sein und sie wendet den Sepia-Farbton zu 100 Prozent an. Ist der Original-Layer hingegen weiß, dann ist die Maske schwarz und der Sepia-Layer kommt überhaupt nicht zum Original-Layer durch, lässt ihn also in Ruhe. Bei Grauwerten liegt die Maske entsprechend in der Mitte. Jetzt ist die Lösung hoffentlich offensichtlich: Die gesuchte Maske ist genau das invertierte Graustufenbild des Original-Layers!

Um dies zu realisieren, kopiert Zeile 69 das Bild im Original-Layer in den Gimp-internen Cut&Paste-Puffer, und Zeile 71 streift dessen Inhalt wieder auf der Layer-Maske »$layer_mask« ab. Zurück kommt eine Referenz auf eine so genannte Floating Section, die Zeile 73 farbinvertiert und die Zeile 74 dann in der Layer-Maske verankert.

In Gimp würde der User hierzu den Original-Layer im Layer-Dialog anklicken, dann zum Bildfenster wechseln, »Select-All« drücken und mit [Ctrl]+[C] den Bildinhalt in den Cut&Paste-Puffer kopieren. Anschließend ein Mausklick auf die Layer-Maske des Sepia-Layers (zweites Thumbnail in der Layer-Zeile), zurück zum Bildfenster und den Inhalt mit »Paste« dort einspielen. Dies erzeugt eine »Floating Section« im Layers-Dialog, die ein Klick auf den Anker am unteren Rand des Layers-Dialogs in die Layer-Maske einbetoniert. Anschließend invertiert der Fotokünstler noch die Farben der Layer-Maske über »Colors | Invert«, und der Layers-Dialog sieht aus wie in Abbildung 8.

Abbildung 8: Das Skript fügt in Gimp einen neuen Layer ein, dessen Bildinhalt – eine Sepia-farbene Fläche – sowie dessen Layer-Maske.

Abbildung 8: Das Skript fügt in Gimp einen neuen Layer ein, dessen Bildinhalt – eine Sepia-farbene Fläche – sowie dessen Layer-Maske.

Es bleibt als Nächstes nur noch, mit Hilfe der Methode »flatten()« die beiden Layer zu einem aktiven zusammenzulegen. Dies wirbelt allerdings die verfügbaren Layer durcheinander, Das Skript muss daher anschließend mit der Methode »get_active_layer()« noch eine Referenz auf den einzigen verbliebenen Layer hervorholen.

Das Resultat mit der ordnungsgemäß aufgetragenen Sepia-Tönung ist in Abbildung 9 zu sehen, und damit das Bild noch etwas dramatischer wirkt, etwa wie in Abbildung 10 gezeigt, dunkelt die Funktion »curves_spline« dunkle Töne noch etwas weiter ab, lässt aber hellere unbeschadet.

Abbildung 9: Mit Sepia-Toning kommen Gelbtöne hauptsächlich in den dunklen Bildstellen zum Einsatz.

Abbildung 9: Mit Sepia-Toning kommen Gelbtöne hauptsächlich in den dunklen Bildstellen zum Einsatz.

Abbildung 10: Noch einmal zum Vergleich das Endergebnis, mit dramatisierter Abdunkelung der dunkleren Bildteile über den Curves-Dialog.

Abbildung 10: Noch einmal zum Vergleich das Endergebnis, mit dramatisierter Abdunkelung der dunkleren Bildteile über den Curves-Dialog.

Die sechs übergebenen Koordinaten definieren einen Graphen wie in Abbildung 11, der die gewünschte Manipulation am Bild vornimmt, ganz so, als hätte der User dies in Gimps Curves-Dialog verlangt. Eine lineare Kurve im Curves-Dialog lässt das Bild in Ruhe, eine Ausbuchtung nach unten hingegen führt zu einer Verdunkelung im jeweiligen Helligkeitsbereich.

Abbildung 11: Durch leichtes Absenken der dunklen Töne bei Beibehaltung der helleren ergibt sich ein dramatischeres Bild.

Abbildung 11: Durch leichtes Absenken der dunklen Töne bei Beibehaltung der helleren ergibt sich ein dramatischeres Bild.

Die Funktion »gimp_file_save()« speichert das Ergebnis unter einem neuen Dateinamen ab, den Zeile 83 durch Anhängen der Zeichenkette »-sepia« an den Originalnamen erzeugt hat.

Installation

Für die Installation der notwendigen Perl-Module Gimp und Gimp::Fu genügt unter Ubuntu Hardy Heron ein einfaches:

sudo apt-get install libgimp-perl

Ältere Ubuntu-Versionen haben eine Macke, aber [5] zeigt, wie man es mit ein paar Tricks trotzdem installiert. Das Log4perl-Modul (erhältlich vom CPAN oder als Paket »liblog-log4perl-perl« der Linux-Distribution) zeigt den Fortschritt der Bildumwandlung auf der Kommandozeile an. Wer das Skript lieber schweigend arbeiten lassen möchte, der kommentiert dafür den Aufruf von »easy_init()« in Zeile 10 des Skripts einfach aus.

Prozeduren suchen

Die Dokumentation von Gimps Perl-Schnittstelle ist nicht sehr detailliert, aber Gimp verfügt über einen exzellenten Procedure-Browser, den der User über das Menü »Xtns->Procedure Browser« aufrufen kann. Gibt er anschließend ins Suchfeld einen erratenen Teil des gewünschten Funktionsnamens ein (beispielsweise »load« oder »save« oder »layer«), dann zeigt der Procedure-Browser eine Liste von verfügbaren API-Funktionen mit minutiös dokumentierten Parametern und Rückgabewerten an (Abbildung 12). Auf diese Weise ist es meist nicht allzu schwierig, mit ein wenig Gespür jede im Gimp-User-Interface per Mausklick verfügbare Aktion auch via API-Funktion auszuführen und damit alle erdenklichen Bildmanipulationen mit Skripten zu automatisieren. (jcb)

Infos

[1] Listings zu diesem Artikel: [ftp://www.linux-magazin.de/pub/listings/magazin/2009/04/Perl]

[2] Retouch Pro: Luminosity Masks and Sepia Toning: [http://www.retouchpro.com/tutorials/lum-mask-sepia.html]

[3] Eric Jeschke, “Sepia Toning”: [http://www.gimp.org/tutorials/Sepia_Toning]

[4] Sepia: [http://en.wikipedia.org/wiki/Sepia_tone]

[5] Michael Schilli, “Farbenspiel”: Linux-Magazin 07/08: [https://www.linux-magazin.de/heft_abo/ausgaben/2008/07/farbenspiel]

[6] Carey Bunks, “Grokking the Gimp”: New Riders Publishing, 2000

[7] Eye of Gnome: [http://projects.gnome.org/eog/]

Der Autor


Michael Schilli arbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat “Goto Perl 5” (deutsch) und “Perl Power” (englisch) für Addison-Wesley geschrieben und ist unter [mschilli@perlmeister.com] zu erreichen.

LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben