Sie sind auf Seite 1von 13

Lehrstuhl VII Graphische Systeme

Ausgabe: Dauer: 2 Wochen

Dipl. Inform. Denis Fisseler Dipl. Inform. Marcel Gaspar Dr. Frank Weichert

vclab@ls7.cs.tu-dortmund.de

Fachlabor Visual-Computing
(Sommersemester 2011)

Projektaufgabe Handgestenerkennung mit OpenCV

Allgemeine Informationen zu den Projektaufgaben: Die Projektaufgaben in der ersten Phase des Fachprojektes Visual Computing dienen dazu, die theoretischen Konzepte der Module Graphische Datenverarbeitung und Digitale Bildverarbeitung um eine praktische Komponente zu erweitern. Gem dieser Ausrichtung sind a die Praktikumsaufgaben derart konzeptioniert, dass die Erarbeitung und Umsetzung praktischer Interaktionsanstze im Vordergrund steht. a In Abhngigkeit der Projektaufgabe stehen zur Bearbeitung ein oder zwei Wochen zur Vera fgung. Diese Informationen entnehmen Sie bitte der Kopfzeile des Aufgabenblattes, welches u auf der Fachlaborseite zum Fachlabor verfgbar ist. Eventuelles Zusatzmaterial (z. B. Cou derahmen) wird zeitgleich auf der Fachlaborseite zur Verfgung stehen. Die Abnahme der u Aufgaben erfolgt jeweils in der Sitzung zum Fachprojekt am Mittwoch (Raum 115, Raum 117 und Raum 122, Otto-Hahn-Strae 16) und beinhaltet sowohl die praktische Vorfhrung u als auch eine Erklrung der realisierten Konzepte. Unabhngig von der Bearbeitungszeit der a a jeweiligen Projektaufgabe ndet die Sitzung zum Fachprojekt wchentlich statt. Diese teilo weise vorliegenden Zwischentermine dienen primr zur Klrung von Unklarheiten und zur a a Besprechung von Teillsungen. Bei Nachfragen auerhalb der o.g. Termine senden Sie bitte o eine E-Mail an die Betreuer: vclab@ls7.cs.tu-dortmund.de. Zur Bearbeitung der Aufgaben steht das VC-Lab am Lehrstuhl fr Graphische Systeme im u Raum 115, im Raum 117 und im Raum 122, Otto-Hahn Strae 16 zur Verfgung. Neben u entsprechend eingerichteten PC-Systemen verfgt das VC-Lab auch uber die notwendige Speu zialhardware zur Bearbeitung der Aufgaben. Selbstverstndlich kann die Umsetzung auch auf a einem privaten Rechner erfolgen die Vorfhrung sollte aber immer auf den Rechnern im u VC-Lab erfolgen.

Seite 1 von 13

OpenCV Vorbereitungsaufgabe
Informationen zur Vorbereitungsaufgabe: Diese Aufgabe dient als Vorbereitung fr die eigentliche Projektaufgabe, bei der C/C++ in u Kombination mit der Computer-Vision Bibliothek OpenCV genutzt werden soll. Ziel ist es, anhand eines einfachen Programms einige ntzliche Datenstrukturen und Funktionalitten u a der OpenCV-Bibliothek kennenzulernen und zu verwenden. Dokumentationen zu OpenCV benden sich auf der oziellen Seite http://opencv.willowgarage.com/wiki/. Eine Einfhrung ist unter http://www.cs.iit.edu/~agam/cs512/lect-notes/opencvu intro/opencv-intro.html abrufbar. Dort nden Sie Details zur Datenstruktur IplImage, die in OpenCV fr die Speicherung von Bildern verwendet wird, sowie verschiedene u Zugrismglichkeiten auf die Bilddaten. o Aufgabenstellung: a) (OpencvSimple) Entpacken Sie das Archiv OpenCV-Simple.zip und nen Sie o das im Unterordner OpenCV-Simple bendliche Projekt OpenCV-Simple.sln und versuchen Sie die Struktur des Programms, das im Wesentlichen aus der Klasse OpencvSimple besteht, nachzuvollziehen. Im Folgenden sollen die 8 Klassenmethoden sowie Konstruktor und Destruktor um ihre Funktionalitten ergnzt werden. Neben dem Proa a jekt und den ntigen Dateien zur Benutzung der OpenCV-Bibliothek bendet sich in o dem zip-Archiv auch die Bilddatei testbild.png, die fr Test- und Manipulationsu zwecke verwendet werden kann. b) (Konstruktor und Destruktor) Die beiden Membervariablen pColorImg und pGrayImg sind Zeiger auf Objekte vom Typ IplImage, die zur Speicherung von Bildern in OpenCV eingesetzt werden und auf die spter genauer eingegangen wird. Diese a werden im Konstruktor mit Null initialisiert. Im Destruktor wird der Speicherplatz uber die OpenCV-Methode cvReleaseImage wieder freigegeben, falls die Zeiger ungleich Null sind, also tatschlich Speicher allokiert wurde. Um Bilder anzuzeigen kann die a OpenCV-GUI-Bibliothek HighGUI verwendet werden, die unter anderem Methoden zur Darstellung von IplImages in einem Fenster anbietet. Ergnzen Sie den Konstruktor a um die Methode cvNamedWindow, um whrend des Programms den Zugri auf das a Fenster zu ermglichen. Als Parameter erwartet die Methode eine Fensterbezeichnung o als Zeichenkette, die zur Identikation des Fensters dient. Nutzen Sie als zweiten Parameter die Konstante CV_WINDOW_AUTOSIZE, die fr eine automatische Anpassung u der Fenstergre an die Gre des IplImage sorgt. o o Fr die Fensterbezeichnung initialisieren Sie die Klassenvariable windowName mit eiu ner beliebigen Zeichenkette und ubergeben diese cvNamedWindow als Parameter. Es knnen auch mehrere Fenster erstellt und verwendet werden, solange sich die Fensterbeo zeichnungen unterscheiden. Dies ist in der Vorbereitungsaufgabe jedoch nicht notwendig. Um den belegten Speicherplatz wieder freizugeben, fgen Sie entsprechend die Methode u cvDestroyWindow in den Destruktor ein.

