Pinball-Bewegungssteuerung

Aus toolbox_interaktion
Wechseln zu: Navigation, Suche

In diesem Projekt wird die Steuerung eines Pinball-Spiels mit Hilfe einer eingebauten/angeschlossenen Webcam beschrieben.

Projektbeschreibung

Für das Pinball Spiel wurde die OpenSource Software Visual Pinball(VP) genutzt. Die Steuerung des Spiels soll über Gesten geschehen. Die Steuerungselemente sind die Flipperhebel, der Plunger (Federelement zum Abschießen der Kugel) und das Stoßen von den Seiten. Das betätigen der Flipperhebel soll über die Hände, das seitliche Stoßen über die Füße und der Plunger über die Körperhaltung gesteuert werden.

Bildvearbeitung

Die Bildbearbeitung benutzt die interne oder eine angeschlossene Webcam. Hierzu wird openFrameworks mit dem openCV-Plugin ofxCv benutzt.

Hintergrund-Subtraktion

Durch Drücken der Leertaste kann der aktuelle Frame abgespeichert werden. Dieser wird dann für die Hintergrund-Subtraktion verwendet. Mit "toCv()" wird der Hintergrund-Frame und der jeweils aktuelle Kamera-Frame in ein "cv::Mat" umgewandelt, damit openCv-Funktionen verwendet werden können. Danach wird vom aktuellen Kamera-Frame das abgespeicherte Hintergrundbild abgezogen:

cvImage = toCv(cam);
cvPrev = toCv(previous);
cvDiff = cvImage - cvPrev;

Regions of Interest

Als nächstes werden 5 Regions of Interest auf die hintergrund-subtrahierte Bild angewendet: Links und rechts oben, jeweils für den linken und rechten Flipper. Links und rechts unten, jeweils für das Stoßen gegen den Flipperautomaten. In der Mitte oben für das Abfeuern des Balls.

Mat roiLeftTC = cvDiff(roiUpperLeft);
Mat roiLeftSC = cvDiff(roiLowerLeft);
Mat roiRightTC = cvDiff(roiUpperRight);
Mat roiRightSC = cvDiff(roiLowerRight);
Mat roiSBC = cvDiff(roiHead);

In der cvDiff-Funktion wird der Bereich für die Region of Interest als cv::Rect übergeben. Diese wurden vorher in der ofApp.h-Header Datei definiert.

cv::Rect roiUpperRight = cv::Rect(0, 0, 200, 240);
cv::Rect roiLowerRight = cv::Rect(0, 300, 200, 180);
cv::Rect roiUpperLeft = cv::Rect(639 - 200, 0, 200, 240);
cv::Rect roiLowerLeft = cv::Rect(639 - 200, 300, 200, 180);
cv::Rect roiHead = cv::Rect(219, 0, 200, 240);

Binarisierung

Weiter erfolgt eine Binarisierung um das Bild später besser auswerten zu können. Hierfür werden die Regions of Interest zu Schwarz/Weiß konvertiert. Und danach mit Hilfe eines Schwellwerts die einzelnen Pixel entweder auf 0 oder auf 255 gesetzt.

cvtColor(roiLeftSC, roiLeftShake, CV_BGR2GRAY);
cvtColor(roiLeftTC, roiLeftTrigger, CV_BGR2GRAY);
cvtColor(roiRightSC, roiRightShake, CV_BGR2GRAY);
cvtColor(roiRightTC, roiRightTrigger, CV_BGR2GRAY);
cvtColor(roiSBC, roiShootBall, CV_BGR2GRAY);

threshold(roiLeftTrigger, roiLeftTrigger, thresh, 255, THRESH_BINARY);
threshold(roiLeftShake, roiLeftShake, thresh, 255, THRESH_BINARY);
threshold(roiRightTrigger, roiRightTrigger, thresh, 255, THRESH_BINARY);
threshold(roiRightShake, roiRightShake, thresh, 255, THRESH_BINARY);
threshold(roiShootBall, roiShootBall, thresh, 255, THRESH_BINARY);

Auswertung

