Crazy Room

Aus toolbox_interaktion
Wechseln zu: Navigation, Suche

Semesterarbeit des Fachbereichs Medientechnik/Kommunikatiosdesign WS 2005/2006

Konzept der interaktiven Anwendung

Als Fortführung des Projektes "Short trippin'" ist das größtenteils aus dem gleichen Team bestehende Projekt " Crazy Room". Dabei werden die Lösungen des vorherigen Semesters weiter ausgebaut und entsprechend verändert. Es entsteht eine interaktive Raumgestaltung in 3D, die ohne Datenhandschuh bedienbar sein wird.
Zu Beginn des Semesters begann erneut die kreative Ideensuche für eine neue Anwendung. Das Projektteam war sich einig, "shorttrippin" als einen abgeschlossenen Block zu betrachten und sich einer neuen Herausforderung zu stellen. Die Inhalte 3D Stereo Effekt und Interaktivität sollten aber natürlich erhalten bleiben und im Vergleich zu den Ergebnissen des letzten Semesters verbessert werden.
Für die Interaktion sollten zwei Ziele erreicht werden. Einerseits auch ohne den bisherverwendeten Datenhanschuh mit 3D-Objekten interagieren zu können und andererseits auch in der Z-Ebene(=Tiefe) eine Interaktion umzusetzen. Denn mit dem Datenhandschuh war bisher nur eine Interaktion in der X/Y Ebene möglich. Hierfür konnte Prof. Heinz Brünig für das Projektteam den Kontakt zur 3SOFT GmbH aus Erlangen herstellen. Die Firma zählt zu den führendenAnbietern von Software-Lösungen auf dem Markt der Embedded Systeme für die Steuerung technischer Geräte und arbeitet mit dem Prototyp einerInfrarotkamera der Firma PMD Technologies GmbH. Diese ermöglicht die Aufnahme und Verarbeitung von 3D-Daten in Echtzeit(siehe Anhang1 auf CD). Für den Bereich der 3D-Visualisierung lautete das Ziel, sich in eine neue 3D Engine einzuarbeiten, da Director auf Grund der massiven Performanceprobleme für einen weiteren Einsatz nicht mehr in Frage kam. Auf der Suche nach einer leistungsfähigeren 3D Engine kamen nach ausgiebiger Recherche im Internet mehrere 3D Engines in Betracht:

  • Mesa 3D
  • Panda 3D
  • Crystal Space 3D
  • Quest 3D

Durch die Zusammenarbeit mit more3D wurde schließlich Quest3D als Arbeitsengine für dieses Semester ausgewählt.

Die Teilsysteme im Überblick

Seit den Anfängen der Software zur Maussteuerung wurde das Programm kontinuierlich weiterentwickelt und präsentiert sich zum Ende des Wintersemesters 2005/2006 als komplexe Applikation mit vielfältigen Einstellungsmöglichkeiten.
Besonders beeinflusst wurde die Weiterentwicklung des Programms von den PMD-Kameras, die uns von der Firma 3Soft zur Verfügung gestellt wurden. Diese Kameras zeichnen 3D-Information auf, die per OSC-Protokoll an das Java-Programm geschickt werden. Dort werden die Werte analysiert und in Aktionen auf dem Bildschirm umgesetzt. Neben dieser Art und Weise, Tiefeninformation aus einem Kamerabild zu gewinnen, wurdeaußerdem mit zwei DV-Kameras getestet. Aus den Unterschieden in den beiden Bildern kann die Entfernung von Objekten zur Kamera bestimmt werden. Diese Information wird von dem Java- Programm genutzt, um Aktivitäten auf dem Bildschirm auszuführen.
Diese verschiedenen Neuerungen wurden in die Oberfläche übernommen zusammen mit verschiedenen Glättungsverfahren und Einstellungen des Bildschirms oder der Kameragröße.

PMD Kamera

Ursprünglich wurde die Infrarotkamera von PMD für industrielle Zwecke entwickelt. Dabei waren Anwendungsbereiche in der Automobilindustrie und Fertigungstechnik angepeilt. Konkrete Beispiele sind Abstandsmessung und Personenerkennung beim Automobil respektive Objekterkennung und –vermessung in der Fertigungstechnik. In erster Linie wurde die Kamera für embedded-Systeme konzipiert. Möglicherweise kommt Ende 2006 eine serienreife Kamera auf den Markt, die es auch kleinen Firmen sowie Privatpersonen ermöglicht diese zu nutzen.

Technik

Diese Kamera arbeitet im Infrarotbereich. Dafür sind rechts und links vom Gehäuse jeweils eine "Infrarotbatterie" angebracht, also viele kleine Infrarotdioden in einem Gehäuse. Diese Dioden senden kodierte Infrarotstrahlen aus, die an Objekten reflektiert werden und vom Objektiv auf den Empfängerchip gelenkt werden. Der Chip berechnet aus der Laufzeit der Infrarotstrahlen die Entfernung zur Kamera. Es entsteht eine "3D Ansicht aus vielen Pixeln". Je nachdem welche Auflösung die Kamera hat, ist das empfangene Bild gröber oder feiner strukturiert. Jetzt kann von der Kamera jeder empfangene Pixel ausgelesen und ausgewertet werden. Das hat den Vorteil im Gegensatz zur gewöhnlichen Bildverarbeitung mit einem 2D Bild, dass für jedes Pixel schon ein Tiefenwert, also ein z-Wert existiert. Zudem braucht man keine Merkmale im Bild, die eindeutig erkannt werden müssen, wie zum Beispiel dem Datenhandschuh und den angebrachten Leuchtdioden. Die Bewegung der Hand kann eben durch die erkannten Pixel und der Tiefeninformation berechnet und erkannt werden.