Seite 2 von 13

c) (startMainLoop) Die Methode startMainLoop soll die Hauptschleife des OpenCVProgramms enthalten, die zur aktiven Tastaturabfrage und dem Aufruf weiterer Methoden bentigt wird. Die beiden Klassenvariablen runLoop, deren boolscher Wert die o Hauptschleife des Programms kontrolliert und key, die zur Speicherung der letzten Tastatureingabe dienen soll, sollen hier eingesetzt werden. Die Bibliothek HighGUI bietet eine einfache Benutzerschnittstelle innerhalb OpenCV, zu der unter anderem die Tastaturabfrage gehrt. Ergnzen Sie die Hauptschleife um die Methode cvWaitKey, sodass o a die Klassenvariable key die aktuelle Tastatureingabe speichert. Dabei soll das Zeitinterval, in dem auf eine Tastatureingabe gewartet wird, 1ms betragen. Falls innerhalb des Zeitintervalls eine Tastatureingabe erfolgt ist, soll die Klassenmethode processKey aufgerufen werden, die die Tastatureingabe verarbeitet. Genauere Informationen zu cvWaitKey entnehmen Sie der C- oder C++-Dokumentation. Tipp: Bei der Suche nach OpenCV-Methoden uber die Quick-Search Funktion, die Sie in der C- bzw. C++-Dokumentation (Online Reference Manual) der oziellen OpenCVWebseite nden, mssen die gesuchten Befehle ohne das cv-Prg eingegeben werden, u a also z.B. WaitKey statt cvWaitKey. Bitte beachten Sie auch, dass sich die C- und C++-Dokumentationen unterscheiden. Sollten Sie einen Befehl in einer der Dokumentationen nicht nden, so versuchen Sie es in der anderen. d) (processKey) Die Methode processKey soll die Tastatureingabe verarbeiten, die als ASCII-Code in der Klassenvariable key gespeichert wird. Ergnzen Sie die Methode a so, dass falls die Esc-Taste gedrckt worden ist, die Hauptschleifen-Bedingung nicht u mehr gegeben ist und das Programm beendet wird. Den gewnschten ASCII-Code knu o nen Sie z.B. der Tabelle http://www.torsten-horn.de/techdocs/ascii.htm entnehmen. Testen Sie, ob das Programm das erwnschte Verhalten zeigt. Belegen Sie u anschlieend sechs weitere Tasten, um die bislang noch nicht verwendeten Klassenmethoden aufrufen zu knnen. o e) (loadImageFromDisk) Beim Bettigen der Taste, die mit der Methode loadImaa geFromDisk verknpft ist, soll ein Farbbild von der Festplatte geladen werden. Dazu u eignet sich die Methode cvLoadImage, die als Parameter eine Zeichenkette mit dem vollstndigen Pfad zur Bilddatei bentigt. Sie knnen z.B. die im zip-Archiv enthaltene a o o Bilddatei testbild.png verwenden. Beachten Sie, dass in der Pfadangabe statt des Backslashs ein Slash verwendet werden muss, also z.B. C:/.../testbild.png. Der Zeiger, der von cvLoadImage zurckgegeben wird, soll in der Klassenvariable u pColorImage gespeichert werden. Nach dem Laden kann uber den Zeiger pColorI mage in der gesamten Klasse auf das Bild zugegrien werden. Um Speicherlcher zu o verhindern, prfen Sie vor dem Laden, ob der Zeiger bereits auf ein IplImage-Objekt u verweist (also ungleich Null ist) und geben Sie in dem Fall zunchst den Bildspeicher a mit der Methode cvReleaseImage, wie sie bereits im Destruktor verwendet wird, frei. Abschlieend soll das geladene Bild mit cvShowImage angezeigt werden. Ubergeben Sie als Parameter die Fensterbezeichnung und das geladene Bild. Testen Sie, ob das Laden und Anzeigen nach Bettigung der gewhlten Taste funktioniert. a a

Seite 3 von 13

