Open Source im professionellen Einsatz
Linux-Magazin 08/2008
© Claudia Hautumm,Pixelio.de

© Claudia Hautumm,Pixelio.de

Perl automatisiert Farbkorrekturen für Digitalfotos

Kartentrick

Wer es zu mühselig findet, die ins Bild gehaltenen Referenzkarten für die Farbkorrektur in Gimp - wie im vorigen Snapshot beschrieben - manuell auszuwählen, der freut sich jetzt sicherlich über ein Skript, das diesen Vorgang automatisiert.

864

Im vorigen Monat ging es an gleicher Stelle darum, den von der Kamera erzeugten Farbstich eines Fotos nachträglich mit Hilfe von Referenzkarten (Abbildung 1) zu korrigieren, die der Fotograf probeweise mit aufnimmt [2]. Die Plastikkärtchen aus dem Fotofachhandel mit genormten Schwarz, Weiß- und Grauwerten sollten im Bild keinerlei Farbwerte ergeben. Mitfotografiert bieten sie daher drei Messpunkte für geringe, mittlere und hohe Lichtintensität, dank derer das Fototool Gimp die Farbkurve eines Fotos im Nachhinein korrigieren kann.

Abbildung 1: Es gilt, die Farbwerte der drei ins Bild gehaltenen Karten zu ermitteln. Hierzu fährt das Skript die Farbwerte entlang der horizontalen Mittelinie ab und sucht die homogenen Flächen der Karten.

Wie findet ein einfaches Perlskript ohne Einsatz von künstlicher Intelligenz heraus, welche Pixelwerte die drei Karten gegebenenfalls erzeugen? Die Schwierigkeit: Die Lage der Karten im Bild ist nicht genau bekannt und auch nicht immer gleich. Schafft es der Fotograf jedoch, die drei Karten, so wie in Abbildung 1 gezeigt, in der Bildmitte aufgefächert zu halten, kann ein Skript der gedachten horizontalen Mittellinie des Bildes folgen und die Karten anhand der Pixelwerte auf der x-Achse ermitteln.

Entlang dieser Linie bleibt die gemessene Lichtintensität nämlich über weite Strecken relativ konstant, solange die Linie über eine der Referenzkarten verläuft. Schneidet die Linie hingegen den Bildhintergrund, dann schwanken die ermittelten Pixelwerte recht stark.

RGB: Dreimal 0 bis 255

Das Listing 1 (»graphdraw«) erzeugt mit Hilfe des Imager-Moduls vom CPAN den in Abbildung 2 gezeigten Kurvenverlauf. Die drei Graphen bilden die Rot-, Grün- und Blauwerte entlang der in Abbildung 1 zur Verdeutlichung eingezeichneten horizontalen Linie in ein Koordinatensystem ein, dessen x-Achse den x-Koordinaten im Bild entspricht und dessen y-Wert den jeweiligen Farbanteil im Bereich zwischen 0 und 255 repräsentiert.

Listing 1:
»graphdraw«

01 #!/usr/local/bin/perl -w
02 use strict;
03 use Imager;
04 use Imager::Plot;
05 use Log::Log4perl;
06 
07 my($file) = @ARGV;
08 die "No file given" unless defined $file;
09 
10 my $img = Imager->new();
11 $img->read( file => $file ) or
12   die $img->errstr();
13 
14 $img->filter(
15   type   => "gaussian",
16   stddev => 10 ) or die $img->errstr;
17 
18 my $y     = int( $img->getheight() / 2 );
19 my $width = $img->getwidth();
20 
21 my $data = {};
22 
23 for my $x (0..$width-1) {
24   push @{ $data->{ x } }, $x;
25 
26   my $color = $img->getpixel( x => $x,
27                               y => $y );
28   my @components = $color->rgba();
29   for my $color_name (qw(red green blue)) {
30     push @{ $data->{ $color_name } },
31          shift @components;
32     }
33 }
34 
35 my $plot = Imager::Plot->new(
36   Width  => 550,
37   Height => 350,
38   GlobalFont =>
39   '/usr/share/fonts/truetype/msttcorefonts/Verdana.ttf');
40 
41 for my $color_name (qw(red green blue)) {
42   $plot->AddDataSet(
43     X => $data->{x},
44     Y => $data->{$color_name},
45     style => {
46       marker => {
47         size   => 2,
48         symbol => 'circle',
49         color => Imager::Color->new($color_name),
50       }
51     }
52   );
53 }
54 
55 my $graph = Imager->new(
56         xsize => 600,
57         ysize => 400);
58 
59 $graph->box(filled => 1, color => 'white');
60 
61     # Add text
62 $plot->{'Ylabel'} = 'RGB Values';
63 $plot->{'Xlabel'} = 'X-Pixel';
64 $plot->{'Title'}  = 'RGB-Distribution';
65 
66 $plot->Render(
67   Image => $graph,
68   Xoff  => 40,
69   Yoff  => 370);
70 
71 $graph->write(file => "graph.png") or die $graph->errstr();

