Webworker Processing II
Mit Processing erstellen Sie mit ein paar Zeilen Code spannende Grafiken und Animationen. In diesem zweiten Teil geht es darum, Bilder einzubinden und zu manipulieren.
In der letzten Ausgabe gab es eine Einführung in die Arbeit mit Processing ( proces sing.org). In diesem Artikel schauen wir uns an, was sich innerhalb von Processing mit Bildern anstellen lässt. Als erstes sorgen wir einfach nur dafür, dass ein Bild geladen und angezeigt wird. Geeignete (und lizenzfreie) Bilder finden Sie zum Beispiel auf unsplash.com. Öffnen Sie einen neuen Sketch und speichern diesen. Processing legt dabei einen neuen Order mit einer entsprechenden .pde-Datei an. In diesem Ordner erzeugen Sie einen weiteren Ordner mit dem Namen data. In den data- Ordner gehören gemäß Dokumentation alle Ressourcen, mit denen Sie innerhalb des Sketches arbeiten möchten, also Bilder, Audio-Dateien oder Fonts. Wir handhaben das ebenso (allerdings wird Processing Ihre Bilder auch einlesen, wenn sich diese auf derselben Ebene wie die .pde-Datei befinden). Nehmen wir an, das Bild heißt beispiel.jpg. Dann binden Sie das Bild mit folgendem Code ein: In der ersten Zeile sehen wir ein Objekt img vom Datentyp PImage vor. Dieser Typ ist dafür gedacht, Bilder zu speichern. Der Datentyp bzw. die Klasse PImage bringt ein paar nützliche Methoden und Felder mit,
um mit dem Bild zu arbeiten. Im setup() wird das Bild beispiel.jpg (das im Ordner data liegen sollte) via loadImage() in das Objekt img geladen. Mit image() wird dieses Objekt an der Position x,y ausgegeben. Im Beispiel wird die linke, obere Ecke des Bildes also an die linke, obere Ecke des Ausgabefensters gesetzt. Wenn das Bild andere Maße als 400×400 Pixel hat, wird es entsprechend abgeschnitten, oder es füllt das Ausgabefenster nicht ganz aus. Sie können das Bild auch skaliert anzeigen, indem Sie die Breite und Höhe vorgeben: Das Laden der Bilder ist eine langsame Angelegenheit. Sie sollten das für jedes Bild nur einmal erledigen, innerhalb des setup(). Falls Sie Bilder innerhalb der draw()Methode laden, kann es passieren, dass das Programm langsamer abläuft oder „Out of Memory“-Fehler erzeugt. Processing versteht die Bildformate gif, jpg, png und tga (Targa Image File).
Einfache Manipulationen
Wie erwähnt, bringt die Klasse PImage einige Methoden mit, die wir nutzen können, um das Bild zu manipulieren. Zum Beispiel können wir Masken, Blenden und Filter einsetzen. Schauen wir uns ein paar Filter an. Ändern Sie das setup() wie folgt: Das Programm arbeitet nun etwas länger, bis das Bild zu sehen ist. Dafür erscheint es etwas verschwommen. Sie können einige andere Filter ausprobieren: Eine Liste aller verfügbaren Filter finden Sie unter bit.ly/2m32ZMN.
Pixelbasierte Änderungen
Nachdem Sie ein Bild in das Objekt img geladen haben, können Sie mit der Methode loadPixels() alle Farbwerte der einzelnen Pixel in ein Array img.pixels[] laden. Das Array enthält dabei der Reihe nach alle Pixel, Zeile für Zeile aneinander gereiht. Aus dem zweidimensionalen Bild wird so ein eindimensionales Array. Für jeden Pixel können wir die Farbwerte Rot, Grün und Blau des RGB-Farbraums auslesen. Wir können nun sämtliche Rot-Werte auf Null setzen:
Hier laden wir mit loadPixels() die aktuellen Pixel des Objekts img in das Array img. pixels[]. Dieses Array gehen wir der Reihe nach durch, von 0 bis zum Ende img. pixels. length. Für jede Position loc lesen wir die aktuellen Werte der Farben Rot r, Grün g und Blau b aus. Dann besetzen wir das Pixel neu. Wir übernehmen die Werte für g und b. Aber den Rot-Anteil r setzen wir auf 0. Damit die Änderungen übernommen werden, müssen wir das Bild via updatePixels() einmal aktualisieren. In der Ausgabe erscheint nun das manipulierte Bild. Genau genommen würde dieses Beispiel auch ohne updatePixels() funktionieren, aber Sie sollten loadPixels() zusammen mit updatePixels() nutzen, um Fehler zu vermeiden.
Pointillism
Wir können das Pixel-Array für einen netten Effekt nutzen. Im folgenden Programm Pointillism von Daniel Shiffman laden wir zunächst ein Bild. Anstatt aber das Bild anzuzeigen, malen wir in jedem Durchgang der Methode draw() einen halbtransparenten Kreis an einem zufälligen Punkt. Als Farbe des Kreises wählen wir die Farbe des ursprünglichen Bildes an diesem Punkt.
Dieser Ansatz lässt sich noch weiter ausarbeiten, siehe Infobox.
Glitch Art
Zum Schluss versuchen wir uns an einem einfachen Beispiel für Glitch Art. Das heißt, wir sorgen für ein paar digitale Fehler in einem Bild und hoffen, dass das Ergebnis für einen interessanten Effekt sorgt. In diesem Fall laden wir das Bild im HSB-Farbraum, suchen zufällige Koordinaten für ein verzerrtes Rechteck und verschieben die Farben innerhalb dieses Rechtecks. Im setup() wechseln wir in den HSB-Farbraum, alle drei Parameter ( h, s, b) können Werte zwischen 0 und 255 annehmen. Wir reduzieren die Framerate auf einen Durchgang pro Sekunde, um die Änderungen besser zu sehen. In jedem Durchlauf der Methode draw() suchen wir Start- und Endpunkte in der Horizontalen und Vertikalen für ein zufälliges Rechteck innerhalb unseres Bildes. Wenn wir im Code loc = j*img. width+i verwenden, ergeben sich echte Rechtecke. Das ist etwas langweilig. Wenn wir statt der echten Breite des Bildes etwas mehr oder etwas weniger nehmen, ergeben sich effektiv verzerrte Rechtecke bzw. Parallelogramme. Dann gehen wir alle Punkte in dem Parallelogramm durch und ändern jede Farbe um denselben Wert auf dem HSB-Farbkreis. Da der Wert für Hue größer als 255 werden kann, sorgen wir dafür, dass wir wieder vorne anfangen und ziehen, wenn nötig, 256 ab. Nun müssen wir nur noch das Bild updaten und ausgeben. Abhängig von den Farben im Ausgangsbild kann es sich anbieten, die Werte etwas zu verändern oder aber im üblichen RGB-Farbraum zu arbeiten. Weiterer Beispiele und Inspirationen für eigene Bildmanipulationen finden Sie auf openprocessing.org. Im nächsten Teil der Serie schauen wir uns an, was wir auf Basis von Zufall und Rauschen basteln können.