f) (saveImagesToDisk) Falls pColorImage und pGrayImage bereits auf bestehende Bildobjekte verweisen, sollen diese in der Methode saveImagesToDisk mittels cvSaveImage auf der Festplatte gespeichert werden. Neben dem Pfad in Form einer Zeichenkette, inklusive Dateinamen und Dateiendung, erwartet die Methode einen Zeiger auf das zu speichernde Bild. Testen Sie die Speicher-Methode. Diese wird spa ter interessant, um z.B. Kamerabilder, die mit der Methode getImageFromCamera erfasst werden sollen, abspeichern zu knnen. o g) (printTextToImage) Um dem Benutzer Informationen mitteilen zu knnen, bietet o OpenCV die Mglichkeit, einen Text direkt in ein Bild zu zeichnen. Implementieren o Sie die Methode printTextToImage, so dass der ASCII-Code der zuletzt gedrckten u Taste sowie die Bezeichnung des aktuellen OpenCV-Fensters, die in der Klassenvariable windowName gespeichert ist, in der oberen linken Ecke des Farbbildes angezeigt wird. Die Zeichenkette, die ausgegeben werden soll, ist bereits in der Methode implementiert und in der Variable buffer gespeichert.Bevor der Text ausgegeben werden kann, muss zunchst eine Schriftart deniert werden. Erzeugen Sie ein neues CvFont-Objekt. Diea ses kann mit Hilfe der Methode cvInitFont initialisiert werden. Anschlieend kann die Zeichenkette mit cvPutText in ein gewnschtes Bild gezeichnet werden. Die Zeiu chenposition (untere linke Ecke des ersten Zeichens) kann mit der statischen Methode cvPoint ubergeben werden, whrend die Textfarbe durch Angabe der drei Farbkana a le uber die statische Methode cvScalar angegeben werden kann. Entnehmen Sie die genauen Parameter der OpenCV C-Dokumentation. Anschlieend soll das modizierte Bild angezeigt werden. Testen Sie, ob die Textausgabe funktioniert und passen Sie gegebenfalls die Parameter an. h) (getImageFromCamera) Beim Aufruf der Methode getImageFromCamera sollen das aktuelle Kamerabild einer angeschlossenen USB-Kamera kopiert und anzeigt und anschlieend die Speicheressourcen wieder freigegeben werden. Ergnzen Sie dazu die a Methode um einen Zeiger auf das Struct CvCapture, das Parameter kapselt, die fr u die Verbindung zu unterschiedlichen Video-Quellen (z.B. Kameras oder Videodateien) bentigt wird. Der Zeiger soll auf das Capture-Objekt verweisen, das von der Methode o cvCaptureFromCAM zurckgegeben wird. Bei Verwendung mehrerer Kameras muss u der Methode cvCaptureFromCAM die ID der gewnschten Kamera mit ubergeben u werden. Soll eine beliebige Kamera verwendet werden oder ist nur eine vorhanden, kann der Parameter CV_CAP_ANY ubergeben werden. Der Zugri auf das aktuelle Kamerabild geschieht uber die Methode cvQueryFrame. Deklarieren Sie einen temporren Zeiger auf ein IplImage und weisen Sie ihm den Zeia ger zu, der von cvQueryFrame zurckgegeben wird und der auf das aktuelle Kamerau bild verweist. Dabei muss der cvQueryFrame-Methode der Zeiger auf das verwendete Capture-Objekt als Parameter ubergeben werden. cvQueryFrame liest das aktuelle Bild aus der Quelle aus, die in dem Capture-Objekt gekapselt ist. Hinweis: Der Speicherbereich, auf den der Zeiger, der von cvQueryFrame zurckgeu gebenen wird, verweist, darf nicht mit cvReleaseImage freigegeben werden. Dieser ist Bestandteil des Capture-Objekts und wird gesondert freigegeben.

Seite 4 von 13

