Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

projektesose20:eyetrackingspielpublic:start

Projektdokumentation Eyetracking Spiel

Link zu unserem Gitlab Repository: Gitlab

Sourcecode

Sourcecode für Fortgeschrittene

Einführung

Unsere Anwendung setzt sich aus zwei Teilen zusammen: Ein einfaches Spiel und ein Eye-Tracking-Programm. Das Spiel ist ein sowohl spiele mechanisch als auch optisch simpler “semi-prozeduraler” Side-Scroller, in dem man Hindernissen durch Springen und Ducken ausweichen muss. Kollidiert man mit einem Hindernis verliert man Gesundheit, bis man schließlich “stirbt”. Das Eyetracking-Programm ist der eigentliche Hauptteil unseres Projekts. Unser Programm funktioniert mit konventionellen Webcams und erkennt, ob der Nutzer nach links, rechts oder vorne schaut anhand der Position der Pupille relativ zum Gesicht.

Inspiriert wurden wir von einer bereits existierenden Eye-Tracking-Lösung der Firma Tobii (https://www.tobii.com), die unter anderem auch Produkte für das Eye-Tracking in Computerspielen verkauft (https://gaming.tobii.com/product/eye-tracker-5/). Leider sind deren Produkte aber sehr Teuer, die neueste Version des “Gaming-Eye-Trackers” Tobii Eye Tracker 5 kostet 229€. Unser Ziel war es Eye-Tracking umzusetzen, ohne dass dafür teure Hardware notwendig ist.

Umsetzung

Überblick über das Gesamtsystem

Programmiert haben wir unser Projekt in der auf Java basierenden Programmiersprache Processing. Zusätzlich haben wir die Bibliotheken “Video” und “OpenCV” erweitert. Video nutzen wir hauptsächlich um mit den Bildern der Webcam Arbeiten zu können. OpenCV ist eine Programmbibliothek mit Algorithmen zur Bildverarbeitung.

Wie bereits erwähnt, setzt sich unser Projekt aus zwei relativ eigenständigen Bestandteilen zusammen: Ein einfaches Spiel und ein Eye-Tracking-Algorithmus. Der größten Teil unserer Zeit haben wir an dem Eye-Tracking-Algorithmus gearbeitet. Die Grundlegenden Probleme, die hier zu lösen waren, sind das Erkennen der Augen im Gesicht des Nutzers, das Erkennen der Pupillen in den Augen und schließlich das Auswerten der Position der Pupillen relativ zum Auge bzw. Gesicht um zwischen den Blickrichtungen links, rechts und geradeaus unterscheiden zu können. In der von uns abgegeben Version des Eye-Tracking-Algorithmus haben wir für die ersten beiden dieser Teilaufgaben gut funktionierende Lösungen gefunden, sodass die Pupille des Nutzers zuverlässig erkannt wird. Was uns noch Probleme bereitet ist die zuverlässige Erkennung der Blickrichtung. Wir haben in der abgegebenen Version noch keine gute Methode zum Bestimmen eines Punktes im Gesicht mit dem die Position der Pupillen verglichen werden kann, um so die Blickrichtung zu erkennen. Eingaben für das Spiel erzeugen wir, indem wir einfach Tastatureingaben (Pfeiltaste nach Oben und Pfeiltaste nach Unten) mit Hilfe der Klasse Robot erzeugen, die dann vom Spiel erkannt werden und Springen und Ducken auslösen. Dieser Ansatz ermöglicht es, dass auch ohne Eye-Tracking nur über Tastatureingaben zu spielen.

Im Vergleich dazu war das Programmieren des Spiels relativ simpel. Hier mussten wir uns eigentlich nur grundsätzlich überlegen, welche Art von Spiel mit angemessenem Aufwand umsetzbar ist und gleichzeitig gut mit der geringen Anzahl unterschiedlicher Eingaben durch unser Eye-Tracking klarkommt. Wir haben uns hier bewusst dazu entschieden die Optik und den Feature-Umfang des Spiels relativ simpel zu halten umso mehr Zeit auf das Eye-Tracking verwenden zu können. Die größten hier zu lösenden Problemen waren die Kollisionserkennung zwischen dem Spiel und Objekten des Levels und die prozedurale Generierung des Levels.

Eyetracking

Augenerkennung

Unser erster Schritt auf dem Weg zu einem Eye-Tracking-Algorithmus war das Erkennen von Gesichtern und Augen. Da OpenCV hierfür bereits fertige Tools (Kaskaden) bereitstellt haben wir das recht schnell hinbekommen. Kaskaden sind recht kompliziert, im Wesentlichen erkennen sie Objekte an Hand von für diese Objekte typische Helligkeitsübergänge. Basierend darauf haben wir dann eine erste einfache Version unseres Spiels erstellt, in der man durch Zwinkern springen und so Hindernissen ausweichen kann. Der Ansatz war hier sehr simpel, denn wir haben einfach die Anzahl der erkannten Augen betrachtet. Zwinkert man, so wird das Auge nicht mehr erkannt, die Anzahl erkannter Augen reduziert sich auf unter zwei und ein Sprung wird ausgelöst.

Kaskaden

Nachdem wir jetzt angemessen zuverlässig die Augen des Nutzers erkennen konnten, mussten wir im nächsten Schritt eine Lösung zum Bestimmen der Position der Pupille im Auge finden. Da wir in der ersten einfachen Version unseres Spiels bereits positive Erfahrungen mit dem Nutzen von Kaskaden gemacht hatten, entschieden wir uns dazu eigenen Kaskaden zu trainieren, um die Augen auszuwerten und die Position der Pupille (links, rechts, mittig) zu erkennen. Dazu haben wir dann ein kleines Programm geschrieben, mit wir ca. 200 brauchbare Bilder von unseren Augen aufgenommen haben, um diese als Grundlage für das Trainieren der Kaskaden zu nutzen. Neben der immensen Rechenleistung und Zeit, die zum Berechnen der Kaskaden notwendig gewesen wäre, waren auch die ersten Zwischenergebnisse nicht vielversprechend. Im Nachhinein betrachtet, sind Kaskaden für diese Anwendung auch nicht wirklich geeignet. Sie funktionieren nach unserem Verständnis eher für das Erkennen grober Formen vor beliebigem Hintergrund und nicht so gut für das Erkennen eines speziellen Details vor einem festen Hintergrund. (Das Ergebnis des Kaskadentrainings ist in unseren Dateien nicht enthalten, da es völlig unbrauchbar ist.)

Abbildung 1: Zwischenergebnis der Kaskadenberechnung
Abbildung 2: Nahansicht der Konturerkennung

Pupillenerkennung

In der zweiten und finalen Version der Pupillenerkennung suchen wir in dem als Augen erkannten Bereich nach den dunkelsten Pixel. Eine fest im Programmcode festgelegte Anzahl (im Moment 100, dies kann durch die Anpassung der Variable pupilSize im Programmcode für bessere Ergebnisse Verbessert werden) an dunkelsten Pixeln wird schwarz eingefärbt, alle anderen Pixel werden weiß eingefärbt. Auf das dann entstandene Bild wird die OpenCV Konturenerkennung angewendet. Diese gibt ein Array an Konturen zurück. Aus der Breite/Höhe und den Mittelpunkten wird ein Kreis mit demselben Mittelpunkt und dem Radius (Breite+Höhe)/4 erstellt. Es wird die Differenz zwischen dem Abstand jedes Punktes zur Mitte und dem Radius berechnet. Diese Differenzen werden als Beträge aufsummiert und anschließend durch die Anzahl der Punkte geteilt. Der damit errechnete Wert gibt ein grobes Maß für die Rundheit der Kontur zurück. Dabei stehen große Werte für sehr unrunde Konturen und kleine Werte für runde Konturen. Das Programm geht davon aus, dass der rundeste der schwarzen Bereiche die Pupille ist. Um die Erkennungsrate weiter zu verbessern werden Konturen die größer und kleiner als ein im Programm angegebener Wert sind aussortiert.

Aktuelle Version des Eyetrackings
Abbildung 3: Abgabeversion des Eyetrackings

Bewegungserkennung

Die durch die Kaskaden erkannten Rechtecke um die Augen dienen als Referenzpunkt für die Pupillenerkennung. Die Variable threshold, gibt an wie weit nach rechts bzw links geschaut werden muss, damit eine Eingabe auf der Tastatur erfolgt. Um Fehler zu reduzieren, wird die Bewegungsrichtung doppelt bestimmt.

Spiel

Spiel
Abbildung 4: Abgabeversion des Spiels

In Anlehnung an das Chrome-Dino-Spiel haben wir uns dann für ein prozedural generierten Side-Scroller entschieden, da man hier nur zwei Eingaben (ducken und springen) braucht. Wir haben uns bewusst für ein Spiel entschieden, das präzise Eingaben in Echtzeit braucht, um so einen guten Benchmark für unseren Eye-Tracking-Algorithmus zu haben. Unser Spiel besteht aus einem Spieler, einer Menge an Hindernissen und Gravitations-Triggern. Der Spieler befindet sich an einer festen Position im sichtbaren Bild und die anderen Objekte des Spiels bewegen sich vom rechten zum linken Bildrand, um so die Illusion einer Vorwärtsbewegung des Spielers zu erzeugen. In der rechten oberen Ecke sieht man die Health-Bar des Spiels, sie zeigt an wie “gesund” der Spieler ist. Der Spieler regeneriert während die seine Gesundheit nicht null ist kontinuierlich Leben. Kollidiert der Spieler mit einem Hindernis werden ihm Leben abgezogen. Kollidiert der Spieler hingegen mit einem Gravitations-Trigger wird die Gravitation des Levels umgepolt, der Spieler läuft also auf an der Decke und die Eingaben für Springen und Ducken werden vertauscht. In der linken oberen Ecke des Spiels wird der aktuelle Score angezeigt, der kontinuierlich wächst bis die Gesundheit des Spielers auf Null abfällt. Mit zunehmendem Score steigt auch die Geschwindigkeit des Levels.

Kollisionserkennung

Alle Gegenstände des Spiels haben ein Rectangle (Java Klasse) als Hitbox. Diese Klasse implementiert das Interface Shape. Wir erzeugen dann Objekte der Klasse Area aus den Hitboxen, die ebenfalls Shape implementiert, und prüfen dann die Größe der gemeinsamen Fläche zwischen Spieler und Hindernis. Ist diese größer null werden dem Spieler entsprechend der größe der gemeinsamen Fläche, also schwere der Kollision, Leben abgezogen.

Generierung

Das Level unseres Spiels wird semi-prozedural generiert. D.h. das Level wird durch zufälliges Aneinanderhängen von vorgefertigten Hindernis und Gravitations-Trigger Abfolgen (Segmenten) während der Laufzeit kontinuierlich erweitert, bis der Spieler “stirbt”.

Ergebnis

Das Spiel ist zwar relativ einfach gehalten, funktioniert dafür aber sehr zuverlässig und benötigt wenig CPU-Leistung. Die CPU-Leistung wird beim Eyetracking, was sehr CPU lastig arbeitet benötigt. Trotz allem ist das Eyetracking sehr langsam und daher nicht für das Spiel geeignet. Nur wenn die Hindernisse enorm weit auseinander platziert werden ist es überhaupt möglich ein paar Hindernisse zu Überspringen. Generell funktioniert beim Eyetracking die Pupillenerkennung bei einer halbwegs brauchbaren Webcam und sehr guten Lichtverhältnissen ausreichend genau, Personen mit heller Iris sind dabei generell im Vorteil und können die Pupillenerkennung auch bei schlechteren Bedingungen nutzen, doch der Vergleichspunkt auf Basis der Kaskaden ist nicht stabil genug um zuverlässig Bewegungen aus der Pupillenposition herauslesen zu können. Nutzungs und Installationshinweise zu unserem Projekt stehen in der readme Datein im Sourcecode.

Ausblick

Im Moment erstellen wir eine Version, die nicht die Kaskaden als Ausgangspunkt für den Referenzpunkt nutzt, sondern spezielle Nutzerabhängige Merkmale des Gesichts. Dazu wird der ORB Algorithmus genutzt. Eine erste funktionsfähige Version ist dabei in dem Ordner Eyetracking_Java_Multithreading zu finden. Leider ist die Installation von OpenCV unter Java nicht ganz einfach und die Verwendung nur erfahrenen Nutzern vorenthalten. Eine Anleitung zur Installation von OpenCV findet sich man hier. Es muss Version 3.4.xx installiert werden. Zusätzlich muss die Library Webcam installiert werden. Und es müssen die Processing Jars in den Classpath eingebunden werden. Wir arbeiten daran ausführbare Jar Dateien zu erstellen, die diese Schritte nicht benötigen.

Testweise haben wir dieses Zip-Archiv erstellt, zum ausführen muss OpenJDK 11 oder höher installiert werden. Unter Windows ist zusätzlich folgende Anleitung zu verwenden. Diese Version ist experimentell und es kann durchaus vorkommen, dass sie nicht funktioniert. Zum starten muss die entsprechende .bat bzw .sh Datei ausgeführt werden.

Bekannte Fehler

Bei der Processing Eyetracking Version tritt der folgende Fehler häufig unter Linux auf: Die Fehlermeldung endet mit „undefined symbol: gst_date_get_type“. Dieser Fehler tritt auf, da auf dem Computer die Library Gstreamer in Version ⇐1.0 installiert ist, die von der Video Library nicht unterstützt wird. Abhilfe schafft die Verwendung der Version 2 der Video Library die manuell von dieser Website heruntergeladen und installiert werden muss.

Eine Anleitung zur Installation der Library findet man hier

projektesose20/eyetrackingspielpublic/start.txt · Zuletzt geändert: 2021/01/10 21:18 von d.golovko