Interaction Design WikiComputer Vision

OpenCV

In diesem Tutorial werden wir uns mit OpenCV beschäftigen. OpenCV (Wikipedia) ist eine Sammlung von Computer Vision Algorithmen, welche von Intel initiiert wurde. Sie beinhaltet einige interessante Funktionen, welche wir uns zu Nutze machen können. Dazu gehören neben den schon gelernten Funktionen (Background Subtraction, Brightest Point) auch Funktionen zum erkennen von Gesichtern oder dem Hervorheben von Kanten in einem Bild.

Die von uns genutzte Implementierung von OpenCV wurde von Greg Bordstein extra für Processing adaptiert. Sie bietet nicht die komplette Vielfalt der Möglichkeiten mit OpenCV, ist aber ein guter Startpunkt und für die meisten Projekte mehr als ausreichend.

Die Library gibt es hier als Download: OpenCV for Processing (Referenz der Funktionen).

Getting Started

Die grundlegende Struktur von OpenCV for Processing ist sehr einfach.

Zuerst müssen wir die Library importieren:

import gab.opencv.*;

Dann können wir ein OpenCV Steuerobjekt deklarieren:

OpenCV opencv;

Welches wir in der setup() Funktion initialisieren können:

opencv = new OpenCV(this, width, height);

Bild an OpenCV übergeben:

opencv.loadImage(video);

OpenCV Funktionen ausführen:

opencv.updateBackground();

Eine grosse Anzahl von Beispielen kommt mit der Library und es wird empfohlen sich diese einmal genauer anzusehen. In den folgenden Beispielen werden die vier wichtigsten Funktionen der Library vorgestellt.

Background Subtraction

Folgendes Beispiel zeigt, wie ein Hintergrundbild mit einem Vordergrundbild verglichen wird. Dazu übergeben wir im setup() nach der Initialisierung der Library mit dem Befehl opencv.startBackgroundSubtraction(5, 3, 0.5); drei Parameter.

Im draw() lesen wir zunächst unser Video-Bild ein und übergeben dieses dann an OpenCV opencv.loadImage(video);. Mit dem Befehl opencv.updateBackground(); sagen wir OpenCV, dass der Hintergrund aktualisiert werden soll und nehmen die Funktionen opencv.dilate(); und opencv.erode(); um etwaige Löcher in der Erkennung zu schliessen. Schliesslich lassen wir uns alle gefundenen Konturen (Bewegung) darstellen:

for (Contour contour : opencv.findContours()) {
  contour.draw();
}

Alle Regionen, welche auf dem folgenden Bild in Rot dargestellt sind, haben sich in den letzten Frames verändert.

Beispiel Expand source
import gab.opencv.*;
import processing.video.*;

OpenCV opencv;
Capture video;

void setup() {
  size(640, 480);
  video = new Capture(this, width, height, 30);
  opencv = new OpenCV(this, width, height);
  
  opencv.startBackgroundSubtraction(5, 3, 0.5);
  video.start();
}

void draw() {
  background(255);
  
  if (video.available()) {
    video.read();
  }
  
  // image(video, 0, 0);  
  opencv.loadImage(video); 
  opencv.updateBackground();
  
  opencv.dilate();
  opencv.erode();
  
  fill(255, 0, 0);
  noStroke();
  
  for (Contour contour : opencv.findContours()) {
    contour.draw();
  }
}

Brightest Point

Mit OpenCV können wir sehr einfach auf diese Methode zugreifen. Dazu rufen wir die Funktion PVector loc = opencv.max(); welche uns direkt einen PVector mit den Koordinaten des hellsten Punktes zurückgibt. In gleicher Weise können wir auch die Koordinaten des dunkelsten Punktes finden PVector loc = opencv.min();.

Beispiel Expand source
import gab.opencv.*;
import processing.video.*;

OpenCV opencv;
Capture video;

void setup() {
  size(640, 480);
  video = new Capture(this, width, height, 30);
  opencv = new OpenCV(this, width, height);
  
  video.start(); 
}

void draw() {
  if (video.available()) {
    video.read();
  }
  
  // image(video, 0, 0); 
  opencv.loadImage(video);
  
  image(opencv.getOutput(), 0, 0); 
  PVector loc = opencv.max();
  
  fill(255, 0, 0);
  noStroke();
  
  ellipse(loc.x, loc.y, 50, 50);
}

Face Detection

Eine sehr interessante Methode in OpenCV ist das sog. Face Detection. Mit dieser Funktion können wir Gesichter in einem Bild erkennen.

Im setup() müssen wir OpenCV zunächst ein sog. Haar-Cascade übergeben. Dieses bestimmt, nach welchen Mustern (Gesicht, Mund, Nase, Körper, usw.) der Algorithmus suchen soll:

opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);

Die folgenden Funktion gibt uns ein Array vom Typ Rectangle zurück. Diese Rechtecke beschreiben die Bereiche im Bild, an welchen ein Gesicht erkannt wurde. Um die Rechtecke zu zeichnen iterieren wir durch das Array und stellen die Rechtecke dar.

faces = opencv.detect();

Mit einer Schlaufe können wir diese dann durchgehen:

for (int i = 0; i < faces.length; i++) {
  rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
}
Beispiel Expand source
import gab.opencv.*;
import java.awt.Rectangle;
import processing.video.*;

OpenCV opencv;
Rectangle[] faces;
Capture video;

void setup() {
  size(640, 480);
  video = new Capture(this, width, height, 30);
  opencv = new OpenCV(this, width, height);

  opencv.loadCascade(OpenCV.CASCADE_FRONTALFACE);  
  // CASCADE_CLOCK
  // CASCADE_NOSE
  // CASCADE_MOUTH
  // CASCADE_UPPERBODY
  // CASCADE_PROFILEFACE
  // CASCADE_EYE
  // CASCADE_PEDESTRIANS
  // ...
  
  video.start();
}

void draw() {
  if (video.available()) {
    video.read();
  }
  
  image(video, 0, 0);  
  opencv.loadImage(video); 
  faces = opencv.detect();

  noFill();
  stroke(0, 255, 0);
  strokeWeight(3);

  for (int i = 0; i < faces.length; i++) {
    rect(faces[i].x, faces[i].y, faces[i].width, faces[i].height);
  }
}

Region Of Interest

Eine weitere hilfreiche Funktion ist die Beschränkung von OpenCV auf einen bestimmten Bereich des Bildes. Dies ist immer dann hilfreich, wenn wir nur einen Teil des Bildes auf Veränderungen oder das Auftauchen von Gesichtern etc. überwachen wollen. Dazu benutzen wir die folgende Funktion:

opencv.setROI(mouseX, mouseY, roiWidth, roiHeight);

Diese gibt einen rechteckigen Bereich an, welcher für OpenCV verwendet werden soll.

Beispiel Expand source
import gab.opencv.*;
import processing.video.*;

OpenCV opencv;
Capture video;

int roiWidth = 150;
int roiHeight = 150;

boolean useROI = true;

void setup() {
  size(640, 480);
  video = new Capture(this, width, height, 30);
  opencv = new OpenCV(this, width, height);
  
  video.start(); 
}

void draw() {
  if (video.available()) {
    video.read();
  }
  
  // image(video, 0, 0); 
  opencv.loadImage(video);
  
  opencv.setROI(mouseX, mouseY, roiWidth, roiHeight);
  
  opencv.findCannyEdges(20,75);
  image(opencv.getOutput(), 0, 0);
}

Aufgaben

Weiteres