Da das ausgelesene Bild auch auerhalb der getImageFromCamera-Methode verwendet werden soll, muss eine Kopie erstellt und uber die Klassenvariable pColorImg zugreifbar gemacht werden. Um Speicherlcher zu vermeiden, prfen Sie zunchst ob o u a bereits ein Farbbild vorhanden ist und lschen Sie es gegebenfalls. Verwenden Sie ano schlieend die Methode cvCloneImage, um eine Kopie des Kamerabildes, auf das der temporre IplImage-Zeiger verweist, zu erstellen. Die Methode gibt einen Zeiger auf a die Kopie zurck. Zeigen Sie anschlieend das Kamerabild an und geben Sie die nicht u lnger bentigten Capture-Ressourcen mittels cvReleaseCapture wieder frei. Dea o tails zu den verwendeten Methoden entnehmen Sie der C-Dokumentation (nicht in der C++-Dokumentation enthalten). Verbinden Sie die Kamera mit dem PC und testen Sie, ob das Kamerabild beim bettia gen der entsprechenden Taste angezeigt wird. Prfen Sie, ob das Speichern des Kameu rabildes auf Festplatte funktioniert. i) (convertToGray) Die Konvertierung des Farbbildes (falls vorhanden) in ein Grauwertbild soll in der Methode convertToGray implementiert werden. Machen Sie sich mit den Details der verwendeten Datenstruktur IplImage vertraut, die Sie im Abschnitt Image data structure der zuvor erwhnten OpenCV-Einfhrung nden. a u Die Klassenvariablen pColorImg bzw. pGrayImg sind Zeiger auf IplImage-Objekte, die auf ein Farbbild (3 Kanal RGB) bzw. ein Grauwertbild (1 Kanal Helligkeit) verweisen. In OpenCV werden die Farbbilder pro Pixel ublicherweise mit 8 Bit pro Farbkanal bzw. bei Grauwertbildern mit 8 Bit fr den Helligkeitskanal gespeichert. u Zunchst soll geprft werden, ob bereits ein Farbbild vorhanden ist. Nur in dem Fall a u wird die Funktion fortgesetzt. Nachdem der Speicherplatz fr das eventuell vorhandene u alte Bild freigegeben worden ist, muss ein neues Einkanal-Grauwertbild angelegt werden, das der Ausung des aktuellen Farbbildes entspricht. Die Methode cvCreateImage o gibt einen Zeiger auf ein neu erstelltes IplImage zurck. Dieser soll der Klassenvariable u pGrayImage zugewiesen werden. Die bentigten Parameter sind die Hhe und Breite o o des Bildes, die als cvSize ubergeben und aus dem pColorImage-Struct ausgelesen werden knnen. Auerdem muss der Datentyp (Depth) des zu erzeugenden Bildes und o die Anzahl der Kanle ubergeben werden. Da die Grauwerte im Wertebereich 0 bis 255 a dargestellt werden sollen, kann die Tiefenkonstante IPL_DEPTH_8U (8 Bit Unsigned) verwendet werden. Ein Zielpixel des Grauwertbildes soll sich nun aus der gewichteten Summe der Farbkanle des entsprechenden Quellpixels ergeben. Berechnen Sie das Grauwertbild, indem a Sie alle Pixel innerhalb einer Schleife druchlaufen. Eine typische Kanalgewichtung bei der Umrechnung eines RGB-Pixels in ein Grauwertpixel ist R 11 + G 16 + B 5 32 Auf welche Art und Weise Sie auf die einzelnen Pixelelemente zugreifen knnen, entneho men Sie dem Abschnitt Accessing image elements aus der oben genannten Einfhrung. u Beachten Sie insbesondere die notwendigen Typumwandlungen (typecast) beim Zugri in den dort aufgefhrten Beispielen sowie darauf, dass OpenCV die Farbkanle nicht in u a GRAY =

Seite 5 von 13

Abbildung 1: Ein Rechteck-Filterkernel mit dem Koordinatenursprung im Zentrum. Links betrgt der Radius 1, rechts 2. a der Reihenfolge RGBRGB..., sondern BGRBGR... speichert. Anschlieend soll das berechnete Grauwertbild angezeigt werden. Starten Sie das Programm und testen Sie die Grauwertkonvertierung. Hinweis: OpenCV besitzt bereits eine Methode zur Konvertierung eines Farbbildes in ein Grauwertbild. Zu Ubungszwecken soll dies jedoch einmal selbst implementiert werden. j) (lowPassFilter) Abschlieend soll die Methode lowPassFilter bearbeitet werden, die einen Tiefpasslter implementieren soll. Das Tiefpassltern ist eine hug ana gewendete Operation, die z.B. zur Rauschreduktion eingesetzt wird. Sie kann mittels lokaler Operatoren im Ortsbereich berechnet werden (siehe Bildverbesserungkapitel der MMI-Vorlesung, Kapitel 3.2.3 B, Skript S. 52). Die Filterkerngre soll uber einen variablen Radius steuerbar sein (siehe Abbildung 1), o so dass die Gre des Filterkern-Fensters n n betrgt, wobei n = 2r + 1 gelten soll. o a Das Fenster soll uber alle Pixelpositionen (x, y) des Quellbildes gelegt und auf diese Weise der Mittelwert des Bildausschnitts unter dem Fenster errechnet werden. Dieser Mittelwert wird dann in das Zielbild an der Position (x, y) eingetragen. Da das Tiefpassltern keine In Place Operation ist, muss zunchst eine temporre, lokale Kopie a a des aktuellen Grauwertbildes angelegt werden. Anschlieend kann das Grauwertbild, auf das der Zeiger pGrayImg verweist, als Zielbild verwendet werden. Die Pixelpositionen (x, y) knnen mit Hilfer einer geschachtelten Schleife durchlaufen o werden. Um auf die einzelnen Pixelwerte unterhalb des Operatorfensters zuzugreifen, die relativ zur aktuellen Position (x, y) deniert sind, knnen Sie eine weitere geschachtelte o Schleife einsetzen. Bedenken Sie bei ihrer Implementierung den Fall, dass das Operatorfenster je nach Position uber den Bildrand hinaus ragen kann. Behandeln Sie diesen Fall entsprechend. Zeigen Sie schlielich das tiefpassgelterte Grauwertbild an und geben Sie alle nicht weiter bentigten Ressourcen wieder frei. Starten Sie das Programm und testen Sie die o implementierte Methode. Fhren Sie die Tiefpasslterung mehrfach hintereinander aus. u Was fllt nach vielen Iterationen auf? Begrnden Sie ihre Antwort. a u

Seite 6 von 13

Handgestenerkennung mit OpenCV


