Processing Workshop | Teil 3 | Pixeldaten verarbeiten und Arrays

Markus Walthert

Bild- und Pixeloperationen
Bilder können in mit loadImage() geladen und im PImage Objekt weiter verarbeitet werden. Neben dem einfachen Darstellen des Bildes kann man auch Pixel um Pixel verändern, ähnlich einem Photoshopfilter.
Manfred-pecki in Processing Workshop | Teil 3 | Pixeldaten verarbeiten und Arrays
Dieses Bild von Manfred Pecki besteht aus verschiedenen Grauwerten. Ich will das Bild in ein reines schwarz/weiß Bild verwandeln. Um zu entscheiden, ob ein Pixel in weiß umgewandelt werden soll, analysiere ich seine Grauwert. Liegt es innerhalb eines bestimmten Grenzwertes (myThreshold), wird es weiß, ansonsten schwarz (Farbwert: 255).

Dieser Grenzwert ist in diesem Beispiel dynamisch an die X-Position des Mauszeigers gekoppelt und gibt einen Wert zwischen 0 und 255 aus
float myThreshold = (float)mouseX / width * 255;

Nachdem das Bild geladen ist
myImage = loadImage("data/manfred-pecki.png");
und als Hintergrundbild wiedergegeben ist
background(myImage);

kann ich mit loadPixels() jedes einzelne Pixel meiner Anwendung in einem Array zur Verfügung stellen, verändern und dieses veränderte Pixel mit updatePixels() neu auf die Screen rendern.

Das passiert alles in der draw() Methode in einer for-Schleife, die genau so lang ist wie das Bild Pixel hat. Diese Länge erhalte ich in einem Array mit pixels.length. Bei welchem Pixel ich mich gerade befinde sagt mir der Zähler myPixelPosition.

In jedem Schleifendurchlauf wird die Funbktion setPixelFromBitmap() aufgerufen, die entscheidet ob ein Pixel weiß oder schwarz werden soll.
Ist die Schleife abgearbeitet, wird das Ergebnis mit updatePixels(); auf die Screen gerendert.

Hier wird auch deutlich, das die Länge und Breite des Bildes für die Verarbeitung keine Rolle spielt, sondern das Bild einfach eine lineare Aneinanderreihung von einzelnen Pixeln ist.
Pixelreihe-340x135 in Processing Workshop | Teil 3 | Pixeldaten verarbeiten und Arrays

Um diesen Prozess auch visuell wahrzunehmen, können wir die Schleife dahingehend ändern, nicht das gesamte Bild je Renderzyklus in draw() zu verändern, sondern entweder Zeilenweise
for (int i=0; i < width; i++) {
oder Pixelweise
for (int i=0; i < 1; i++) {

Um dieses Beispiel anzuzeigen bitt auf das Vorschaubild klicken!

PImage myImage;
 
int myPixelPosition;
 
void setup() {
  size(176,247);//Screnn in der Größe des importieren Bildes
  frameRate(60);
 // myImage = loadImage("http://ifdblog.org/ba-om2010/data_processingblog");
  myImage = loadImage("data/manfred-pecki.png");
  background(myImage);
}
void draw() {
  /* lädt die komplette Screen in den Array pixels[] von myImage */
  loadPixels();
 
  /* den "Schwellwert" festlegen
  *  Operation ergibt einen Wert von 0 - 255
  */
  float myThreshold = (float)mouseX / width * 255;
 
  for (int i=0; i &lt; pixels.length; i++) {
    setPixelFromBitmap(myThreshold);
    /*
    * Inkrement von myPixelPosition und mit dem *Modulo* wird
    * garantierrt, dass der Array in seinen Grenzen bleibt
    */
    myPixelPosition++;
    myPixelPosition%= pixels.length;
  }
  /* alle Pixels darstellen */
  updatePixels();
}
 
void setPixelFromBitmap(float theThreshold) {
  /*
  * das aktuelle Pixel abfragen
  * myPixePosition ist global definiert und kann deshalb überall verwendet werden
  */
  int myImagePixel = myImage.pixels[myPixelPosition];
 
  /*
  * Abfrage, ob aktuelle Pixel größer oder kleiner ist als der Schwellwert...
  * entsprechend wird der Farbwert invertiert
  */
  if (brightness(myImagePixel) &lt; theThreshold) {
    pixels[myPixelPosition] = color(0);
  }
  else {
    pixels[myPixelPosition] = color(255);
  }
}

Modulo
Der Modulo gibt mir den Rest einer Division zurück.
5 Modulo 2 = 1
5 % 2 = 1

Damit kann ich einen Zähler erstellen, der nie über einen Bestimmten Wert wächst und einen Array out of Bounds Fehler produziert, also einen Arrayindex abfragt der größer wäre als der Arry tatsächlich ist:
myPixelPosition%= pixels.length;
wo_befinde_ich_mich_im_array %= gesamtlänge_des_arrays

int[] myArray;
int myArrayPosition;
void setup() {
  size(320, 240);
  frameRate(5);
  rectMode(CENTER);
 
  myArray = new int[]{
    40, 80, 120, 160, 200, 240, 280  };
}
void draw() {
  background(255);
  myArrayPosition++;
  myArrayPosition %= myArray.length;
  println(myArrayPosition);
  rect(myArray[myArrayPosition], height / 2, 40, height / 2);
}