PMD Software

PMD Control ist eine Software der Firma 3Soft, die die Handhabung der Kamera vereinfacht. Die Daten der Kamera werden visuell aufbereitet, so dass man das 3D-Bild der Kamera tatsächlich anschauen kann. Außerdem lassen sich zum Beispiel die Punkte des Schwerpunkts, oder das umschreibende Rechteck bestimmen. Die Punkte können geglättet werden und per OSCProtokoll an andere Anwendungen verschickt werden.

OSC Protokoll

PMD Control verschickt die berechneten Daten per OSC Protokoll an andere Anwendung. Port und Adresspattern kann man dabei selbst definieren. Im Laufe des Projekts wurden verschiedene Werte analysiert, die sich für die weiteren Berechnungen in der Java-Applikation besonders eignen. Ein beispielhafter Aufbau einer OSC Message ist im Folgenden dargestellt.

Beschreibung Datentyp Index
Initialisierungs-Wert Int/Bool 0
Tracking Punkt x-Wert Float 1
Tracking Punkt y-Wert Float 2
1. Punkt Bounding-Box x-Wert Float 3
1. Punkt Bounding-Box y-Wert Float 4
1. Punkt Bounding-Box z-Wert Float 5
2. Punkt Bounding-Box x-Wert Float 6
2. Punkt Bounding-Box y-Wert Float 7
2. Punkt Bounding-Box z-Wert Float 8
Anzahl der relevanten Tracking Punkte int 0

Bildbearbeitung

Die visualisierten Daten der Kamera können durch verschiedene Bildbearbeitungsverfahren verbessert und den eigenen Anforderungen angepasst werden.

Glättung

Die Glättung der Werte kann mit Mean-Smoothing oder Median-Smoothing (Mittelwerte) Erfolgen. Da die PMD-Kameras abhängig von ihrer Auflösung sehr fehlerhaft (springende Punkte) Daten überträgt, ist es notwenig, diese Fehler zu minimieren. Dies geschieht mittels verschiedener Glättungsverfahren. Diese Glättungsverfahren arbeiten mit Mittelwerten die sie aus benachbarten Punkten des betrachteten Pixels berechnen. So wird leichtes Pixelrauschen minimiert.

Tracking Funktionen

Die unterstützten Tracking Funktionen der Software heißen Front-Percent und Kalman Front Tracker. Die Software arbeitet mit verschiedenen Trackingverfahren um einen relevanten Punkt zu extrahieren. Zu diesem Zweck werden nur die Punkte als gültig betrachtet, die aus Sicht des Front Direction Vectors im Vordergrund liegen. Aus diesen selektierten Punkten wird der Mittelwert errechnet und als Tracking-Point festgelegt. Dieser Tracking-Point besitzt die Koordinaten XYZ. Die Menge der selektierten Punkte kann man manuell festlegen.

Software

Seit den Anfängen der Software zur Maussteuerung wurde das Programm kontinuierlich weiterentwickelt und präsentiert sich zum Ende des Wintersemesters 2005/2006 als komplexe Applikation mit vielfältigen Einstellungsmöglichkeiten.
Besonders beeinflusst wurde die Weiterentwicklung des Programms von den PMD-Kameras, die uns von der Firma 3Soft zur Verfügung gestellt wurden. Diese Kameras zeichnen 3D-Information auf, die per OSC-Protokoll an das Java-Programm geschickt werden. Dort werden die Werte analysiert und in Aktionen auf dem Bildschirm umgesetzt. Neben dieser Art und Weise, Tiefeninformation aus einem Kamerabild zu gewinnen, wurde außerdem mit zwei DV-Kameras getestet. Aus den Unterschieden in den beiden Bildern kann die Entfernung von Objekten zur Kamera bestimmt werden. Diese Information wird von dem Java- Programm genutzt, um Aktivitäten auf dem Bildschirm auszuführen.
Diese verschiedenen Neuerungen wurden in die Oberfläche übernommen zusammen mit verschiedenen Glättungsverfahren und Einstellungen des Bildschirms oder der Kameragröße.

Klassendiagramm

Die Hauptklasse mit der main-Methode ist die Ausgabe. Nach dem Starten erzeugt sie die Oberfläche und den XMLHandler. Der XMLHandler liest eine XML-Datei ein, in der die Einstellungen für die Oberfläche gespeichert sind, und aktiviert dann die entsprechenden Knöpfe und Checkboxen.
Nach dem Start wird die Klasse Verbindung erzeugt, die die Kommunikation zur Kamera über das OSC Protokoll regelt. Außerdem wird in Verbindung ein Objekt der Klasse Steuerung initialisiert und die Oberfläche als Referenz übergeben.
Sobald in der Oberfläche auf den Knopf "Start" gedrückt wird, tritt die Steuerungsklasse in Aktion. Sie überprüft, welche Kamera in der Oberfläche aktiviert wurde und erzeugt die entsprechende Unterklasse:
SteuerungPMDSmall, Steuerung PMDBig, Steuerung 2d oder Steuerung3d.
Hier ist also das klassische Designpattern Factory realisiert.
Parallel zur Steuerung gibt es die Klasse Glaettung, die auf die empfangenen Werte von der Kamera Glättungsverfahren anwendet. Die verfügbaren Operatoren können in der Oberfläche eingestellt werden.
Da das Projekt in diesem Semester verstärkt mit den PMD-Kameras beschäftigt war, haben wir eine zusätzliche Option eingebaut. Beim Erkennen eines Mausklicks wird eine Sounddatei abgespielt. Die dafür zuständige Klasse ist SimpleAudioPlayer.
Die genauen Abhängigkeiten werden im folgenden Klassendiagramm dargestellt.