Informationen zur Projektaufgabe: Die Projektaufgabe Handgestenerkennung mit OpenCV ist dem Themengebiet Computersehen zuzuordnen und soll an das Arbeitsgebiet der digitalen Bildverarbeitung heranfhren. u Ziel der Aufgabe ist es, die unter anderem aus den Vorlesungen MMI und Digitale Bildverarbeitung bekannte Bildverarbeitungspipeline zu implementieren, um unterschiedliche Handgesten in fortlaufenden Kamerabildern in Echtzeit zu erkennen. Montieren Sie dazu eine USBKamera mit Hilfe eines geeigneten Stativs so, dass diese eine Hand vor einem Hintergrund erfasst, der sich Farblich mglichst von der Hand abhebt, und verbinden Sie die Kamera mit o dem PC. Das Programm soll sowohl dazu in der Lage sein, anzugeben, wie viele Finger ausgestreckt sind (also 0 bis 5) als auch den Fall erkennen knnen, dass sich keine Hand im Bild o bendet. Die Abbildung 2 zeigt eine Beispielkonguration. Zunchst soll ein Kamerabild erfasst und in ein Grauwertbild konvertiert werden. Die anschliea ende Anwendung eines einfachen, adaptiven Schwellenwertoperators sowie morphologischer Operationen sollen das Bild mglichst optimal fr die nachstehende Merkmalsextraktion voro u bereiten. Aufgrund des engen Zeitrahmens soll die Einschrnkung auf einfache chen- und a a konturbasierte Merkmale gengen. Mit Hilfe der extrahierten Merkmale soll schlielich die u Handgeste von einem zuvor entsprechend kalibrierten Klassikator bestimmt und das Ergebnis als Feedback in Form einer Textausgabe an den Benutzer weitergegeben werden. Zur Bearbeitung der aktuellen Projektaufgabe soll C/C++ in Kombination mit der ComputerVision Bibliothek OpenCV genutzt werden, die im Rahmen der Vorbereitungsaufgabe bereits eingefhrt worden ist. u Aufgabenstellung: Handgestenerkennung mit OpenCV a) Entpacken Sie das Archiv OpenCV_Handgesture.zip und nen Sie das im Uno terordner OpenCV_Handgesture bendliche Projekt OpenCV_Handgesture.sln. Machen Sie sich mit der Struktur des Programms vertraut. Die wichtigste Klasse ist GestureRecognizer. Sie verwendet die beiden Klassen ImageProcessor, die fr die u eigentliche Bildverarbeitung zustndig ist, und Classifier, die extrahierte Merkmaa le des verarbeiteten Bildes klassiziert und schlielich die durch den Benutzer gezeigte Handgeste angibt. b) Ergnzen Sie den Konstruktor der Klasse GestureRecognizer um ein cvNameda Window, um IplImages anzeigen zu knnen. Falls Sie spter weitere Fenster bentigen, o a o fgen Sie den entsprechenden Code ebenfalls dem Konstruktor hinzu. Der Destruktor u sollte die im Konstruktor belegten Ressourcen wieder freigeben. c) Die Klasse GestureRecognizer besitzt, ahnlich wie in der Vorbereitungsaufgabe, die Hauptschleife des Programms, die in jedem Durchlauf ein Kamerabild abarbeiten soll und die sich in der Methode startMainLoop bendet. Innerhalb der Hauptschleife soll die komplette Bildverarbeitungspipeline implementiert werden, so dass sie auf jedes Kamerabild angewendet werden kann. Die Hauptschleife soll am Ende die folgenden Schritte realisieren:

Seite 7 von 13

Abbildung 2: Aufbaukonguration

Abbildung 3: Beobachtetes Kamerabild

Abfrage und Bearbeitung der Tastatureingabe Zugri auf das aktuelle Kamerabild Verarbeitung des Bildes (Bildverbesserung) Merkmalsextraktion Klassikation Ausgabe der erkannten Geste in Textform Anzeigen des aktuellen (verarbeiteten) Bildes Da jetzt alle Bilder des Kameravideostroms ausgewertet werden sollen, ohne jedes Mal die Verbindung uber cvCaptureFromCAM neu aufzubauen, fgen Sie die Bereitstellung u des Zugris auf die Kamera vor der Schleife ein. Innerhalb der Hauptschleife soll zunchst die Tastatureingabe abgefragt werden. Falls a eine Eingabe erfolgt ist, soll diese in der Methode processKey verarbeitet werden. Ergnzen Sie processKey so, dass die Hauptschleife, die von der Klassenvariable runa Loop anhngig ist, beim Drcken der Esc-Taste beendet wird. a u Setzen Sie als nchstes in der Hauptschleife den bereits deklarierten Zeiger pCamImg a auf das aktuelle Kamerabild, das Sie mit cvQueryFrame erhalten. Zeigen Sie am Ende der Hauptschleife das aktuelle Bild an. Geben Sie nach der Hauptschleife die Kameraressourcen wieder frei. Das Bildobjekt, auf das der Zeiger pCamImg verweist, darf jedoch nicht explizit freigegeben werden. Die entsprechenden Daten werden innerhalb des CvCapture-Objekts verwaltet und bei dessen Freigabe automatisch gelscht. o Starten Sie das Programm und prfen Sie, ob der Videostrom angezeigt wird, also ob die u Kamerabild fortlaufend aktualisiert. Beenden Sie das Programm mit der Esc-Taste.

