Das Fotomanipulationsprogramm Gimp hilft nicht nur dabei, Fotos optisch aufzubrezeln, sondern kann aus brandneuen Digitalbildern auch nostalgisch angehauchte Schwarz-Weiß-Bilder mit dem typischen Gelbstich produzieren.
Sieht man sich 100 Jahre alte Schwarz-Weiß-Bilder an, fällt 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 unternam, kam mir die Idee, einige auf der Reise mit der Digitalkamera aufgenommene Farbbilder (Abbildung 1) spaßeshalber in Schwarzweiß umzuwandeln und künstlich zu altern (Abbildung 2).
Abbildung 1: Das mit einer modernen Digitalkamera aufgenommene Originalfoto. |
Abbildung 2: Das mit Gimp künstlich gealterte Schwarz-Weiß-Foto mit Gelbstich. |
Die sogenannte Sepia-Tönung alter Fotografien kommt laut [4] durch ein Pigment zustande, das Fotografien ab dem späten 19. Jahrhundert chemisch zugesetzt und aus einem im Ärmelkanal heimischen Fisch namens ``Sepia officinalis'' gewonnen wurde. Um diesen Effekt bei neuen Digitalaufnahmen zu erzielen, werden vor allem die dunkeln Teile eines Bildes mit einem hellen Gelb-Braunton (Abbildung 3) versetzt. Mittelhelle Bildteile sind weniger betroffen und helle Stellen fast überhaupt nicht.
Es reicht
also nicht, einem Bild die Farbinformationen zu entziehen und es anschließend
gelblich einzufärben -- der täuschend nachgemachte Effekt erfordert
subilere Maßnahmen. Eric Jeschke hat auf [2] eine Reihe von Gimp-Operationen
zusammengestellt, die täuschend echte Vorkriegsbilder produzieren.
Mit dem Perl-Modul Gimp
vom CPAN lassen sich die Einzelschritte in ein
Perl-Skript verpacken, das der Nostaligiefreund ohne nennenswerten
Arbeitsaufwand auf ganze Fotoreihen loslassen kann.
Abbildung 3: Die Farbe "Sepia", ein heller Gelb-Braunton mit dem RGB-Wert [162,138,101]. |
Das Skript in Listing sepiafy
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 man anschließend mit einem Image-Viewer
wie zum Beispiel eog
(Eye-of-Gnome) ansehen kann.
Wie schon einmal in [5] erläutert, verlangen Gimp-Skripts zunächst einige
bürokratische Verwaltungsmaßnahmen, um Kontakt mit dem Gimp-Programm
aufzunehmen. 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 Hilfstext. Zeile 33 ruft schließlich
mit main()
das Gimp-Programm auf, das wiederum, wegen des Eintrags
in Zeile 30, die ab Zeile 36 definerte Funktion sepiafy()
aufruft.
Von hinten durch die Brust direkt ins Auge!
Die Funktion gimp_file_load()
in Zeile 39 lädt Bilddateien in allen von
Gimp unterstützten Formaten von der Festplatte und wandelt sie ins 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 Test in Zeile 42
bricht sofort das Programm ab.
Um Manipulationen am Bild auszuführen, ist zunächst das betroffene
``Drawable'' zu ermitteln, im vorliegenden Fall ist es der gerade aktive
(und bisland einzige) Layer im Gimp-Image. Die Funktion
image_get_active_layer()
mit der von der Ladefunktion vorher
zurückgelieferten
Bildreferenz $img
als Argument gibt ein Handle auf den zu bearbeitenden
Bild-Layer zurück.
Dessen Methode desaturate_full()
lässt aus den Bilddaten sämtliche Farbinformationen verschwinden.
Der Parameter 2 legt dabei das Verfahren DESATURATE-AVERAGE fest.
Weitere mögliche Werte wären die Methoden DESATURATE-LIGHTNESS (0) oder
DESATURATE-LUMINOSITY (1), die Farben aufgrund ihrer Helligkeit oder
ihrer Leuchtkraft in Grauwerte umwandeln und leicht unterschiedliche
Ergebnisse liefern.
Abbildung 4: Nach dem Aufruf der Funktion desaturate_full() verschwinden alle Farbinformationen und es bleibt ein Schwarz-Weiß-Bild. |
Übrig bleibt ein Graustufenbild (Abbildung 4), in das nun der
helligkeitsbasierte Gelbstich hineinfahren muss. Hierzu legt sepiafy
mit
der Funktion layer_copy()
einen weiteren Layer $sepia_layer
an, der eine Kopie
des Original-Layers des Bildes ist, um dem Skript Angaben von
Bildhöhe und Breite und anderem Krimskrams zu ersparen. Der Parameter
1
stellt sicher, dass der neue Layer einen sogenannten Alpha-Channel
anlegt, den er später zum Anlegen einer Layer-Maske brauchen wird. Dazu
später mehr.
Den Modus, mit dem der neue Layer mit den alten interferiert, um ein Gesamtbild
zu erzeugen, setzt Zeile 52 auf COLOR_MODE
. Ein anschließender
Aufruf von image_add_layer()
fügt den neu erzeugten, aber herrenlosen
Layer über dem aktuellen Layer im Layer-Dialog des gerade
bearbeiteten Bildes ein. Der Parameter -1 gibt an, dass er im Layer-Dialog
ganz oben zu liegen kommt.
Wozu der neue Layer $sepia_layer
?
Er wird mit der RGB-Farbe (162,138,101), dem
gelb-braunen Sepia-Ton, gefüllt und anschließend mittels einer
Layer-Maske helligkeitsabhängig auf den Original-Layer appliziert.
Das Füllen mit der via gimp_context_set_foreground()
gesetzten
Vordergrund-Farbe erledigt die Methode drawable_fill()
in Zeile 59.
Der Parameter 0 steht für das Verfahren FOREGROUND-FILL
.
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 }
Wäre es das Ziel, den Sepia-Ton gleichmäßig auf den Original-Layer
zu applizieren, könnte das Skript an dieser Stelle die verschiedenen
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. |
Da sepiafy
aber dunkle Stellen stärker vergilben will als helle, kommt
noch eine sogenannte Layermaske 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,
noch herrenlose Maske zum Layer $sepia_mask
hinzu.
Wie genau funktionieren eigentlich Masken im Gimp? Masken selektieren Bildteile, ganz genau 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 Schwarzweiß-Bild, dessen weiße Regionen selektierte Bildteile repräsentieren und dessen dunkle Pixel unselektierte. Selektiert der User also ein Rechteck in der Bildmitte, 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 nur so 'halb' 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 Teile des Originalbildes, an denen das Maskenbild helle Pixel aufweist.
Um die Transparenz eines Layers zu definieren, erlaubt es Gimp, zu jedem Layer eine sogenannte Layer-Maske zu definieren. Dieses Grauwertbild appliziert an seinen weißen Stellen die Bildwerte des Layers zu 100%, während die schwarzen Maskenpixel den Layer 100% 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 kommen wir der Sache schon näher.
Abbildung 6: Eine Layer-Maske mit einem dicken schwarzen Kreis als ... |
Abbildung 7: ... lässt das Bild im Schwarzteil der Maske unangetastet, appliziert aber den Sepia-Ton vollständig auf die Teile des Bildes, an denen die Maske weiß ist. |
Wie also muss nun die Maske aussehen, damit sie eine zum Verwechseln ähnliche Sepia-Färbung des Orignalbildes vornimmt, 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 appliziert den Sepia-Farbton zu 100%. Ist der Original-Layer hingegen weiß, ist die Maske schwarz und der Sepia-Layer kommt überhaupt nicht zum Original-Layer durch, lässt ihn also in Ruhe. Und an 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 ``Floating Section'', die Zeile 73 farb-invertiert
und Zeile 74 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 eingespielt. 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 werden noch die Farben der Layer-Maske über ``Colors->Invert'' invertiert 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 und dessen Layer-Maske |
das invertierte Originalbild ist.
Es bleibt nur noch, mittels der Methode flatten()
die beiden Layer zu einem aktiven
zusammenzufalten. Dies wirbelt allerdings die verfügbaren Layers durcheinander
und das Skript muss anschließend mit der Methode
get_active_layer()
der Bildreferenz eine Referenz auf den einzig
verbliebenen Layer hervorholen.
Das Resultat mit ordnungsgemäß aufgetragener
Sepia-Tönung ist in Abbildung 9 zu sehen, und damit
das Bild noch etwas dramatischer wirkt, wie in Abbildung 11 gezeigt, dunkelt
die Funktion curves_spline
dunkle Töne noch etwas ab, lässt aber hellere
unbeschadet. Die sechs übergebenen Koordinaten definieren einen Graphen
wie in Abbildung 10, die 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 9: Mit Sepia-Toning kommen Gelbtöne hauptsächlich in den dunklen Bildstellen zum Einsatz. |
Abbildung 10: Durch leichtes Absenken der dunklen Töne bei Beibehaltung der helleren ergibt sich ein dramatischeres Bild. |
Abbildung 11: Noch einmal zum Vergleich das Endergebnis, mit dramatisierter Abdunkelung der dunkleren Bildteile über den Curves-Dialog. |
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.
Zur 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
schweigen lässt, kommentiert den Aufruf von easy_init()
in Zeile
10 des Skripts einfach aus.
Abbildung 12: Gimps "Procedure Browser" hilft, die richtige API Funktion zu finden. |
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
(z.B. ``load'' oder ``save'' oder ``layer''), zeigt der Procedure-Browser eine
Liste von verfügbaren API-Funktionen mit minutiös dokumentierten
Parametern und Rückgabewerten an. So ist es meist möglich, mit etwas
Gespür jede im Gimp User-Interface per Mausklick verfügbare Aktion via
API-Funktion auszuführen und alle erdenklichen Bildmanipulationen zu
automatisieren.
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2009/04/Perl
``Sepia Toning'', Eric Jeschke, http://www.gimp.org/tutorials/Sepia_Toning/
``Retouch Pro: Luminosity Masks and Sepia Toning'', http://www.retouchpro.com/tutorials/lum-mask-sepia.html
``Farbenspiel'', Michael Schilli, Linux-Magazin 2008/07, http://www.linux-magazin.de/heft_abo/ausgaben/2008/07/farbenspiel
``Grokking the Gimp'', Carey Bunks, 2000, New Riders Publishing
Michael Schilliarbeitet 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. Seine Homepage: http://perlmeister.com. |