Die Methode »read()« des Imager-Moduls ist ein Multitalent, das alle gängigen Bildformate erkennt, einliest und in das interne Imager-Format zur zügigen Weiterverarbeitung umwandelt. Geht irgendetwas schief, liefern die Imager-Methoden falsche Werte zurück. Um mehr Details über einen Fehler herauszufinden, ruft der sorgfältige Programmierer in diesem Fall die Methode »errstr()« auf, die daraufhin eine Klartextbeschreibung des Fehlers liefert.

Die Methode »getpixel()« untersucht die RGB-Werte eines per x- und y-Koordinate festgelegten Pixels im Bild. Sie gibt ein Objekt vom Typ »Imager::Color« zurück. Es enthält die RGB-Werte des Pixels und gibt sie mit der Methode »rgba()« zusammen mit dem Wert des Alphakanals preis. Es interessieren nur die ersten drei RGB-Werte, die das Skript mit »shift« in Zeile 31 extrahiert.

Abbildung 2: Die Farbwerte des ungefilterten Bildes sind zu zittrig, um die Karten zuverlässig zu erkennen. Die Bereiche, die die Karten repräsentieren, zeichnen sich nicht deutlich genug ab.

Bequem bebildert

Das Modul Imager::Plot stellt öde Zahlenkolonnen in einem ansprechenden Koordinatensystem dar, ohne dass viel Fitzelei mit Skalierung, Achsenbeschriftungen oder grafischem Layout notwendig wäre. Es liefert Bilddateien in allen gängigen Formaten, die der Nutzer danach mit einem Image-Viewer oder einem Webbrowser begutachtet. Der Konstruktor »new()« nimmt die gewünschten Dimensionen der Achsengrafik und den Pfad zu einem installierten Truetype-Font für die Achsenbeschriftung entgegen.

Das Skript sammelt alle Koordinatendaten in einem Hash von Hashes, auf den die Referenz »$data« zeigt. Es legt alle x-Koordinaten in »$data->{x}« und alle Rotwerte in »$data->{red}« ab. Analoges gilt für die Grün- und Blauwerte entlang der x-Achse. Die Methode »AddDataSet« bestimmt jeweils die Daten für einen der drei Graphen. Das Skript ruft sie dreimal auf, um die Daten für alle drei Graphen in drei verschiedenen Farben malen zu können.

Zeile 55 erzeugt anschließend ein neues Imager-Objekt, das später die gewünschte Grafikdatei erzeugt. Zuerst füllt die Methode »box()« den Bildhintergrund weiß aus, dann zeichnet »Render()« das Koordinatensystem, die Beschriftung und schließlich auch die drei Graphen in einem Rutsch. Die Methode »write()« schreibt die Ausgabedatei im PNG-Format auf die Festplatte.

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Perl-Snapshot

    Was harmlos mit ein paar sonderbaren Katzenbildern begann, ist zu dem Internetphänomen schlechthin angeschwollen: Memes, mit Witztexten versehene Fotos, und animierte Gag-Gifs. Kein Witz: Mit Perl lassen die sich prima selbst bauen und individuell gestalten.

  • Foto-Labor

    Gimp, das GNU Image Manipulation Program, verbessert und manipuliert digitale Bilder mit anspruchsvollen Filterfunktionen. Statt immer wieder die gleichen Manöver mit der Maus auszuführen, lassen sich die Vorgänge mit Gimps Perl-Schnittstelle sogar automatisieren.

  • Farbenspiel

    Oft benötigen ganze Serien digitaler Bilder dieselben Korrekturen, was den Fotografen zu immer gleichen Schritten in Gimp zwingt. Viel bequemer kommt zum Ziel, wer die Retusche automatisiert.

  • Alter geht vor Schönheit

    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.

  • Zufall unter Beobachtung

    In manchen Firmen laufen die Mitarbeiter mit Secur-ID-Tokens der Firma RSA Security herum. Das kleine Authentisierungsgerät berechnet und zeigt jede Minute eine Ziffernkombination, die beim Einloggen temporär gültig ist. Eine mit Perl gestrickte Zeichenerkennung schaut dem Schlüsselgenerator beim Zocken zu.

comments powered by Disqus

Ausgabe 09/2017

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.