Beschreibung aller Klassen

Es gibt folgende Klassen:

Ausgabe
Verbindung
Glaettung
SimpleAudioPlayer
Steuerung
Steuerung2D
Steuerung3D
SteuerungPMDBig
SteurungPMDSmall
Ausgabe
Oberfläche "Allgemein"

Das Aussehen der Oberfläche beim Start zeigt die Abbildung. Im Bereich Modus kann man auswählen zwischen den unterstützten Kameras. "Gerd2d" ist die bisherige Steuerung, die das Bewegen der Maus erlaubt und einen Mausklick ausführt, sobald der Benutzer die Finger zusammenführt. Mehr dazu in der Dokumentation vom Semester SS 2005.
Mit dem Radiobutton "Gerd3d" wird der Modus für zwei DV-Kameras gesetzt. Neben dem reinen Steuern und dem bisher realisiertem Klick, kann man zusätzlich ermitteln, wie tief die Hand des Benutzers sich im Raum befindet.
Der dritte Knopf aktiviert die PMD Kamera. Da es zwei Kameras mit unterschiedlicher Auflösung gibt, muss im Reiter "Konfiguration" diese noch bestimmt werden.
Für die PMD-Kameras wurde das Abspielen von Sound beim Klicken implementiert. Um diese Funktion zu aktivieren muss die Checkbox "Sound aktivieren" angewählt sein.
Im Bereich Koordinaten werden die aktuellen Werte des Mauszeigers ausgegeben. Bei Bedarf können diese Werte in einem Logfile abgespeichert werden. Die gesamten Einstellungen in der Oberfläche können abgespeichert und geladen werden. Das kann sinnvoll sein, wenn man mit verschiedenen Kameratypen testet und nicht wiederholt alle Einstellungen vornehmen will. Beim Starten der Software werden immer die zuletzt ausgeführten Einstellungen geladen.
Im Reiter "Konfiguration" kann man genauere Einstellungen definieren. Im Bereich "Auflösung" kann die Bildschirmgröße, sowie die Kameraauflösung gewählt werden. Das manuelle Einstellen der Bildschirmauflösung kann dann von Nutzen sein, wenn die 3D-Anwendung ihrerseits die Auflösung beim Start verändert. Wenn die PMD-Kamera im Reiter "Allgemein" selektiert wurde, wird über die Größe der Kamerauflösung bestimmt, ob es sich um die kleine oder die große Kamera handelt.
Dementsprechend wird später über die Steuerung entweder die Klasse SteuerungPMDSmall bzw. SteuerungPMDBig erzeugt. Der Computer, auf dem die Applikation läuft ist verbunden mit zwei Beamern. Die Bildschirmauflösung beinhaltet also die doppelte Breite. Der Benutzer soll aber nur in einem Bildschirm navigieren. Deswegen kann man über "Anzeige" entscheiden ob die Steuerung auf einen oder zwei Bildschirmen möglich ist. Der Bereich "Konfiguration" bietet die Möglichkeit, den Port, auf dem die Anwendung horcht, sowie das Adresspattern des OSC-Protokolls manuell einzustellen.

Verbindung

Die Klasse Verbindung wird in der Ausgabe erzeugt und implementiert das Interface OSCListener. Diese Klasse behandelt die Kommunikation mit den Kameras und empfängt Werte über das OSC Protokoll. Sie erzeugt die Klasse Steuerung und leitet die erhaltenen Werte weiter.
Wichtige Methoden:
connect(int port, String strAdr) disconnect() acceptMessage(Date time, OSCMessage message)
setParameters(String strCamera, String strCamRes, String strScreenRes, String strGlaettung1,
String strGlaettung2, boolean isInterpolationChecked, int numberOfScreens, boolea
isSoundOnClicked) setAction(boolean isSpezAction) setMouseValues()

Mithilfe des Interface OSCListener ist es möglich, auf einem Port nach Meldungen zu horchen. Über die Methode connect(int port, String strAdr) werden von der Oberfläche aus ein Port und ein Adresspattern an die Verbindung übergeben. Die Methode erzeugt einen Empfänger der Klasse OSCPortIn, der nach dem Start auf dem spezifizierten Port horcht. Sobald OSCPackete ankommen, wird die Methode acceptMessage(Date time, OSCMessage message) automatisch aufgerufen. Solange der Start-Knopf in der Oberfläche nicht angeklickt wurde, passiert jedoch nichts. Wenn der Benutzer "Start" drückt, wird über die Methode setAction(boolean isSpezAction) eine boolesche Variable auf "true" gesetzt. Die acceptMessage- Methode fragt nach genau dieser Variable und ruft setMouseValues() auf, wenn sie "true" ist. Beim Klicken des "Start-Knopfes" wird außerdem die Methode setParameters(String strCamera, String strCamRes, String strScreenRes, String strGlaettung1, String strGlaettung2, boolea isInterpolationChecked, int numberOfScreens, boolean isSoundOnClicked) aufgerufen. Sie leitet die Informationen weiter an die Steuerungsklasse, die die Einstellungen in der Oberfläche auf den eigentlichen Programmcode überträgt. In dieser Art des Weiterleitens wird das verwendete Pattern "Chain of Responsibility" deutlich.