Als letzter Schritt wird noch gezählt wie viele Pixel nicht 0 sind. Da immer noch ein paar falsch erkannte Pixel dabei sind. Ist diese Anzahl größer als ein festgelegter Wert wird eine OSC Nachricht gesendet. m ist dabei ein Objekt vom Typ ofxOscMessage. Mit der Funktion addIntArg(int i) wird der OSC Message ein zu übertragender Wert hinzugefügt.

if (countNonZero(roiLeftTrigger) > pixel_cnt) {
    // send LeftTrigger signal
    m.addIntArg(leftFlipper);
    printf("LeftTrigger\n");
}
if (countNonZero(roiRightTrigger) > pixel_cnt) {
    // send RightTrigger signal
    m.addIntArg(rightFlipper);
    printf("RightTrigger\n");
}
if (countNonZero(roiLeftShake) > pixel_cnt) {
    // send LeftShake signal
    m.addIntArg(leftKicker);
    printf("LeftShake\n");
}
if (countNonZero(roiRightShake) > pixel_cnt) {
    // send RightShake signal
    m.addIntArg(leftKicker);
    printf("RightShake\n");
}
if (countNonZero(roiShootBall) < pixel_cnt) {
    // send Trigger Ball signal
    m.addIntArg(starter);
    printf("Ball\n");
}

OSC Schnittstelle

mit Hilfe des OSC Protokolls wird zwischen 2 Laptops Daten übertragen. Dabei ist einmal (Laptop Win7) in der Bilverarbeitungssoftware ein OSC Sender integriert, der OSC Messages an einen Teilnehmer im Netz sendet und zwar mit Port 12345. Die Adresse des OSC Protokolls ist dabei einfach gehalten. Sie heißt /testaufbafu. Auf dem zweiten Rechner (Laptop Win10) ist ein OSC Receiver in Betrieb, der auf Nachrichten am Port 12345 lauscht und verarbeiten kann. Pinball HW-SW-Verteilung.png

Integration in Visual Pinball

Die Integration in VP gestaltete sich wesentlich schwieriger als zunächst gedacht. Das OpenSource Projekt VP ist ein Visual Studio Projekt und sollte daher auch mit eben diesem bearbeitet werden. Der Funktionsumfang von Visual Studio Express reichte jedoch nicht für VP, sodass die Community Edition genutzt werden musste (siehe Versionen von Visual Studio). Zur Zeit des Praktikums war die Version 2015 die aktuellste. Diese wurde auch genutzt. In der Version 9.9.1 von VP wird das Microsoft DirectX SDK (August 2007) vorausgesetzt. Dieses ist in dieser Form jedoch nicht mehr zum Download verfügbar. In der neueren Version (June 2010) fehlt jedoch "dinput8.lib", das damals noch beim SDK dabei war und bei VP genutzt wird. Die Version June 2010 liegt im Content Service zum Download bereit. Dieses Problem wurde dadurch gelöst, dass das vorhandene "dinput.lib" kopiert und umbenannt wurde. Dies hatte wenige Änderungen im Source Code zur Folge, damit erfolgreich übersetzt werden konnte. Siehe Pinball Projekt (main.h Z.34ff, pininput.cpp Z.545ff Z.609ff). Ausserdem benötigt VP 9.9.1 die Active Template Library (ATL) von Visual Studio (liegt im Content Service) und ein Windows Development Kit (benötigte Files liegen im Content Server).

Die Installation vom openFrameworks Plugin für Visual Studio hat reibungslos geklappt. Auch die mitgelieferten Beispielprogramme funktionierten reibungslos. Das Einbinden in das Projekt VP war nicht ohne Weiteres möglich, sodass die Implementierung des OSC Receiver in VP aufgrund von Zeitmangel nicht realisiert werden konnte. Für die korrekte Ausführung der ausführbaren Datei sind noch die DLLs FreeImage.dll und SciLexer.dll notwendig.

Systemkonfiguration

Für die Bildverarbeitung und den OSC Sender und Receiver wurden CodeBlocks 12.11 mit openFrameworks 0.8.4 verwendet. Für das Pinball Projekt wurde mit Visual Studio 2015 Community Edition und dem openFrameworks plugin gearbeitet.

Downloads

CodeBlocks Projekt für die Bildverarbeitung und den OSC Sender

VP Projekt