Seite 8 von 13

d) Um das Kamerabild dahingehend zu bearbeiten, dass eine mglichst einfache Merkmalso extraktion ermglicht wird, muss es zunchst bearbeitet werden. Dies soll innerhalb der o a Klasse imageProcessor geschehen. Als einzige Klassenvariable besitzt imageProcessor den Zeiger resultImg. Dieser verweist auf ein IplImage, das das Ergebnis der Bildbearbeitung speichert. Die Methode processImg, die ein Eingabebild sowie weitere Parameter entgegennimmt, fhrt die Bildbearbeitung durch und gibt einen Zeiu ger auf das Ergebnisbild zurck. u Da sich die Ausung des Kamerabildes whrend des Videos nicht andert, jedoch zum o a Zeitpunkt der Bearbeitung bereits angelegt sein soll, soll das Ergebnisbild im Konstruktor der Klasse imageProcessor erzeugt werden. Um die Bildgre passend zu whlen, o a erwartet der Konstruktor als Parameter ein IplImage. Ergnzen Sie den Konstruktor so, a dass ein neues IplImage angelegt wird, das die Gre des als Parameter ubergebenen o Bildes hat, jedoch ein Grauwertbild ist (also genau einen Kanal besitzt) und weisen Sie dieses Bild dem Zeiger resultImg zu. Der Destruktor soll die Bildressourcen des Ergebnisbildes, falls vorhanden, wieder freigeben. Erzeugen Sie noch vor der Hauptschleife der Klasse GestureRecognizer ein imageProcessor-Objekt und ubergeben Sie als Parameter ein aktuelles Kamerabild, das Sie uber cvQueryFrame erhalten. Innerhalb der Hauptschleife soll die processImg Methode des ImageProcessors aufgerufen und das Ergebnisbild dem Zeiger resultImg zugewiesen werden. Auerdem soll am Ende der Hauptschleife nicht mehr das Kamerabild, sondern das Ergebnisbild ausgegeben werden. e) Als nchstes geht es um die Implementierung der Methode processImg, die das Bild a fr eine einfache Merkmalsextraktion vorbereiten soll. Als Merkmal soll spter zunchst u a a die gre der Flche, die die Hand im Bild einnimmt, verwendet werden. o a Dazu soll eine einfache schwellenwertbasierte Segmentierung des Bildes durchgefhrt u werden, so dass jedes Pixel entweder der Hand oder dem Hintergrund zugeordnet wird. Der Schwellenwert T sowie das zu bearbeitende Bild werden der Methode processImage als Parameter ubergeben. Da das Kamerabild in der Regel ein Farbbild (3 Kanle), das Ergebnisbild resula tImg jedoch ein Grauwertbild (1 Kanal) ist, muss zunchst eine Konvertierung durcha gefhrt werden. Anstatt einer einfach RGB-zu-Grauwertkonvertierung soll jedoch mit u den Farbkanalgewichtungen experimentiert werden. Uberlegen Sie sich dazu, zu welchem Anteil welche Kanle geeignet sind, um Hautfarben mglichst gut von einem a o nicht-hautfarbenden Hintergrund unterscheiden zu knnen. Testen Sie ihre Hypotheo sen, indem Sie das Programm starten und untersuchen, welche Gewichtungen einen mglichst groen Kontrast zwischen der Hautfarbe und dem Hintergrund erzeugen. o f) Auf dem errechneten Grauwertbild in der Methode processImg soll als nchstes der a als Parameter ubergebene Schwellenwert T angewendet werden. Setzen Sie alle Pixel, deren Grauwert kleiner als T ist auf 0, andernfalls auf einen Grauwert ungleich 0, z.B. 100. Dadurch wird das Bild binrwertig, und es liegt eine Segmentierung in Handpixel a und Hintergrundpixel vor (siehe Abbildung 4). Kritisch ist dabei die Wahl des Schwel-

Seite 9 von 13

Abbildung 4: SchwellenwertOperator

Abbildung 5: Mathematische phologie

Mor-