Die gerade empfangene OSC-Nachricht wird in setMouseValues() extrahiert und in einem Array gespeichert. Wenn die Steuerungsklasse gerade Werte verarbeitet, wird die aktuelle Nachricht verworfen, wenn sie jedoch inaktiv ist, werden die Werte an sie übergeben.
Die Methode disconnect() wird von der Oberfläche aus aufgerufen, wenn bereits ein aktives Object der Verbindung existiert, und eine neue Verbindung aufgebaut werden soll. Über das OSC Protokoll werden verschiedene Werte übergeben, je nach angeschlossener Kamera. Diese Werte werden entweder von Eyesweb generiert oder von der PMDControl Software von 3Soft übertragen. Die expliziten Datentypen werden im Folgenden kurz erläutert.

Glaettung

Wichtige Methoden:
hystereseGlaettung(int xFresh,int yFresh, double dRadius)
interpolate(int xFresh,int yFresh)
Projekt Interkation | Crazy Rooms
MT/KD, WS 2005/2006 30
medianGlaettung(int x,int y)
setCoordinates(int[] freshCoordinates)

In dieser Klasse sind alle Algorithmischen Feinheiten der Software eingebaut. Es kommen hauptsächlich Algorithmen aus der Bildverarbeitung zum Einsatz.
Die Schwierigkeit besteht darin, aus der Vielzahl von Pixeln, die die Kamera liefert eine stabile Hand – Maus – Bewegung herzustellen. Um dies zu gewährleisten, werden verschiedene Verfahren angewendet.
Die Methode hystereseGlaettung() führt, wie der Name schon sagt eine Hysterese-Glättung mit x und y Werten durch. Diese Werte werden stabilisierst, und dadurch wird ein wildes Hüpfen der Maus verhindert. Einzelne Pixel, die zufälligerweise erkannt werden und somit "ins Bild springen", werden rausgefiltert.
Dabei betrachtet man den Radius des aktuellen Punktes, der von der Kamera geliefert werden.
Hier ist mit den Punkt der Schwerpunkt gemeint, der von PMD Control schon ermittelt wird. Der Radius hat einen festen Wert, der durch den Aufruf der Steuerungsklasse bereits mitgeliefert wird.
Dazu wird die absolute Differenz des neuen x-Wertes mit dem jeweils vorherigen alten x-Wert gebildet und diese mit dem Radius verglichen. Ist die absolute Differenz größer als der Radius und ist der neue x-Wert größer als der alte x-Wert wird vom neuen x-Wert der Radius abgezogen. Das gleiche wird mit dem y-Wert gemacht. Dadurch verhindert man extreme Sprünge der Koordinaten.
Als nächstes folgt die Interpolationsmethode interpolate(int xFresh,int yFresh). In dieser Methode werden zusätzliche Punkte zwischen 2 detektierten Kamerapunkten errechnet. Das hat zur Folge, dass die Maus eine glatte (smooth) Bewegung vollführt und es nicht zu spontanen Sprüngen kommt, weil sie die errechneten Zwischenpunkte abläuft. Allerdings wird dabei auch die Geschwindigkeit zur realen Handbewegung etwas verlangsamt, was ein Nachzieh-Effekt für den Betrachter zur Folge haben könnte. Die Länge des Abstandes zwischen der neuen und er alten Koordinate errechnet sich mit Hilfe des "Satz des Pythagoras". Mit der Länge kann man die Zeit errechnen, die sich durch den Quotienten von Länge und Geschwindigkeit, die fest voreingestellt ist (hier mit 10000) ergibt. Daraus lassen sich wiederum Schritte errechnen: Sie ergeben sich wieder durch den Quotienten von Zeit und einen vorher festgelegten Zyklus (hier 10). Dieser wird dann noch mit 1000 multipliziert. Differenz X ergibt sich durch die Differenz zwischen neuem und altem X-Wert dividiert durch die Schritte.
Das gleiche gilt für den y-Wert. Nun wird noch eine Schleife durchgelaufen mit der Anzahl der Schritte als maximaler Wert. Darin wird jeweils ein temporärer Wert für x und y erstellt der sich jeweils aus Summe des alten x-Wert und dem Produkt von Differenz X und Iterationsschritt ergibt. Nachfolgender Programmcode veranschaulicht die Überlegungen.

Die Medianglättung wird in der Methode medianGlaettung(int x, int y) durchgeführt. Unter der Medienglättung versteht man das Bilden eines Mittelwertes. Dazu wird ein Array gebildet, mit einer bestimmten Anzahl an Werten. In dieser Software werden 5 Werte in das Array gesteckt.
Jedes Mal wenn diese Funktion aufgerufen wird, kommen die detektierten die x- und y- Koordinaten in das Array. Ein Zähler zählt dabei hoch. Ist der Zähler größer als 4, wird der Puffer bzw. das Array wieder auf 0 gesetzt. Die Werte die bei jedem Methodenaufruf ankommen, werden in einer for-Schleife jeweils aufaddiert, bis das Array die Maximalgröße von 5 erreicht hat.
Am Ende werden die aufsummierten x- und y-Werte noch durch die Größe des Arrays geteilt und in einen int-Vektor gesteckt. Diesen gibt die Methode zurück – er enthält die neue geglättete Koordinate.
Zur Veranschaulichung finden sie den Quellcode in Programmteil 3:
Medianglättung:
Die letzte Methode in der Glättungsklasse ist so kurz wie simpel. setCoordinates(int[] freshCoordinates) holt x- und y-Werte aus einem Vektor und steckt sie in Integer-Variablen. Diese Werte werden in den obingen Glättungsmethoden verwendet, sie sind jeweils als xOld und yOld bezeichnet.
Diese Werte sind Vergleichswerte, also die alten x- und y-Werte mit denen die neu ankommenden Werte verglichen werden. Dazu wird diese setCoordinates() immer am Schluss in der Methode doMouseMove() der Klasse Steuerung aufgerufen, also nachdem die neuen Koordinaten schon an die Glättungsklasse geschickt wurden. Damit stehen für den nächsten Aufruf von doMouseMove() die "alten" x- und y-Werte zur Verfügung.

