Simpler Green-Screen in Processing

Hinzugefügt am von Steffen Fiedler
Video Hintergrund entfernen
Unter einem green- bzw. bluescreen versteht man die Art und Weise Videoaufnahmen vor einer einfarbigen grünen oder blauen Fläche aufzunehmen, welche es ermöglicht Objekte vor der Fläche freizustellen. Dabei wird jeder in diesem Ton eingefärbte Bildpunkt des Videos als transparent angesehen. Die Grundlage für eine Umsetzung des Prinzips in Processing haben wir schon im Beispiel simpler Farbfilter gelegt. Jedoch benötigen wir den speziellen Hintergrund für die Aufnahme.

In diesem Beispiel wird ein Weg vorgestellt diesen Effekt mit jeglichem Hintergrund zu erzielen. Dabei nutzen wir nicht eine standardisierte Farbe als Hintergrund, sondern bedienen uns eines vorher aufgenommenen Bildes. Das Bild steht in diesem Fall für den zu entfernenden Hintergrund. Nach dem Starten des Processing Programms wird es durch das Drücken der Taste 'b' aufgenommen und mit der Funktion get() in der Variable back abgelegt. Wie in den vorherigen Beispielen durchlaufen wir im draw-Block jedes einzelne Pixel des Kamerabildes und vergleichen dabei den Farbwert mit dem Hintergrundbild back. Wenn eine Änderung üben den Schwellwert threshold vorliegt wird dieses Pixel im Sketchfenster abgebildet. Anderenfalls ist an dieser Stelle nur der graue Hintergrund sichtbar. Bei der Ermittlung der Farbwerte bilden wird die Summe aus allen drei Farbkanälen und vergleichen diese. Eine präzisere Lösung wäre jeden Kanal einzeln abzufragen und zu vergleichen. Grundsätzlich gilt: Je besser die Szene ausgeläuchtet ist, umso genauer die Freistellung.

Der Sketch

import processing.video.*;

// Video-Aufnahme-Auflösung
final int VIDEO_WIDTH  = 320;
final int VIDEO_HEIGHT = 240;

// Variable zum Speichern des Hintergrundbildes.
PImage back = null;

// Wert um den sich die Summe der RGB Kanäle mind. ändern 
// muss, damit das Pixel als 'aktiv' erkannt wird. 
float threshold = 50;

// Objekt zum Zugriff auf die angeschlossene Kamera.
Capture cam = null;

void setup () {
  size (VIDEO_WIDTH, VIDEO_HEIGHT);
  // Initialisiert die Verbindung zur Kamera und 
  // gleicht die frame rate von Kamera und Sketch an.
  cam = new Capture (this, VIDEO_WIDTH, VIDEO_HEIGHT, 15);
  frameRate (15);
}

void draw () {

  // Wenn die Videokamrea verfügbar ist
  if (cam.available ()) {
    
    // Auslesen des Kamerabildes und
    // füllen des Hintergrunds mit grau
    cam.read ();
    background (40);

    // Alle Pixel vom Sketchfenster für die 
    // spätere Bearbeitung laden.
    loadPixels ();

    // Wenn ein Hintergrundbild aufgenommen wurde.
    if (back != null) {

      // Für jedes Pixel in der Zeichenfläche
      for (int i=0; i < cam.pixels.length; i++) {

        // Farbe an der Position 'i' im Kamerabild
        // und im Hintergrundbild auslesen
        color c1 = cam.pixels[i];
        color c2 = back.pixels[i];

        // Die Summe aus allen drei Farbkanälen bilden
        float s1 = red (c1) + green (c1) + blue (c1);
        float s2 = red (c2) + green (c2) + blue (c2);

        // Unterschied zwischen Hintergrundbild und Kamerabild
        // errechnen für dieses Pixel.
        float deltaPixel = s1 - s2;

        // Hat sich dieses Pixel mind. um unseren Schwellenwert 
        // geändert? Wenn ja – zeichne das Pixel aus dem 
        // Kamerabild an diese Position.
        if (deltaPixel > threshold || deltaPixel < -threshold) {
          pixels[i] = cam.pixels[i];
        }
      }
    }

    // Aktualisiere das Sketchfenster mit dem Bild 
    // aus dem von uns modifizierten 'pixels' Array.
    updatePixels ();
  }
}

void keyReleased () {
  // Beim Drücken der Taste 'b' wird das Hintergrundbild 
  // im Speicher durch die Variable 'back' abgelegt. Dieses 
  // gilt als Referenz für unseren "blue screen".
  if (key == 'b' || key == 'B') {
    back = cam.get ();
  }
}