lenwertes. Um auf unterschiedliche Helligkeitseinsse exibel reagieren zu knnen, soll u o der Schwellenwert durch den Benutzer angepasst werden knnen. Ergnzen Sie dazu die o a Methode processKey der GestureRecognizer-Klasse so, dass beim Drcken der u + bzw. - Taste der Schwellenwert T vergrert bzw. verkleinert wird. o Starten Sie das Programm, beobachten Sie das angezeigte Bild und suchen Sie durch Anpassung des Schwellenwertes nach einer Konguration, die die Hand mglichst gut o vom Hintergrund abtrennt. g) Trotz Anpassung des Schwellenwertes ist es aufgrund von Rauschen und feinen Strukturen der Haut oder des Hintergrundes nicht mglich, die Hand- bzw. Hintergrundreo gion homogen zu segmentieren. An dieser Stelle kann die mathematische Morphologie (Grauwertmorphologie) helfen, um feine und damit in unserem Fall unwichtige Details zu entfernen und, durch das Schlieen kleiner Lcken, ein homogeneres Ergebnis zu eru zielen. Dazu soll auf das binrwertige Bild das sog. Opening, gefolgt von einem Closing, a durchgefhrt werden. Das Opening setzt sich aus den Operationen Erosion, gefolgt von u der Dilatation, zusammen; das Closing genau umgekehrt aus Dilatation, gefolgt von der Erosion. Dabei wird das sog. strukturierende Element uber das gesamte Bild geschoben (hnlich wie bei der Anwendung eines Filterkerns in der Vorbereitungsaufgabe). Machen a Sie sich die Funktionsweise anhand des Digitale Bildverarbeitung-Skriptes (Kapitel B, Bildverbesserung, Seite 99), des Buches Digital Image Processing von Gonzalez, Woods, Kap. 8.4.5 oder des Artikels http://en.wikipedia.org/wiki/Mathematical_morphology klar. OpenCV bietet bereits die beiden Grundoperationen cvErode und cvDilate ( In Place-Implementierung). Entnehmen Sie die Details der C-Dokumentation. Kombinieren Sie die beiden Methoden, um ein Opening, gefolgt von einem Closing, zu realisieren. Verwenden Sie dabei das strukturierende Element, dass OpenCV als Default nutzt (NULL). Ein mgliches Ergebnis ist in Abbildung 5 zu sehen. o Fhren Sie das Programm aus und testen Sie, ob die mathematische Morphologie, anu gewendet auf das binrwertige Bild, ein besseres Ergebnis liefert als zuvor. Experimena tieren Sie mit der Anzahl der Iterationen, die bei den Operationen cvErode und cvDilate jeweils durchgefhrt werden sollen und ermitteln Sie einen brauchbaren Wert. u

Seite 10 von 13

h) Innerhalb der Hauptschleife soll auf dem Ergebnisbild, das nach dem Aufruf der processImg-Methde des imageProcessors zur Verfgung steht, eine Merkmalsextraku tion durchgefhrt werden. Als Merkmal soll die Anzahl der Pixel gezhlt werden, die zur u a Hand gehren. Speichern Sie dieses Bildmerkmal in der Klassenvariable imageFeature o ab. i) Um anhand des extrahierten Bildmerkmals zu entscheiden, welche Handgeste vom Benutzer gezeigt wird, soll mit Hilfe eines Klassikators eine Klassikation durchgefhrt u werden. Die Klasse Classifier soll einen einfachen Klassikator realiseren, der zum einen durch eine Benutzerinteraktion angelernt werden soll, und zum anderen in der Lage ist, anhand angelernter Beispieldaten eine Klassikation eines gegebenen Bildmerkmals, und dadurch der im Bild dargestellten Handgeste, durchzufhren. u Die Klassen, zwischen denen anhand des Bildmerkmals klassiziert werden soll, werden als Array in der Klasse Classifier gespeichert. Der Konstruktor erwartet die Anzahl der Klassen als Parameter. Jede Klasse besitzt einen Namen und einen sie charakterisierenden Merkmalswert. Uber die Methoden setClassName bzw. setClassFeature lassen sich die Bezeichnung einer Klasse als Zeichenkette bzw. der Merkmalswert einer Klasse als Integer angeben. Zu einem gegebenen Merkmalswert soll die Methode getIndexOfClosestClass den Index der Klasse zurckgeben, deren Merkmalswert dem als Parameter ubergebeu nen Wert am hnlichsten ist. Dabei entspricht der Index der Position der Klasse in a dem Array. getNameOfClosestClass soll analog den Namen der passendsten Klas se zurckgeben. Implementieren Sie die Methoden getIndexOfClosestClass und u getNameOfClosestClass, wobei fr einen ubergebenen Merkmalswert die Klasse u am hnlichsten sein soll, deren Merkmalswert die geringste Merkmalsdierenz zum a ubergebenen Merkmalswert aufweist. Erzeugen Sie im Konstruktor der Klasse GestureRecognizer ein neues Classi fier-Objekt und weisen Sie es der Klassenvariable pClassifier zu. Ubergeben Sie entsprechend der Aufgabenstellung die Anzahl der bentigen Klassen als Parameter. Im o Destruktor soll der Klassikator wieder gelscht werden. o Ergnzen sie als nchstes die Methode configureClassifier der Klasse Gestura a eRecognizer, indem Sie den einzelnen Klassen des Klassikators passende Namen vergeben. Die Namen sollten die verschiedenen Handgesten bezeichnen. Rufen Sie die Methode direkt nach der Erzeugung des Klassikators, die im Konstruktor der Klasse GestureRecognizer durchgefhrt wird, auf. u j) Bevor der Klassikator eingesetzt werden kann, muss er zunchst kalibriert ( angelernt) a werden. In unserem Fall gilt es fr die einzelnen Klassen die fr die jeweiligen Handgesten u u charakteristischen Merkmalswerte zu bestimmen und zu speichern. Dazu kann das in der Hauptschleife berechnete Bildmerkmal imageFeature verwendet werden. Die Idee dabei ist, eine bestimmte Geste in die Kamera zu halten und das zu der Handgeste berechnete Bildmerkmal in die entsprechende Klasse des Klassikators zu speichern. Es soll auch mglich sein, die Merkmalswerte einzelner Klassen zur Laufzeit neu kalibrieren o

Seite 11 von 13

Abbildung 6: Flchenbasierte a Bildmerkmale zu knnen. o