SimpleAudioPlayer

Der SimpleAudioPlayer spielt eine Sounddatei ab, die ihm mit playAudioFile(String file) übergeben wird. Der Code ist weitgehend übernommen von http://www.jsresources.org/examples/SimpleAudioPlayer.html.

Steuerung

Die Hauptsteuerungsklasse erbt von der Klasse Robot. Die Unterklassen erben von der Hauptsteuerungsklasse und somit auch von der Klasse Robot. Über diese Klasse kann die Systemmaus angesteuert werden. Zudem können Maustasten, das Mousewheel und auch die Keyboardtasten betätigt werden. Alle Klassen nutzen diese Eigenschaften um die Koordinaten in eine Interaktion zu wandeln.
Wichtige Methoden:
setParam(String strSelectedCam, String strCamResolution,
String strScreenResolution, String strFirstOp, String strSecondOp,
boolean isInterpolationClicked, int iNrOfSrceens);
refresh(Object[] spezCoordinates);
doMouseMove();

Die Klasse Steuerung ruft, je nach Auswahl der Kamera, ihrerseits die Unterklassen auf, z.B. SteuerungPMD, . SteuerungPMDsmall, SteuerungGerd2d, SteuerungGerd3d.
Hier wurde das Design Pattern "Factory" eingesetzt. Durch eine von der Klasse Ausgabe mitgegebene Variable, wird je nach Wert die entsprechende Klasse initialisiert, die in der Lage ist die empfangenen OSC-Patterns richtig zu interpretieren. Dieser Wert wird bei Aktivierung des Programms durch die Methode setParam(…) übertragen. Des Weiteren werden die Werte der Kameraauflösung, Bildschirmauflösung und der Glättungsoperatoren, die für die Mausbewegung eingesetzt werden, übergeben. Eben so die Reihenfolge in welcher die Glättungen aufgerufen werden. Die Glättungenalgorithmen werden aus der Klasse Glaettung bezogen.
Für die Verarbeitung und Analyse der Koordinaten wird die Methode refresh(…) aufgerufen. In dieser Methode wird wiederum eine Methode der zuvor initialisierten Unterklasse aufgerufen. In dieser Methode refreshXXX(...) (XXX=> Kameratyp) wir das Koordinaten-Array und die Bildschirmauflösung mitgegeben. Über die Methode getTrackingPoint() erhält man die in der Unterklasse skalierten Koordinaten. Diese Koordinaten werden abschließend in die Klasse doMouseMove() übergeben, in der sie in der richtigen Reihenfolge über die eingestellten Glättungsverfahren laufen gelassen werden.
Anschleißend werden über die Methode mouseMove() der Klasse Robot, die Koordinaten an die Sytem-Maus übergeben.

Steuerung2d

Die Steuerung 2D entspricht dem Entwicklungsstand der Software aus dem letzten Semester. Weitere Informationen zu dieser Klasse finden sich in der Shorttrippin' Dokumentation.

Steuerung3d

Wichtige Methoden:
refresh3d(Object[] spezCoordinates,int[] result)
Steuern in der Z-Ebene:
myMouseWheel(float tiefe)
Analyse eines echten Klicks:
PmdMousePress(String strButton)
isPmdMousePressed()
PmdMouseRelease(String button)
isPmdMouseReleased()

Diese Klasse befindet sich noch in der Entwicklungsphase. Hier wird über 3D-Stereo Aufnahmetechnik mit zwei DVKameras eine Interaktion aufgebaut. Die Koordinaten werden in Eyesweb detektiert, analysiert und berechnet. Hier ist noch Datenhandschuh Gerd nötig, um die Analyse fehlerfrei durchzuführen. Die Bewegung des Mauszeigers auf dem Bildschirm und das Auslösen eines Mausklicks sind wie in der Klasse Sterung2d realisiert. Zusätzlich besteht die Möglichkeit über die Methode myMouseWheel(...) die Entfernung der Hand (über den Handschuh und seine Dioden) zu bestimmen. Diese Tiefeninformation wird über die Disparität der beiden DV-Bilder geliefert. Diese Angaben sind relativ, entsprechen also keinen natürlichen Maßeinheiten. Über die oben genannte Funktion ist es Möglich das Mausrad anzusteuern. Ist der Tiefenwert größer als ein bestimmter Schwellwert, wird z.B. hochgescrollt, ist er niedriger wird runtergescrollt.

In diesem Ansatz steckt großes Potential und es wird sich lohnen, in an diesem Gebiet weitzugforschen.

SteuerungPMDSmall

Wichtige Methoden:
refreshPmdSmall(Object[] objCoordinates, int[] result)
getTrackingPoint()
setTrackingPoint(Object[] trackCoordinates)
Detection eines Klicks:
handleDepthMouse(Object[] objCoordinates)
Bewegung auf den Achsen:
moveZAxis(Object[] objCoordinates)
moveXAxis(Object[] tiefe)
Analyse eines echten Klicks:
PmdMousePress(String strButton)
isPmdMousePressed()
PmdMouseRelease(String button)
isPmdMouseReleased()

