Aktivität im Bild feststellen in Processing

Hinzugefügt am von Steffen Fiedler
Video Aktivität erkennen
Um Bewegung in einer Bildreihe zu erkennen, müssen diese nach Veränderungen durchsucht werden. D.h. man vergleicht das aktuell von der Kamera gelieferte Bild mit den vorher aufgenommenen. Wenn sich Pixel bzw. Abschnitt merklich in ihrem Farbton verändert haben, liegt eine Aktivität vor der Kamera vor. Wie in vorherigen Beispielen testen wir diese Form der Änderung indem wir die Summen der RGB Kanäle vom aktuellen und vergangenen Bildern ermitteln und vergleichen. Die in der Vergangenheit aufgenommenen Bilder speichern wir daher nicht in Form eines PImage, sondern als float array (beinhaltet die Summe der RGB-Farbwerte pro Pixel). Betitelt mit den Namen buffer1, buffer2 und buffer3 werden die letzten drei Bilder abgelegt. Der Mittelwert dieser geht in den Vergleich mit dem aktuellen ein, als Fehlerkorrektur bei rauschenden Kameras. Stärke der Änderung in Graustufen
Video Aktivität erkennen
Eine kleine Veränderung im Programm macht die Stärke der Änderung sichtbar. Je weiter entfernt die beiden verglichenen Farbwerte sind, umso großer bzw. kleiner ist der Wert von deltaPixel. Dieser in der color() Funktion verwendet macht die Aktivität in Graustufen sichtbar. Alle Änderungen mit einem negativen Wert werden dabei schwarz repräsentiert. Um diese Abschnitte ebenfalls in feinen Abstufungen darzustellen bedarf es einer if-Abfrage. Innerhalb wird das Vorzeichen umkehrt wenn deltaPixel kleiner als 0 ist(im Code ausgeklammert).
if (deltaPixel > threshold || deltaPixel < -threshold) {
        
  /* Wenn die Differenz kleiner als 0 ist, 
    * kehre das Vorzeichen um. Dadurch werden 
    * die schwarzen Stellen vermieden.
    */
  //if (deltaPixel < 0) {
  // deltaPixel = deltaPixel * -1;
  //}

  pixels[i] = color (deltaPixel);
}

Der Sketch

import processing.video.*;

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

// Bildergedächtnis zum Ablegen der letzen 
// drei Videobilder. Diese bilden die Grundlage 
// für das Erkennen der Aktivität vor der Kamera.
float[] buffer1 = new float[VIDEO_WIDTH * VIDEO_HEIGHT];
float[] buffer2 = new float[buffer1.length];
float[] buffer3 = new float[buffer1.length];

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

// Schnittstelle zur Kamera
Capture cam;

void setup () {
  size (VIDEO_WIDTH, VIDEO_HEIGHT);
  // Da die Videokamera keine 60 Bilder pro Sekunde liefert,
  // kann die Framerate des sketches auf 15 angepasst werden.
  // Framerate von Kamera und Sketch sind damit gleich.
  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 ();
    
    // Gehe durch jedes Pixel im Bild und Vergleiche
    // den Farbwert an dieser Position mit den Farbwerten 
    // in der Vergangenheit (siehe buffer 1-3).
    for (int i=0; i < cam.pixels.length; i++) {

      // Farbe an der Position 'i' im Kamerabild
      color col = cam.pixels[i];
      // Die Summe aus allen drei Farbkanälen bilden
      float sum = red (col) + green (col) + blue (col);

      // Die mögliche Bewegung an dieser Position im Kamerabild 
      // wird durch das Vergleichen der Farbwerte praktiziert. 
      // Dabei werden die letzten drei Bilder und das aktuelle 
      // einbezogen.
      float deltaPixel = (buffer1[i] + buffer2[i] + buffer3[i]) / 3 - sum;

      // Falls sich der Farbwert über die festgelegte Grenze 
      // geändert hat, färbe das Pixel weiß ein. Anderefalls 
      // zeichne es nicht (bleibt als Hintergrund eingefärbt).
      if (deltaPixel > threshold || deltaPixel < -threshold) {
        pixels[i] = color (255);
      }

      // Verschiebe das 'Bildgedächnis' um einen Rutsch nach hinten.
      // Überschreibe das älteste Bild (buffer3) und rücke die  beiden 
      // anderen um eine Stelle nach hinten. Das aktuelle Bild wird in 
      // 'buffer1' abgelegt. (Dies passiert Pixel für Pixel!)
      buffer3[i] = buffer2[i];
      buffer2[i] = buffer1[i];
      buffer1[i] = sum;
    }
    
    updatePixels ();
  }
}