Abbildung 7: Kantenbasierte Bildmerkmale

Erweitern Sie dazu die Methode processKey so, dass z.B. beim Drcken der Taste u 1 der Wert des aktuellen Bildmerkmals in die entsprechende Klasse des Klassikators geschrieben wird. Beim Kalibrieren der Klassen muss dann zur Laufzeit beim Beta tigen einer der gewhlten Kalibrierungstasten die passende Handgeste in die Kamera a gezeigt werden. Belegen Sie fr jede Geste je eine Taste. Fgen Sie in der Hauptschleife u u einen temporren Zeiger auf eine Zeichenkette hinzu. Rufen Sie die Klassikatormethoa de getNameOfClosestClass mit dem berechneten Bildmerkmal als Parameter auf und weisen Sie die zurckgegebene Zeichenkette dem hinzugefgten Zeiger zu. u u k) Um dem Benutzer die erkannte Geste mitzuteilen, soll die Hauptschleife um eine Textausgabe in das Bild resultImg ergnzt werden. Zum einen soll die Bezeichnung der a Handgeste ausgegeben werden, die zum aktuellen Bildmerkmal am besten passt. Zum anderen sollen weitere Informationen wie der aktuelle Schwellenwert und der Wert des Bildmerkmals ausgegeben werden. Implementieren Sie die geschilderte Funktionalitt in der Methode printInfotexta ToImage der Klasse GestureRecognizer und fhren Sie sie in der Hauptschleife vor u dem Anzeigen des Ergebnisbildes aus. l) Starten Sie das Programm und passen Sie den Schwellenwert mglichst optimal an. o Fhren Sie eine Kalibrierung fr alle in der Aufgabenstellung genannten Handgesten u u durch und prfen Sie anschlieend, ob diese korrekt erkannt werden. Experimentieren u Sie noch einmal mit den Parametern des Programms (Farbkanalgewichtung und Anzahl der Iterationen bei den morphologischen Operationen) und versuchen Sie dadurch eine mglichst optimale Erkennung der gezeigten Handgesten zu erreichen. o m) Bislang basiert das extrahierte Bildmerkmal auf der von der Hand eingenommen Fla che (siehe Abbildung 6). Das Programm soll nun dahingehend erweitert werden, dass stattdessen die Lnge der Kontur, also die Anzahl der Konturpixel als Merkmal dienen a soll (siehe Abbildung 7). Dazu ist hauptschlich eine Erweiterung der Klasse imagea Processor notwendig.

Seite 12 von 13

Erweitern Sie die Methode processImg so, dass nach den morphologischen Operationen ein Kantendetektor auf dem Ergebnisbild durchgefhrt wird, der Objektkonturen u hervorhebt. Ein gngiger Gradientenoperator ist der Sobel-Operator, der z.B. aus der a Vorlesung Mensch-Maschine-Interaktion (Segmentierung, Kapitel 3.2.4 B, S. 112) bekannt ist. Dieser kombiniert die Detektion horizontaler und vertikaler Kanten. Dabei verwendet der Sobel-Operator ein 3 3-Fenster und gewichtet die unter dem Fenster liegenden Bildpixel entsprechend der im Skript angegebenen Formel:

gSOBEL = |(A + 2B + C) (G + 2H + I)| + |(A + 2D + G) (C + 2F + I)| , wobei A bis I die Grauwerte des Quellbildes unter dem 3 3-Fenster an den Positionen A B C D E F G H I angeben. Das Fenster ist an der Position E zentriert. Orientieren Sie sich bei der Implementierung an dem Tiefpasslter aus der Vorbereitungsaufgabe. Da es sich auch hier um keine In Place-Operation handelt, bentigen Sie ein Hilfsbild. Passen Sie die Klasse o imageProcessor entsprechend an. Tipp: Das Ergebnis des Sobeloperators kann auerhalb des Wertebereichs des Bildes liegen, auf dem er angewendet wird. Folglich muss der Datentyp des Hilfsbildes entsprechend gewhlt werden. Siehe Dazu den Abschnitt OpenCV naming conventions in der a oben genannten Einfhrung. u n) Um die Merkmalsextraktion, die ein binrwertiges Bild erwartet, nicht ndern zu msa a u sen, soll das berechnete Kantenbild ebenfalls durch einen weiteren Schwellenwert binrwertig gemacht werden. Erweitern Sie sowohl die Klasse GestureRecognizer um a einen weiteren Schwellenwert T2 so, dass auch dieser durch den Benutzer uber die Tastatureingabe verndert werden kann. Passen Sie die Schnittstelle der Methode proa cessImg an, um den Schwellenwert zu ubergeben. Zeichnen Sie T2 ebenfalls als Text in das Ergebnisbild ein. Tipp: Um an Performance zu gewinnen, knnen Sie den Schwellenwerttest auch direkt o beim berechnen des Sobeloperators auswerten. Testen Sie das Ergebnis und passen Sie den neuen sowie den alten Schwellenwert den Lichtverhltnissen an. Vergleichen Sie die Gestenerkennungsresultate mit der Flchena a basierten Version. Welche der beiden liefert bessere Ergebnisse? Begrnden Sie ihre u Aussage.

Seite 13 von 13