Diese Klasse ist für die Verwertung der Koordinaten der kleinen PMD Kamera zuständig. Über die Hauptsteuerungsklasse werden die Koordinaten und die Bildschirmauflösung via refreshPmdSmall(...) übergeben. Es wird überprüft ob sich die Hand im Aktiv Volumen befindet. Wenn die Hand außerhalb des Volumens ist, kann über die normale Maus gesteuert werden, wenn sie innerhalb ist werden die Mausfunktionen vom Programm übernommen. Nun werden in dieser Methode die verschiedenen Funktionen aufgerufen, die für die Analyse der Koordinaten zuständig sind.
Die Koordinaten werden entsprechend der mitgegebenen Bildschirmauflösung von der Funktions setTrackingPoint(..) hoch skaliert, um die kleine Kameraauflösung auf den gesamten, höhe aufgelösten Bildschirm anzupassen. Diese Koordinaten können anschließend über die Methode getTrackingPoint(...) ausgelesen werden. Weiter wird der Mausklick und das Auslösen verschiedener Keyboardbuttons (z.B. WASD = laufen im 3D Modell) detektiert und ausgelöst.
Um einen Mausklick der Rechten oder Linken Taste zu detektieren, werden in der Funktion handleDepthMouse(...) die Z-Werte verschiedener selektierten Punkte (siehe PMDcontrol) betrachtet. Genauer wird sich der erste und letzte selektierte Punkt angeschaut. Liegt die Differenz der beiden Punkte in der Nahe von 0 so wird kein Klick ausgelöst.
Liegt die Differenz um einen bestimmten Schwellwert (bei unseren Einstellungen + -20) wird ein Klick ausgelöst.
Dieser muss aber zuvor geprüft werden.
Um nun festzustellen ob wirklich geklickt werden darf und nicht schon geklickt ist, müssen nun einige Methoden zur Qualitätssicherung des Mausklicks durchlaufen werden. Nachdem die Differenz errechnet wurde wird die Methode PmdMousePress(...) aufgerufen, die letztendlich auch den Klick auslöst. Zuvor wird durch die Funktion isPmdMouse-Pressed(...) aber gestestet ob es wirklich möglich ist in diesem Moment zu Klicken.

1. Eine historische Verfolgung der Koordinaten ist wichtig um Fehlkoordinaten herauszufiltern. In einem Koordinatenpuffer wird der Mittelwert von einer bestimmten Anzahl bebildet um diese Fehler auszuschließen.
Es gibt folgende Anforderungen um einen Klick auzulösen. Das Problem ist das einen vollständiger Mausklick nicht nur ein MousePress() sondern auch ein MouseRelease() ausmacht. Erst wenn das MouseRelease() auf das MousePress() folgt, wird die Aktion, über der der Mauszeiger steht ausgelöst. Um Drag 'n' Drop zu ermöglichen ist dieser Mechanismus durchaus sinnvoll, wenn nicht essentiell. Nun muss aber sichergestellt werden dass, wenn ein MousePress() ausgelöst ist und kein sofortiges MouseRelease() folgt( z.B. bei Drag 'n' Drop), nicht permanent ein weiteres MousePress() ausgelöst wird. Dies würde zur Verwirrung des Systems führen, da die Maus sich in einem inkonsistenten Zustand befinden würde. Zur Verhinderung dieses Falls wurde die folgende IF-Abfrage implementiert Hier entscheiden letzt endlich zwei Schwellwert über die Validität eines Klicks. Ein Maximaler Schwellwert für MousePress() (I_MAX_DEPTH ) und ein minimaler Schwellwert für MouseRelease() (I_MIN_DEPTH). Wenn die Koordinate (total) den definierten MAX Schwellwert überscheitet und die Maus noch nicht gedrückt ist (!ismousepressed), darf ein MousePress() durchgeführt werden. Es wird sich gemerkt das gerade ein Klick ausgeführt wird (ismousepressed=true) und von der Funktion isPmdMousePressed() wird an die Funktion PmdMousePress() zurückgegeben, dass geklickt werden darf (return = true).
Ist in einem anderen Fall die Koordinate größer als der MAX Schwell wert, aber es ist schon geklickt (ismousepressed == true), wir zurückgegeben das nicht ein weiters mal geklickt werden darf. Doch nun ist bei den nächsten Koordinaten ein MouseRelease() wahrscheinlich.

Programmteil 4: wichtige Abfragen zum Auslösen eines Klicks
Im Dritten Fall ist die Koordinate kleiner als der MAX Schwellwert und auch kleiner als der MIN Schwellwert, d.h. es darf der Mausklick durch ein MouseRelease() komplett beendet werden. Es wird gekennzeichnet das die Maus nicht mehr geklickt ist und deswegen nicht ein weiters mal geklickt werden darf.
Parallel zur Methode MousePress(), die implizit einen Klick validiert, wird die Funktion MouseRelease() aufgerufen, die ihrerseits die Gültigkeit eines Realease testet. Diese Abfrage setzt natürlich auf die Methode isMousePress() auf. Zwei Vorrausetzen sind für eine Release gegeben. Erstens darf die Maus nicht mehr geklickt sein (ismousepressed == false) und zweitens muss sie vorher einmal geklickt worden sein (possibleclick == true).
Sind diese beiden Vorraussetzungen gegeben, wird ein Release von der Methode MouseRelease() durchgeführt. Um sich zusätzlich zum Mausklick in einer 3D Umgebung auch vorwärts bewegen zu können wurden die Methoden moveZAxis() und moveXAxis() implementiert . Hier wird das oben erwähnte klicken von Keyboardbuttons möglich. Wie in einem herkömmlichen 3D Spiel kann man sich auch in unserer Umgebung mit denn Tasten WASD fortbewegen. Diese Tasten funktionieren ähnlich wie die Pfeiltasten auf der Tastatur.
Da wir diese Bewegungsmöglichkeit auch ohne Tastatur ermöglichen wollen, uns war auch nur mit der Hand, wurden folgende Mechanismen realisiert. In den oben genannten Funktionen werden die x,y und z-Werte des Trackingpoints betrachtet. Die Methode moveZAxis() ist für die Vorwärtsbewegung zuständig, d.h. wenn der Trackingpoint, also die Hand einen bestimmten Schwellwert in der Tiefe (Z-Ebene) überschreitet, wird der Keyboardbutton "W" ausgelöst. Hier wieder rum die Überprüfung, das zur richtigen zeit und nicht doppelt gepresset und releaset wird. In der ähnlichen Art wird die Seitwärtsbewegung in der Methode moveXAxis() durchgeführt. Hier der Schwellwert an der rechten und linken Seite der Aktivbox mit den Tasten "A" und "D".

SteuerungPMDBig

Wichtige Methoden:
refreshPmdBig(Object[] objCoordinates, int[] result)
getTrackingPoint()
setTrackingPoint(Object[] trackCoordinates)
Detection eines Klicks:
boundingClick(Object[] boundCoordinates)
handleDepthMouse(Object[] boundCoordinates)
Bewegung auf den Achsen:
moveZAxis(Object[] objCoordinates)
moveXAxis(Object[] tiefe)
Analyse eines echten Klicks:
PmdMousePress(String strButton)
isPmdMousePressed()
boundClick(int total,int iPufferLength)
depthClick(int total,int iPufferLength)
PmdMouseRelease(String button)
isPmdMouseReleased()

Dies ist die Klasse um die Koordinaten der PMD Kamera mit der Auflösung 160 x 120 px zu analysieren. Der große Unterschied zwischen den beiden Kameras besteht darin, das die hohe Auflösung der "großen" PMD- Kamera zwar für eine flüssiger Bewegung des Trackingpoints sorgt, aber eine hohe Rate an fehlinterpretierten Koordinatenpunkten liefert. Dies geschieht zum größten Teil an den Randbereichen eines aufgezeichneten Objektes. Die Funktionsweisen der Koordinatenskalierung und die Bewegung auf der X und Z Achse sind wie in der zuvor beschriebenen Steuerungsklasse SteuerungPmdSmall.
Die Unterscheide liegen in der Detektion der Mausklicks. Außer der zuvor beschriebenen Methode handleDepthMouse(...), die in dieser Klasse in der gleichen Weise implementiert ist, besteht zusätzlich die Möglichkeit über die Methode boundingClick() einen Mausklick durchzuführen. In dieser Methode werden nicht die Tiefenwerte der selektierten Punkte analysiert sondern der umschließende Quader der diese Selektierten Punkte umgibt. Die Methoden zur Validitätsprüfung des Klicks sind ähnlich denen der oben ausgeführten Klasse mit dem Unterschied, dass zwei neue Methoden eingeführt wurden um die verschiedenen Klickmethoden handleDepthMouse(...) und boundingClick() auf Klickgültigkeit zu prüfen.
Dies war nötig, weil verschiedene Parameter nötig waren um einen MousePress() in beiden Methoden zuverlässig detektieren zu können. Diese Hilfsmethoden heißen isboundClick(...) und isdepthClick(...).

XMLHandler

Diese Klasse kümmert sich um das Speichern und Laden von Einstellungen. Alle Einstellungen werden in eine XML Struktur gebracht und anschließend in eine XML Datei geschrieben
Es ist möglich:

  • aktuelle Programm Einstellungen in eine XML Dateien zu schreiben und im Filesystem abzulegen
  • die gespeichertne Einstellungen aus einer XML Datei zu laden
  • Die zuletzt verwendeten Einstellungen werden beim Schließen automatisch in eine XML-Datei gespeichert und beim Neustart des Programms gleich geladen.

Übersicht Methoden:
public XmlHandler(Ausgabe spezFenster)
private void setNewTitle(File f )
public void readXmlAndChangeSettings(File f )
public void getAndWriteXML(File outputfile)
private Document parseXmlFile(String filename, boolean validating)
private void readXml (Document doc)
private void changeSettings()
private String readTags (String uebergabe)

Beschreibung der Funktionen:
Im Konstruktor der Klasse XML-Handler, also in public XmlHandler(Ausgabe spezFenster) wird die Klasse mit der Klasse Ausgabe "bekannt" gemacht, sie muss deshalb auch public sein. Hier könnten auch noch alles Variablen initialisiert werden, was aber hier nicht gemacht wird.
Die Methode readXmlAndChangeSettings(File f ) ruft im Wesentlichen 3 weiter private Methoden auf, nämlich parseXml-File (String filename, boolean validating), readXml (Document doc) und changeSettings().
parseXmlFile() erstellt eigentlich nur ein Document über eine DocumentBuilderFactory und eine DocumentBuilder und stellt das für readXML() zur Verfügung bzw. übergibt es dieser.
readXml (Document doc) greift auf eine im Filesystem liegende XML Datei zu und liest deren Inhalt. Dazu wird intern ein Document angelegt. In dieses Document wird anschließend eine NodeList gesteckt. Darin werden anschließend die einzelnen Tags über die Methode readTags(String uebergabe) abgelegt. Diese Methode sucht die gewünschten Nodes in der XML-Datei per Namen des Tags, der mit dem String "uebergabe" von readXml() übergeben wird.
Danach werden die Text-Inhalte der Nodes in einen Zwischenspeicher vom Typ String geschrieben. Dieser wird von der Methode readTags() an readXML() zurückgegeben. Die Inhalte werden nun in Variablen abgespeichert, und wenn nötig in Integer geparst. Auf diese Variablen kann nun die ganze Klasse zugreifen.
Die Methode changeSettings() nimmt nun die eingelesenen Werte und überträgt die Einstellungen in die Ausgabe-Klasse. Natürlich werden auch dabei die optischen Elemente auf derOberfläche neu gesetzt, zum Beispiel das "setzen" von RadioButtons.
getAndWriteXML(File outputfile) holt sich im Wesentlichen zuerst die aktuellen Programm- Einstellungen aus der Oberfläche, erstellt anschließend ein XML Document und schreibt dieses dann in eine Datei ins Dateisystem. Sie wird von der Klasse Ausgabe aus aufgerufen. Die Aktualisierung der Werte übernimmt die Methode getActualSettings(), die direkt auf die Oberfläche der Klasse "Ausgabe" zugreift und alle Werte in Variablen speichert. Ist das geschehen, wird eine neue Instanz der DocumentBuilderFactory erstellt. In diese Factory wird ein DokumentBuilders-Objekt ins Leben gerufen.
Danach wird noch eine DOMImplementation erstellt, die ihrerseits wieder ein Document anfertigt. In diesem Document wird zuerst ein root- Element geschaffen, in welches dann die jeweiligen Unterelemente bzw. Nodes samt ihrem Inhalt verschachtelt werden. Danach wird das Document in ein DOMSource Objekt gesteckt. Jetzt braucht man "nur" noch ein Objekt vom Typ Result. Sind diese beiden Objekt angelegt, werden sie in ein Transformer Objekt gesteckt, welches zuvor von einer TransformerFactory Instanz angelegt wurde und nun in die XML Datei geschrieben wird.
Natürlich gibt es Routinen, die zum Beispiel überprüfen, ob es schon eine Datei gibt die genau so heißt, wie die aktuelle die gespeichert werden soll, und es wird nachgefragt, ob diese dann wirklich überschrieben werden soll.
Zu guter letzt schreibt setNewTitle(File f ) den Namen der geladenen Konfigurationsdatei in die Titelzeile des Fensters. Beim 1. Start wird keine Einstellung geladen, weil die "preferences.xml" noch nicht existiert, die beim Beenden des Programms automatisch geschrieben wird.
Deshalb erscheint auch beim 1. Start eine Fehlermeldung, die auf das Fehlen der "preferences.xml" hinweist.

3D-Visualisierung

Im letzten Semester wurde die 3D-Visualisierung ja bekanntlich in Macromedia Director abgewickelt. Dies konnte auch bis zum Ende des vergangenen Semesters präsentabel umgesetzt werden, jedoch hatten sich schon während des Projektsverlaufs einige Probleme ergeben:
Das notwendige Abspielen von zwei movie clips auf der Directorbühne für den 3D-Stereo Effekt führte zu starken Performance Problemen am PC. Sowohl während der Arbeit mit Director, als auch zur Laufzeit der damaligen Anwendung shorttrippin.
Arbeiten mit dem veralteten und nicht weiter entwickelten Shockwave-3D Format.
Die notwendige zweite Kamera für die Ausgabe des zweiten movie clips für den 3D-Stereo Effekt musste manuell programmiert und angesteuert werden.
Director ist für derartige Anwendungen schlicht und einfach nicht ausgelegt.
Somit war schon vor Beginn von crazyrooms klar, dass man sich nach einer neuen Visualisierungsschnittstelle umschauen musste. Durch unseren Partner more3D wurden wir auf die 3D-Engine Quest3D der holländischen Firma Act-3D aufmerksam gemacht und auch mit einer entsprechenden Lizenz versorgt. Denn für unsere 3D-Stereo Ausgabe mit der more3D-Stereo Suite war es wichtig, dass wir eine Anwendung entwickeln, die auf Microsofts DirectX Schnittestelle basiert. Genau das ist bei Quest3D der Fall. Zunächst soll nun eine kurze Einführung in Quest3D gegeben werden, um dann den Aufbau und die Elemente von crazyrooms in Quest3D zu erläutern.

Was ist Quest3D

Quest3D ist eine Software für Multimediaanwendungen. Ein Einsatzbereich sind interaktive Echtzeit 3D Anwendungen, wie z.B. virtuelle Produktpräsentationen im Fall von crazyrooms. Quest3D ist jedoch kein Programm zum Erstellen von 3D Modellen. Diese müssen in einem separaten Programm wie 3dsMax erstellt werden und können dann in Quest3D importiert und dort weiter verarbeitet werden. Ähnlich wie bei EyesWeb hat man eine Auswahl von Blöcken(=channels), die miteinander logisch verknüpft werden können. Jeder Block hat bestimmte Fähigkeiten und bietet somit viele Funktionen. So entsteht durch das Verbinden von verschiedenen channels schließlich eine Anwendung mit einer Baumstruktur, die in Windows gestartet werden kann.
Standardmäßig ist Quest3D unterteilt in drei Bereiche: channels, Objekte und Animation. Diese Unterteilungen stellen die drei separaten Aufgaben dar, die notwendig sind, um Echtzeit 3D Anwendungen zu erstellen.
Über die channels können die Logik und die Abhängigkeiten der virtuellen Welt festgelegt werden. Man kann z.B. die Position eines 3D Objekts mit der Position der Maus verbinden. So erhält das 3D Objekt seine Position immer von der Position der Maus. Generell repräsentieren die channels Aktionen, Daten oder beides zugleich.
Im Objektabschnitt definiert man das Aussehen der 3D Objekte. Man kann ihnen dort eine oder mehrere Texturen, Glanz, Transparenz oder eine andere Farbe geben.
Im Animationsabschnitt setzt man virtuelle Kameras, Lichter und "Bonestrukturen", um z.B. das 3D Modell eines organischen Objekts realistisch zu animieren. Natürlich geht es vor allem um Bewegungen und folglich um das Festlegen von bestimmten Werten zu bestimmten Zeitpunkten.