Kinect for Windows SDK開發(fā)入門(十):手勢識(shí)別 上:基本概念
像點(diǎn)擊(clicks)是GUI平臺(tái)的核心,輕點(diǎn)(taps)是觸摸平臺(tái)的核心那樣,手勢(gestures)是Kinect應(yīng)用程序的核心。和圖形用戶界面中的數(shù)字交互不同,手勢是現(xiàn)實(shí)生活中存在的動(dòng)作。如果沒有電腦我們就不需要鼠標(biāo),但是沒了Kinect,手勢依然存在。從另一方面講,手勢是日常生活中人與人之間相互交流的一部分。手勢能夠增強(qiáng)演講的說服力,能夠用來強(qiáng)調(diào)和傳遞情感。像揮手(waving)或者指點(diǎn)(pointing)這些手勢都是某種無聲的演講。
Kinect應(yīng)用程序的設(shè)計(jì)和開發(fā)者的任務(wù)就是將這些現(xiàn)實(shí)生活中存在的手勢映射到計(jì)算機(jī)交互中去以傳達(dá)人的想法。嘗試從鼠標(biāo)或觸摸式的GUI設(shè)計(jì)移植基于手勢的自然交互界面要做很多工作。借鑒過去30多年來對于這一概念的研究,以及從一些Kinect for Xbox的體感游戲中獲取一些設(shè)計(jì)理念,計(jì)算機(jī)工程師和交互設(shè)計(jì)師一起為Kinect創(chuàng)建了一系列新的手勢庫。
本文將會(huì)介紹用戶體驗(yàn)的一些知識(shí),并討論如何將手勢應(yīng)用到Kinect應(yīng)用程序中。我們將展示Kinect如何作為自然交互界面(Natural User Interface)的人機(jī)交互模型的一部分。我們將討論一些具體的使用Kinect來進(jìn)行手勢識(shí)別及交互的例子。更重要的是,將會(huì)展示一些已經(jīng)作為Kinect手勢識(shí)別庫中的手勢。
1. 什么是手勢在許多不同的學(xué)科中,手勢(gesture)有著其獨(dú)特的含義,可能這些含義之間有某些異同。在藝術(shù)領(lǐng)域,手勢被用來傳達(dá)舞蹈中最富表現(xiàn)力的部分,特別是在亞洲舞蹈藝術(shù)中,手勢被作為某些宗教符號(hào)或者象征。在交互設(shè)計(jì)領(lǐng)域,在基于觸摸的自然交互界面中手勢和操控有很大區(qū)別。
以上這些說明手勢在不同的學(xué)科領(lǐng)域都有自己獨(dú)特的含義。在學(xué)術(shù)領(lǐng)域都試圖對手勢定義一個(gè)抽象的概念。在用戶體驗(yàn)設(shè)計(jì)領(lǐng)域使用最廣泛的關(guān)于手勢的定義實(shí)在Eric Hulteen 和Gord Kurtenbach 1990年發(fā)表的一篇名為人機(jī)交互中的手勢(Gestures in Human-Computer Communication),定義如下:”手勢是身體的運(yùn)動(dòng),他包含一些信息。揮手道別是一種手勢。敲擊鍵盤不是手勢,因?yàn)橛檬种傅倪\(yùn)動(dòng)去敲擊按鍵沒有被觀察,也不重要,他只表達(dá)的鍵盤被按下這一動(dòng)作。(A gesture is a motion of the body that contains information. Waving goodbye is a gesture. Pressing a key on a keyboard is not a gesture because the motion of a finger on its way to hitting a key is neither observed nor significant. All that matters is which key was pressed)”
這個(gè)定義既解釋了什么是手勢也解釋了什么不是手勢。像這樣的下一個(gè)正式的定義通常有兩個(gè)方面的困難,既要避免太具體也要避免太抽象。如果一個(gè)定義太具體-如,定義某項(xiàng)技術(shù)-可能會(huì)隨著UI技術(shù)的變化會(huì)變得模糊不清。作為一種學(xué)術(shù)定義而不是以常見的用法為基礎(chǔ)的定義,它也必須足夠一般,并且符合或者說廣大的研究機(jī)構(gòu)先前已發(fā)表在HCI的研究成果及藝術(shù)中符號(hào)學(xué)。另一方面,定義過于寬泛,也會(huì)有有無關(guān)緊要的風(fēng)險(xiǎn):如果一切都是一種姿態(tài),那么就什么都不是了。
Eric Hulteen 和Gord Kurtenbach關(guān)于手勢的定義的中心在于手勢能夠用來交流,手勢的意義在于講述而不是執(zhí)行。
有趣的是將語言和行為引入到人機(jī)交互接口中來,這是一種徹底的變革。我們與計(jì)算機(jī)交互語音變?yōu)闊o聲的語言(mute):我們通過指點(diǎn)和手勢而不是語言與計(jì)算設(shè)備進(jìn)行溝通。當(dāng)和計(jì)算機(jī)進(jìn)行交互時(shí),我們點(diǎn)擊鍵盤按鍵或觸摸屏幕。我們似乎更喜歡這種形式的靜音通信即使當(dāng)前的技術(shù)能夠支持更簡單的語音指令。我們沒有操作(manipulation)的力量,和虛擬的對象而不是真實(shí)的物體進(jìn)行交互,因而沒有持久性。運(yùn)動(dòng)成為純粹的手勢。
基于Eric Hulteen 和Gord Kurtenbach的定義,我們都明白什么是 UI 操作 ——暫時(shí)不是一種手勢 ——理解什么是手勢以及手勢表示"重大"行為或者符號(hào)仍然有很大的困難。移動(dòng)交互的含義是什么?手勢進(jìn)行溝通和語言進(jìn)行溝通的最明顯不同是什么?我們做手勢的象征意義往往很抽象簡單。
在人機(jī)交互領(lǐng)域,手勢通常被作為傳達(dá)一些簡單的指令而不是交流某些事實(shí)、描述問題或者陳述想法。使用手勢操作電腦通常是命令式的,這通常不是人們使用手勢的目的。例如,揮手(wave)這一動(dòng)作,在現(xiàn)實(shí)世界中通常是打招呼的一種方式,但是這種打招呼的方式在人機(jī)交互中卻不太常用。通常第一次寫程序通常會(huì)顯示“hello”,但我們對和電腦打招呼并不感興趣。
但是,在一個(gè)繁忙的餐館,揮手這一手勢可能就有不同的含義了。當(dāng)向服務(wù)員招收時(shí),可能是要引起服務(wù)員注意,需要他們提供服務(wù)。在計(jì)算機(jī)中,要引起計(jì)算機(jī)注意有時(shí)候也有其特殊意義,比如,計(jì)算機(jī)休眠時(shí),一般都會(huì)敲擊鍵盤或者移動(dòng)鼠標(biāo)來喚醒,以提醒計(jì)算機(jī)“注意”。當(dāng)使用Kinect時(shí),可以使用更加直觀的方式,就行少數(shù)派報(bào)告阿湯哥那樣,抬起雙手,或者簡單的朝計(jì)算機(jī)揮揮手,計(jì)算機(jī)就會(huì)從休眠狀態(tài)喚醒。
在人機(jī)交互領(lǐng)域,手勢通常有一些含義,表示有意讓某些事情發(fā)生。手勢是一種指令。當(dāng)通過鼠標(biāo)或者觸控板去點(diǎn)擊UI界面上的按鈕時(shí),我們希望按鈕會(huì)觸發(fā)其背后的事件。通常,按鈕上會(huì)有一個(gè)標(biāo)簽來指示按鈕的功能如:開始、取消、打開、關(guān)閉。我們的手勢操作就是想要實(shí)現(xiàn)這些事件。
上面的定義中的第一點(diǎn)可以得出,手勢的另一個(gè)特點(diǎn)是比較隨意(arbitrary)。手勢有限定的領(lǐng)域,那么在該領(lǐng)域之外沒有任何意義。令人驚訝的是除了指向(pointing)和聳肩(shurg),人類學(xué)家沒有發(fā)現(xiàn)任何東西我們可以稱之為一種通用的手勢。然而,在計(jì)算機(jī)的UI中,指向(pointing)通常被認(rèn)為是直接操作因?yàn)樗鼱可娴礁櫍瑫r(shí)聳肩的含義太微妙而不好辨識(shí)。因此,我們想要使用的任何Kinect手勢必須基于應(yīng)用程序的用戶 和應(yīng)用程序的設(shè)計(jì)和開發(fā)者之間就某種手勢代表的含義達(dá)成一致。
因?yàn)槭謩菔侨我獾?arbitrary)所以他們也是基于約定的(conventional)。應(yīng)用程序的設(shè)計(jì)者必須告訴用戶正在使用的手勢的意義,或者是這些手勢是約定俗稱大家都知道的。此外,這些約定不是基于語言文化,而是對已確定的技術(shù)規(guī)則。我們知道如何使用鼠標(biāo) (行為學(xué)習(xí)) 并不是因?yàn)檫@是我們已經(jīng)從我們的文化導(dǎo)入的東西,而是因?yàn)檫@是基于特定的圖形用戶界面的跨文化約定。同樣地,我們知道如何點(diǎn)擊或滑動(dòng)智能手機(jī),不是因?yàn)檫@些都是文化的約定,而是因?yàn)檫@些都是跨文化自然用戶界面項(xiàng)約定。有趣的是,我們在一定程度上知道如何點(diǎn)擊平板電腦,因?yàn)槲覀円郧皩W(xué)習(xí)了如何使用鼠標(biāo)單擊。技術(shù)約定之間可以相互轉(zhuǎn)化,這是因?yàn)檎Z言和手勢可以通過不同的語言和文化之間來轉(zhuǎn)換。
然而,手勢的這種任意性和基于約定的特性也帶來了誤解性(misunderstanding),這是在設(shè)計(jì)任何用戶界面,尤其是像Kinect這樣的沒有任何預(yù)先設(shè)定好的操作約定的用戶界面時(shí)需要關(guān)注的風(fēng)險(xiǎn)。就像在有些國家,點(diǎn)頭表示否定搖頭表示可能。手勢,或者任何身體的運(yùn)動(dòng),都有可能產(chǎn)生誤解。
總之,在人機(jī)交互領(lǐng)域,手勢是:
表達(dá)一種簡單的命令天生有隨意性基于某種協(xié)定可能被誤解注意:實(shí)際的直接操作(manipulation)不是手勢。
2. 自然交互界面(NUI)討論手勢而不討論自然用戶界面顯然不完整。自然用戶界面是一系列技術(shù)的合計(jì),他包括:語音識(shí)別,多點(diǎn)觸控以及類似Kinect的動(dòng)感交互界面,他和Windows和Macs操作系統(tǒng)中鼠標(biāo)和鍵盤交互這種很常見圖形交互界面不同。就像圖像交互界面和之前的命名行交互界面不同那樣。
自然交互界面自然在哪兒呢?早期自然交互界面的發(fā)起者認(rèn)為交互界面的設(shè)計(jì)應(yīng)該對用戶非常直觀,使用用戶先天就會(huì)的行為來進(jìn)行交互操作。他的目標(biāo)是不需要操作由圖標(biāo)和菜單構(gòu)成的基于GUI 的應(yīng)用程序界面,因?yàn)檫@種界面通常具有陡峭的學(xué)習(xí)曲線。相反,理想化的狀態(tài)是,用戶應(yīng)該能夠走到應(yīng)用程序前面,就能夠開始使用它。在過去的幾年里隨著觸摸功能的智能手機(jī)和平板電腦的流行,逐漸取代了鍵盤鼠標(biāo),當(dāng)我們看到孩子們開始走到任何觸摸屏設(shè)備面前,用手去觸摸它,期待它的響應(yīng),在這一點(diǎn)上看這一理念已經(jīng)實(shí)現(xiàn)。
雖然自然用戶界面的自然性似乎是直接操作的最佳寫照,當(dāng)使用手指來進(jìn)行觸摸交互時(shí),先天自然和后天學(xué)習(xí)行為之間的對立被打破。一些手勢,如輕觸屏幕,在某種意義上就是先天就會(huì)的動(dòng)作。其他的動(dòng)作比如說雙擊,獲得點(diǎn)擊然后拖拉等,沒有先天就會(huì)。而且隨著不同的設(shè)備制造商開始支持不同觸摸手勢,為了使得相同的手勢在不同的觸摸平臺(tái)上有相同的意義和行為,為某些手勢定義一些約定顯得更加重要。
自然用戶界面(NUI)的自然性更多的是一種相對自然的概念。對于NUI的更現(xiàn)代的理解受Bill Buxton所影響。他認(rèn)為NUI界面的設(shè)計(jì)充分利用了用戶預(yù)先就會(huì)的技能,用戶和UI進(jìn)行交互感到很自然,使得他們甚至忘了是從哪里學(xué)到這些和UI進(jìn)行交互所需的技能的。換句話說,第一次操作時(shí),我們不記得我們曾經(jīng)學(xué)過這些知識(shí)。例如,輕點(diǎn)(tap)這個(gè)手勢早平板電腦和手機(jī)中使用的很頻繁,這個(gè)技能是從我們之前在傳統(tǒng)的人機(jī)交互界面上使用鼠標(biāo)來指向并點(diǎn)擊某一個(gè)界面上的元素學(xué)來的。點(diǎn)擊(click)和輕點(diǎn)(tap)的最主要區(qū)別在于,點(diǎn)擊需要鼠標(biāo),對于觸摸屏,不需要額外的設(shè)備,只需要用手指輕輕觸摸一下屏幕就可以了。
這引出了自然用戶界面的另一個(gè)特點(diǎn)。用戶和計(jì)算機(jī)之間的交互看起來不需要任何媒介,這種相互作用的媒介是不可見的。例如,在語音識(shí)別界面中,人機(jī)交互是通過具有復(fù)雜電子過濾去噪的麥克風(fēng)實(shí)現(xiàn)的,其內(nèi)部有解析發(fā)音語義單元的各種算法,將這些語義傳遞給其它軟件來進(jìn)行將特定的短語解釋為命令,并將該命令映射到某種軟件功能操作。但是,內(nèi)部的這一切,對用戶是不可見的。當(dāng)用戶對計(jì)算機(jī)發(fā)出這樣的命令,"嘿,注意我",她會(huì)認(rèn)為計(jì)算機(jī)會(huì)像類似大多數(shù)人的本能那樣的響應(yīng)這個(gè)命令。
自然用戶界面的 依賴于先驗(yàn)知識(shí)和不需要媒介的交互這兩個(gè)特征是每一種NUI界面的共同特征,其他方面如觸摸,語音和動(dòng)態(tài)交互界面則因設(shè)備的不同而各異。目前,大多數(shù)關(guān)于NUI的設(shè)計(jì)都是基于多點(diǎn)觸控體驗(yàn)的。這就是為什么前面對于手勢的標(biāo)準(zhǔn)定義是那樣定義的。它是將多點(diǎn)觸摸的場景進(jìn)行修改并將手勢和操作區(qū)分開來。
關(guān)于手勢(gesture)和操作(manipulation)的爭論也存在于語音交互界面中,命令等同于手勢,語音等同于直接操作,在動(dòng)態(tài)交互界面中,將手或者身體追蹤展示在可視化界面上手和身體的運(yùn)動(dòng)等同于直接操作。自由形式的運(yùn)動(dòng)像揮手這一動(dòng)作就屬于手勢。
但是Kinect還有第三種交互界面,他和觸摸和語音交互不同。那就上一篇文章中所講的姿勢(pose),姿勢是身體的某一部分和其他部分之間的一種靜態(tài)關(guān)系,他不是運(yùn)動(dòng)的。Kinect中的姿勢和日常生活中的姿勢是一樣的,例如,左臂伸出45度表示將當(dāng)前的窗口變?yōu)榛顒?dòng)的交互窗體,右臂伸出45度或者135度表示垂直滾動(dòng)工具欄。
另外,交互方式可以從一種類型的交互界面轉(zhuǎn)換到另外一種交互界面。以按鈕為例,按鈕其實(shí)就是一個(gè)符號(hào),這是一個(gè)先驗(yàn)的圖形用戶界面。從最基本的功能來講,按鈕就是一個(gè)通過鼠標(biāo)點(diǎn)擊在一個(gè)可視化元素的文字或者圖像上觸發(fā)一些命令的工具。在過去15年,按鈕被作為人機(jī)交互界面的一個(gè)集成部分,被轉(zhuǎn)換到多點(diǎn)觸摸界面,以及Kinect用戶界面中來。
自然用戶界面設(shè)計(jì)師所追求的是的是自然,按鈕恰好提供了這一點(diǎn)。但是按鈕在每一種用戶界面中的轉(zhuǎn)換都面臨著一些挑戰(zhàn)。
圖形用戶界面中按鈕的一個(gè)通常的特征是他提供了一個(gè)懸浮狀態(tài)來指示用戶光標(biāo)已經(jīng)懸停在的按鈕上方的正確位置。這種懸浮狀態(tài)將點(diǎn)(click)這個(gè)動(dòng)作離散開來。懸浮狀態(tài)可以為按鈕提供一些額外的信息。當(dāng)將按鈕移植到觸摸屏交互界面時(shí),按鈕不能提供懸浮狀態(tài)。觸摸屏界面只能響應(yīng)觸摸。因此,和電腦上的圖像用戶界面相比,按鈕只能提供“擊”(click)操作,而沒有“點(diǎn)”(point)的能力。
當(dāng)將按鈕移植到基于Kinect的用戶界面上時(shí),按鈕的行為就變得更加特殊了?;贙inect的圖形界面中,按鈕的行為和觸摸界面中的剛好相反,他只提供了懸?。╤over)的“點(diǎn)”(point)的能力,沒有“擊”(click)的能力。按鈕這種更令用戶體驗(yàn)設(shè)計(jì)者感到沮喪的弱點(diǎn),在過去的幾年里,迫使設(shè)計(jì)者不斷的對Kinect界面上的按鈕進(jìn)行改進(jìn),以提供更多巧妙的方式來點(diǎn)擊視覺元素。這些改進(jìn)包括:懸停在按鈕上一段時(shí)間、將手掌向外推(笨拙地模仿點(diǎn)擊一個(gè)按鈕的行為)等。
雖然觸摸界面也有手勢,但Kinect 界面有些互動(dòng)不是手勢,不過軟件的開發(fā)和設(shè)計(jì)者傾向于以 Kinect 手勢操作作為交互界面。這似乎是因?yàn)槭褂檬謩葑鳛槲锢聿僮魇?Kinect 應(yīng)用程序的最大的特點(diǎn)。與此相反的是,觸摸界面的突出特點(diǎn)是直接操作。雖然可能不準(zhǔn)確,人們通常將自然交互界面劃分為三類:語音交互界面,觸摸交互界面和手勢交互界面。
然而,在關(guān)于Kinect的相關(guān)介紹文檔中,你會(huì)發(fā)現(xiàn)有時(shí)候姿勢(pose)和操作(manipulation)都被描述為手勢。這些都沒有錯(cuò)。要記住的是,當(dāng)我們討論Kinect中的一些術(shù)語,如揮手(wave),滑動(dòng)(swipe),我們會(huì)作為純粹的手勢,而姿勢和操控只有在隱喻意義上才稱之為手勢。
以上的討論都很重要,因?yàn)槲覀儠?huì)進(jìn)一步設(shè)計(jì)Kinect互動(dòng)的語意,我們將最終移除從其他圖形界面上借鑒過來的關(guān)于按鈕的語意,然后嘗試建立基于Kinect的先驗(yàn)的語意。揮手(wave)這是Kinect中純粹的手勢,是最早的這種嘗試。喬治亞技術(shù)研究所的研究人員正在利用 Kinect 來解釋美國手語。相反,其他研究人員,正在利用 Kinect 解釋身體語言——另一種預(yù)先形成的手勢和姿勢的溝通。諸如此類的研究可以視為對于NUI的第二層研究。這些逐漸接近了最初NUI人機(jī)交互的原始的夢想,不只是看不見,而且NUI能夠自適應(yīng)以理解我們的行為,而不是迫使我們了解我們和電腦的人機(jī)交互。
3. 手勢從哪里來在手勢交互界面中,純粹的手勢,姿勢和追蹤以及他們之間的組合構(gòu)成了交互的基本術(shù)語。對于Kinect來說,目前可以使用的有8個(gè)通用的手勢:揮手(wave),懸浮按鈕(hover button),磁吸按鈕(magnet button),推按鈕(push button),磁吸幻燈片(magnetic slide),通用暫停(universal pause),垂直滾動(dòng)條(vertical scrolling)和滑動(dòng)(swipping)。其中的一些術(shù)語是微軟自己引入的,有一些是游戲代理商設(shè)計(jì)的,還有一些是Kinect for PC開發(fā)人員為了開發(fā)應(yīng)用而引入的。
很少情況下會(huì)為人際交互界面術(shù)語進(jìn)行定制。通常要將這8種手勢區(qū)分開來,并在一些應(yīng)用中通用也不常見。相似的情況在web術(shù)語和手機(jī)手勢中設(shè)計(jì)新的界面時(shí)也會(huì)遇到,其中只有部分的設(shè)計(jì)能夠變成標(biāo)準(zhǔn)。在網(wǎng)頁設(shè)計(jì)領(lǐng)域,走馬燈和光標(biāo)動(dòng)畫流行一時(shí),并在一片鄙夷聲中迅速消失。在手機(jī)設(shè)計(jì)領(lǐng)域由于蘋果公司在觸摸屏領(lǐng)域的早期地位這種術(shù)語得到了很好的規(guī)范。蘋果引入了一些觸摸手勢術(shù)語,如輕點(diǎn)(tap),點(diǎn)住不放(tap and hold),滑動(dòng)swipe及pinch。
交互術(shù)語形成規(guī)范有幾個(gè)障礙。第一個(gè)就是為了獲得利益而避免標(biāo)準(zhǔn)化。在90年代后期的瀏覽器大戰(zhàn)中,盡管各大廠商在口頭上說標(biāo)準(zhǔn)化協(xié)議很重要,但是在瀏覽器開發(fā)上依舊不停的開發(fā)自己的HTML版本,以吸引開發(fā)者使用他們的技術(shù)。設(shè)備制造商可以利用市場占有率的優(yōu)勢來鎖定消費(fèi)者,通過在他們的手機(jī)上實(shí)現(xiàn)自己定義語意的觸屏,來推行自己的手勢操作。這些都是不自然的行為,因?yàn)椴煌瑥S商對于同一手勢的語意都不同,并且他們看起來不自然,使用不同廠商的產(chǎn)品需要再學(xué)習(xí)。
另一種形成規(guī)范化的障礙是上下文手勢的專利。例如,蘋果公司不能對“滑動(dòng)”(swipe)操作申請專利,但是它可以對“滑動(dòng)解鎖手機(jī)”這個(gè)手勢申請專利,這使得其他公司需要使用這一技術(shù)或者設(shè)計(jì)理念時(shí)要么給蘋果公司支付專利費(fèi),要么將蘋果告上法庭以避免專利費(fèi),或則干脆不使用這一上下文手勢。如果不使用這一上下文手勢,那么產(chǎn)品就破壞了之前我們學(xué)習(xí)到使用很自然的方式滑動(dòng)解鎖手機(jī),音樂播放器,平板電腦等這一約定了。
最后一個(gè)障礙是,設(shè)計(jì)一個(gè)手勢很困難。手勢術(shù)語會(huì)面對一些App Store中手機(jī)應(yīng)用程序和YouTube中視頻應(yīng)用所遇到的一些問題:人們要么會(huì)要么不會(huì)。手勢需要思考如何定義的簡單使得人們能夠去用,這就是長尾理論留下來的問題。
那么什么樣的手勢術(shù)語才是好的呢。如果一個(gè)手勢易于使用,那么他就被認(rèn)為是設(shè)計(jì)良好的。在交互設(shè)計(jì)中,易用性有兩個(gè)方面:可用(affordance)和反饋(feedback)。反饋就是說用戶知道當(dāng)前正在進(jìn)行的操作。在網(wǎng)頁中,點(diǎn)擊按鈕會(huì)看到按鈕有一點(diǎn)偏移,這就表示交互成功。鼠標(biāo)按鍵按下時(shí)的聲音在某種意義上也是一種反饋,他表示鼠標(biāo)在工作。對于Winodw Phone Metro風(fēng)格的界面上的磁貼,開發(fā)這認(rèn)為這些按鈕應(yīng)該足夠大,以容下大面積的觸摸區(qū)域,但是他們也認(rèn)為過大的觸摸區(qū)域會(huì)使得用戶觸摸到區(qū)域外面也會(huì)觸發(fā)注冊的事件。另外,狀態(tài)信息或者確認(rèn)對話框會(huì)在應(yīng)用程序中彈出以提示用戶發(fā)生了一些事情。在 Xbox 的儀表板中,使用Kinect傳感器產(chǎn)生的光標(biāo)懸停在的熱點(diǎn)上開始動(dòng)畫播放。
如果說反饋發(fā)生在操作進(jìn)行中或者之后,那么可用性(affordance)就發(fā)生在操作之前了??捎眯跃褪且环N提示或者引導(dǎo),告訴用戶某一個(gè)可視化元素是可以交互的,指示用戶該元素的用處。在GUI交互界面中,按鈕是能夠最好的完成這些理念的元素。按鈕通過文字或者圖標(biāo)提示來執(zhí)行一些函數(shù)操作。GUI界面上的按鈕通過懸浮狀態(tài)可以提示用戶其用途。最好的可用性-可能有點(diǎn)繞圈-就是約定俗成。用戶知道某一個(gè)可視化元素的用途,因?yàn)橹霸谄渌麘?yīng)用中使用過類似的可視化控件,或者是在其他設(shè)備中執(zhí)行過類似的操作。但是,這一點(diǎn)對于基于Kinect的手勢交互界面來說有點(diǎn)困難,因?yàn)橐磺卸际切碌摹?/P>
通常的做法就是使用借用其他類型交互界面中的約定。在觸摸交互界面中,一個(gè)輕點(diǎn)(tap)手勢和通常的鼠標(biāo)點(diǎn)擊是等同的。響應(yīng)輕點(diǎn)事件的兩個(gè)可視化元素,圖標(biāo)和按鈕,也被設(shè)計(jì)的和傳統(tǒng)的GUI界面上的圖標(biāo)和按鈕一樣,來達(dá)到提示用戶該元素的作用這一目的。Kinect也使用按鈕和圖標(biāo)來使得用戶能夠更加容易使用。因?yàn)镵inect基本上是基于”點(diǎn)”(pointing)而原生不支持“擊”(clicking)。在此之前,軟件界面設(shè)計(jì)者和開發(fā)者的花費(fèi)了很多精力來對手勢交互界面進(jìn)行定制以實(shí)現(xiàn)“擊”這一動(dòng)作。
和觸摸交互界面不一樣,手勢交互界面可以從社會(huì)中人的一般手勢中借用一些手勢操作。這就使得揮手(wave)成為Kinect應(yīng)用程序的經(jīng)典手勢。因?yàn)檫@一姿勢和現(xiàn)實(shí)生活中的姿勢有象征性聯(lián)系使得非常容易理解和使用。軌跡追蹤,雖然在技術(shù)上不是手勢,但是他是另一個(gè)在現(xiàn)實(shí)生活中和指點(diǎn)有聯(lián)系的術(shù)語。當(dāng)在電視機(jī)或者顯示器前揮動(dòng)手時(shí),好的Kinect應(yīng)用程序應(yīng)該能夠追蹤到手的運(yùn)動(dòng),并顯示一個(gè)光標(biāo)隨著手一起運(yùn)動(dòng)。當(dāng)我們在現(xiàn)實(shí)生活中指點(diǎn)物體時(shí),Kinect中的手部追蹤顯示的手形圖標(biāo)的反饋使得程序更加易用。
目前,現(xiàn)實(shí)生活中的易用性手勢在Kinect交互界面中用的比較少,大部分的易用性都是從傳統(tǒng)的GUI界面上的可用性移植過來的。隨著時(shí)間的改變,這一點(diǎn)會(huì)得到改善。在觸摸屏設(shè)備上新的手勢通過在傳統(tǒng)的已經(jīng)建立的約定中添加手指來形成。兩指輕點(diǎn)和一指輕點(diǎn)有些不同,使用兩個(gè)手指或者多個(gè)手指進(jìn)行滑動(dòng)有其獨(dú)特的含義。最終,觸摸手勢全部由手指完成。另一方面,真正的手勢用戶界面,有一個(gè)近乎無限的語意庫,使得我們可以基于現(xiàn)實(shí)生活中相關(guān)聯(lián)的手勢進(jìn)行改進(jìn)。
本文接下來從理論到實(shí)現(xiàn),討論如何實(shí)現(xiàn)手勢識(shí)別,并展示了Kinect中八中基本手勢中的揮手(wave)手勢的識(shí)別。
4. 實(shí)現(xiàn)手勢識(shí)別Microsoft Kinect SDK并沒有包含手勢識(shí)別引擎。因此需要開發(fā)者來定義和手勢識(shí)別。從SDK的Beta版放出以來,一些第三方開發(fā)者創(chuàng)建的手勢引擎已初見端倪。但是,微軟沒有將他們作為標(biāo)準(zhǔn)的引擎??磥磉@可能還要等微軟將手勢識(shí)別引擎添加到SDK中來,或者指明可替代的解決方案。本節(jié)對手勢識(shí)別技術(shù)進(jìn)行了簡單介紹,希望能夠幫助開發(fā)者在標(biāo)準(zhǔn)的手勢識(shí)別引擎出來之前,可以自己動(dòng)手開發(fā)手勢識(shí)別引擎。
手勢識(shí)別相對來說可以簡單也可以很復(fù)雜,這取決與要識(shí)別的手勢。有三種基本的方法可以用來識(shí)別手勢:基于算法,基于神經(jīng)網(wǎng)絡(luò)和基于手勢樣本庫。每一種方法都有其優(yōu)缺點(diǎn)。開發(fā)者具體采用那種方法取決與待識(shí)別的手勢、項(xiàng)目需求,開發(fā)時(shí)間以及開發(fā)水平?;谒惴ǖ氖謩葑R(shí)別相對簡單容易實(shí)現(xiàn),基于神經(jīng)網(wǎng)絡(luò)和手勢樣本庫則有些復(fù)雜。
4.1 基于算法的手勢識(shí)別算法是解決軟件開發(fā)中幾乎所有問題的最基本方法。使用算法的基本流程就是定義處理規(guī)則和條件,這些處理規(guī)則和條件必須符合處理結(jié)果的要求。在手勢識(shí)別中,這種算法的結(jié)果要求是一個(gè)二值型對象,某一手勢要么符合預(yù)定的手勢要么不符合。使用算法來識(shí)別手勢是最基本的方法,因?yàn)閷τ谟幸稽c(diǎn)編程能力的開發(fā)這來說,手勢識(shí)別的代碼易于理解,編寫,維護(hù)和調(diào)試。
但是,最簡單直接的方法也有其缺點(diǎn)。算法的簡單性限制了其能識(shí)別到的手勢的類別。對于揮手(wave)識(shí)別較好的算法不能夠識(shí)別扔(throw)和擺(swing)動(dòng)作。前者動(dòng)作相對簡單和規(guī)整,后者則更加細(xì)微且多變。可能能夠?qū)懸粋€(gè)識(shí)別擺動(dòng)(swing)的算法,但是代碼可能比較費(fèi)解和脆弱。
算法還有一個(gè)內(nèi)在的擴(kuò)展性問題。雖然一些代碼可以重用,但是每一種手勢必須使用定制的算法來進(jìn)行識(shí)別。隨著新的手勢識(shí)別算法加入類庫,類庫的大小會(huì)迅速增加。這就對程序的性能產(chǎn)生影響,因?yàn)樾枰褂煤芏嗨惴▉韺δ骋粋€(gè)手勢進(jìn)行識(shí)別以判斷該手勢的類型。
最后,每一個(gè)手勢識(shí)別算法需要不同的參數(shù),例如時(shí)間間隔和閾值。尤其是在依據(jù)流程識(shí)別特定的手勢的時(shí)候這一點(diǎn)顯得尤其明顯。開發(fā)者需要不斷測試和實(shí)驗(yàn)以為每一種算法確定合適的參數(shù)值。這本身是一個(gè)有挑戰(zhàn)也很乏味的工作。然而每一種手勢的識(shí)別有著自己特殊的問題。
4.2 基于神經(jīng)網(wǎng)絡(luò)的手勢識(shí)別當(dāng)用戶在做手勢時(shí),手勢的形式并不總是足夠清晰到能夠判斷用戶的意圖。例如跳躍手勢,跳躍手勢就是用戶短暫的跳起來,腳離開地面。這個(gè)定義不能夠提供足夠的信息來識(shí)別這一動(dòng)作。
咋一看,這個(gè)動(dòng)作似乎足夠簡單,使得可以使用算法來進(jìn)行識(shí)別。首先,考慮到有很多種不同形式的跳躍:基本跳躍(basic jumping)、 跨欄(hurdling)、 跳遠(yuǎn)(long jumping)、 跳躍(hopping),等等。但是這里有一個(gè)大的問題就是,由于受到Kinect視場區(qū)域的限制,不可能總是能夠探測到地板的位置,這使得腳部何時(shí)離開地板很難確定。想象一下,用戶在膝蓋到下蹲點(diǎn)處彎下,然后跳起來。手勢識(shí)別引擎應(yīng)該認(rèn)為這是一個(gè)手勢還是多個(gè)手勢:下蹲或 下蹲跳起或者是跳起?如果用戶在蹲下的時(shí)間和跳躍的時(shí)間相比過長,那么這一手勢可能應(yīng)被識(shí)別為下蹲而不是跳躍。
看到這些,最開始對跳躍的定義就會(huì)變得模糊。這一姿勢很難定義清楚,使得不能夠通過定義一些算法來進(jìn)行識(shí)別,同時(shí)這些算法由于需要定義過多的規(guī)則和條件而變得難以管理和不穩(wěn)定。使用對或錯(cuò)的二值策略來識(shí)別用戶手勢的算法太簡單和不夠健壯,不能夠很好的識(shí)別出類似跳躍,下蹲等動(dòng)作。
神經(jīng)網(wǎng)絡(luò)的組織和判斷是基于統(tǒng)計(jì)和概率的,因此使得像識(shí)別手勢這些過程變得容易控制?;谑裁淳W(wǎng)絡(luò)的手勢識(shí)別引擎對于下蹲然后跳躍動(dòng)作,80%的概率判斷為跳躍,10%會(huì)判定為下蹲。
除了能夠識(shí)別復(fù)雜和精細(xì)的手勢,神經(jīng)網(wǎng)絡(luò)方法還能解決基于算法手勢識(shí)別存在的擴(kuò)展性問題。神經(jīng)網(wǎng)絡(luò)包含很多神經(jīng)元,每一個(gè)神經(jīng)元是一個(gè)好的算法,能夠用來判斷手勢的細(xì)微部分的運(yùn)動(dòng)。在神經(jīng)網(wǎng)絡(luò)中,許多手勢可以共享神經(jīng)元。但是每一中手勢識(shí)別有著獨(dú)特的神經(jīng)元的組合。而且,神經(jīng)元具有高效的數(shù)據(jù)結(jié)構(gòu)來處理信息。這使得在識(shí)別手勢時(shí)具有很高的效率。
使用基于神經(jīng)網(wǎng)絡(luò)進(jìn)行手勢識(shí)別的缺點(diǎn)是方法本身復(fù)雜。雖然神經(jīng)網(wǎng)絡(luò)以及在計(jì)算機(jī)科學(xué)中對其的應(yīng)用已經(jīng)有了好幾十年,建立一個(gè)好的神經(jīng)網(wǎng)絡(luò)對于大多數(shù)程序員來說還是有一些困難的。大多數(shù)開發(fā)者可能對數(shù)據(jù)結(jié)構(gòu)中的圖和樹比較熟悉,而對神經(jīng)網(wǎng)絡(luò)中尺度和模糊邏輯的實(shí)現(xiàn)可能一點(diǎn)都不了解。這種缺乏建立神經(jīng)網(wǎng)絡(luò)的經(jīng)驗(yàn)是一個(gè)巨大的困難,即使能夠成功的構(gòu)建一個(gè)神經(jīng)網(wǎng)絡(luò),程序的調(diào)試相當(dāng)困難。
和基于算法的方法相比,神經(jīng)網(wǎng)絡(luò)依賴大量的參數(shù)來能得到精確的結(jié)果。參數(shù)的個(gè)數(shù)隨著神經(jīng)元的個(gè)數(shù)增長。每一個(gè)神經(jīng)元可以用來識(shí)別多個(gè)手勢,每一個(gè)神經(jīng)遠(yuǎn)的參數(shù)的變化都會(huì)影響其他節(jié)點(diǎn)的識(shí)別結(jié)果。配置和調(diào)整這些參數(shù)是一項(xiàng)藝術(shù),需要經(jīng)驗(yàn),并沒有特定的規(guī)則可循。然而,當(dāng)神經(jīng)網(wǎng)絡(luò)配對機(jī)器學(xué)習(xí)過程中手動(dòng)調(diào)整參數(shù),隨著時(shí)間的推移,系統(tǒng)的識(shí)別精度會(huì)隨之提高。
4.3 基于樣本的識(shí)別基于樣本或者基于模版的手勢識(shí)別系統(tǒng)能夠?qū)⑷说氖謩莺鸵阎氖謩菹嗥ヅ洹S脩舻氖謩菰谀0鍘熘幸呀?jīng)規(guī)范化了,使得能夠用來計(jì)算手勢的匹配精度。有兩種樣本識(shí)別方法,一種是存儲(chǔ)一系列的點(diǎn),另一種方法是使用類似的Kinect SDK中的骨骼追蹤系統(tǒng)。在后面的那個(gè)方法中,系統(tǒng)中包含一系列骨骼數(shù)據(jù)和景深幀數(shù)據(jù),能夠使用統(tǒng)計(jì)方法對產(chǎn)生的影像幀數(shù)據(jù)進(jìn)行匹配以識(shí)別出已知的幀數(shù)據(jù)來。
這種手勢識(shí)別方法高度依賴于機(jī)器學(xué)習(xí)。識(shí)別引擎會(huì)記錄,處理,和重用當(dāng)前幀數(shù)據(jù),所以隨著時(shí)間的推移,手勢識(shí)別精度會(huì)逐步提高。系統(tǒng)能夠更好的識(shí)別出你想要表達(dá)的具體手勢。這種方法能夠比較容易的識(shí)別出新的手勢,而且較其他兩種方法能夠更好的處理比較復(fù)雜的手勢。但是建立這樣一個(gè)系統(tǒng)也不容易。首先,系統(tǒng)依賴于大量的樣本數(shù)據(jù)。數(shù)據(jù)越多,識(shí)別精度越高。所以系統(tǒng)需要大量的存儲(chǔ)資源和CPU時(shí)間的來進(jìn)行查找和匹配。其次系統(tǒng)需要不同高度,不同胖瘦,不同穿著(穿著會(huì)影響景深數(shù)據(jù)提取身體輪廓)的樣本來進(jìn)行某一個(gè)手勢。
5.識(shí)別常見的手勢選擇手勢識(shí)別的方法通常是依賴于項(xiàng)目的需要。如果項(xiàng)目只需要識(shí)別幾個(gè)簡單的手勢,那么使用基于算法或者基于神經(jīng)網(wǎng)絡(luò)的手勢識(shí)別就足夠了。對于其他類型的項(xiàng)目,如果有興趣的話可以投入時(shí)間來建立可復(fù)用的手勢識(shí)別引擎,或者使用一些人家已經(jīng)寫好的識(shí)別算法,接下來本文介紹幾種常用的手勢,并演示如何使用算法的方法來識(shí)別他們,手勢識(shí)別的另外兩種方法由于其復(fù)雜性本文不做介紹。
不論選擇哪種手勢識(shí)別的方法,都必須考慮手勢的變化范圍。系統(tǒng)必須具有靈活性,并允許某一個(gè)手勢有某個(gè)范圍內(nèi)的變動(dòng)。很少有人能夠每次都做一模一樣的手勢。例如,考慮周伯通當(dāng)前左右手畫圓圈這個(gè)手勢,重復(fù)這一手勢10次,圓形的中心每次都在一個(gè)點(diǎn)嗎,圓形的起點(diǎn)和重點(diǎn)每次都在相同的地方嗎?每次畫圓的時(shí)長都一樣嗎?然后使用右手做這個(gè)動(dòng)作,最后比較結(jié)果?;蛘呃瓗讉€(gè)朋友或者家人來做,然后觀察。也可以站在鏡子前面看自己做,或者使用錄像設(shè)備錄下來再看。技巧就是對于某一手勢,讓盡可能多的人來做,然后試圖標(biāo)準(zhǔn)化這一手勢。手勢識(shí)別一個(gè)比較好的方式就是關(guān)注手勢最核心的部分而不是哪些外在的細(xì)枝末節(jié)。
5.1 揮動(dòng)(wave)手勢只要玩過Xbox上的體感游戲,可能都使用過揮手這個(gè)手勢。揮手這一手勢不論年齡大小都能夠做的一個(gè)簡單動(dòng)作。這是一個(gè)友好的,快樂的手勢,人們通常揮手或者招手來打招呼或者道別。在應(yīng)用開發(fā)的上下文中,揮手手勢通常告訴應(yīng)用程序已經(jīng)準(zhǔn)備好了,可以開始體驗(yàn)應(yīng)用了。
揮手是最簡單最基本的手勢。使用算法方法能夠很容易識(shí)別這一手勢,但是之前講到的任何方法也能夠使用。雖然揮手是一個(gè)很簡單的手勢,但是如何使用代碼來識(shí)別這一手勢呢?讀者可以在鏡子前做向自己揮手,然后仔細(xì)觀察手的運(yùn)動(dòng),尤其注意觀察手和胳膊之間的關(guān)系。繼續(xù)觀察手和胳膊之間的關(guān)系,然后觀察在做這個(gè)手勢事身體的整個(gè)姿勢。有些人保持身體和胳膊的不動(dòng),使用手腕左右移動(dòng)來揮手。有些人保持身體和胳膊不動(dòng)使用手腕前后移動(dòng)來揮手??梢酝ㄟ^觀察這些姿勢來了解其他各種不同揮手的方式。
XBOX中的揮手動(dòng)作定義為:從胳膊開始到肘部彎曲。用戶以胳膊肘為焦點(diǎn)來回移動(dòng)前臂,移動(dòng)平面和肩部在一個(gè)平面上,并且胳膊和地面保持平行,在手勢的中部(下圖1),前臂垂直于后臂和地面。下圖展示了這一姿勢。
從圖中可以觀察得出一些規(guī)律,第一個(gè)規(guī)律就是,手和手腕都是在肘部和肩部之上的,這也是大多是揮手動(dòng)作的特征。這也是我們識(shí)別揮手這一手勢的第一個(gè)標(biāo)準(zhǔn)。
第一幅圖展示了揮手這一姿勢的中間位置,前臂和后臂垂直。如果用戶手臂改變了這種關(guān)系,前臂在垂直線左邊或者右邊,我們則認(rèn)為這是該手勢的一個(gè)片段。對于揮手這一姿勢,每一個(gè)姿勢片段必須來回重復(fù)多次,否則就不是一個(gè)完整的手勢。這一運(yùn)動(dòng)規(guī)律就是我們的第二個(gè)準(zhǔn)則:當(dāng)某一手勢是揮手時(shí),手或者手腕,必須在中間姿勢的左右來回重復(fù)特定的次數(shù)。使用這兩點(diǎn)通過觀察得到的規(guī)律,我們可以通過算法建立算法準(zhǔn)則,來識(shí)別揮動(dòng)手勢了。
算法通過計(jì)算手離開中間姿勢區(qū)域的次數(shù)。中間區(qū)域是一個(gè)以胳膊肘為原點(diǎn)并給予一定閾值的區(qū)域。算法也需要用戶在一定的時(shí)間段內(nèi)完成這個(gè)手勢,否則識(shí)別就會(huì)失敗。這里定義的揮動(dòng)手勢識(shí)別算法只是一個(gè)單獨(dú)的算法,不包含在一個(gè)多層的手勢識(shí)別系統(tǒng)內(nèi)。算法維護(hù)自身的狀態(tài),并在識(shí)別完成時(shí)以事件形式告知用戶識(shí)別結(jié)果。揮動(dòng)識(shí)別監(jiān)視多個(gè)用戶以及兩雙手的揮動(dòng)手勢。識(shí)別算法計(jì)算新產(chǎn)生的每一幀骨骼數(shù)據(jù),因此必須記錄這些識(shí)別的狀態(tài)。
下面的代碼展示了記錄手勢識(shí)別狀態(tài)的兩個(gè)枚舉和一個(gè)結(jié)構(gòu)。第一個(gè)名為WavePosition的枚舉用來定義手在揮手這一動(dòng)作中的不同位置。手勢識(shí)別類使用WaveGestureState枚舉來追蹤每一個(gè)用戶的手的狀態(tài)。WaveGestureTracker結(jié)構(gòu)用來保存手勢識(shí)別中所需要的數(shù)據(jù)。他有一個(gè)Reset方法,當(dāng)用戶的手達(dá)不到揮手這一手勢的基本動(dòng)作條件時(shí),比如當(dāng)手在胳膊肘以下時(shí),可調(diào)用Reset方法來重置手勢識(shí)別中所用到的數(shù)據(jù)。
private enum WavePosition{ None = 0, Left = 1, Right = 2, Neutral = 3}private enum WaveGestureState{ None = 0, Success = 1, Failure = 2, InProgress = 3}private struct WaveGestureTracker{ public int IterationCount; public WaveGestureState State; public long Timestamp; public WavePosition StartPosition; public WavePosition CurrentPosition; public void Reset() { IterationCount = 0; State = WaveGestureState.None; Timestamp = 0; StartPosition = WavePosition.None; CurrentPosition = WavePosition.None; }}
下面代碼顯示了手勢識(shí)別類的最基本結(jié)構(gòu):它定義了五個(gè)常量:中間區(qū)域閾值,手勢動(dòng)作持續(xù)時(shí)間,手勢離開中間區(qū)域左右移動(dòng)次數(shù),以及左手和右手標(biāo)識(shí)常量。這些常量應(yīng)該作為配置文件的配置項(xiàng)存儲(chǔ),在這里為了簡便,所以以常量聲明。WaveGestureTracker數(shù)組保存每一個(gè)可能的游戲者的雙手的手勢的識(shí)別結(jié)果。當(dāng)揮手這一手勢探測到了之后,觸發(fā)GestureDetected事件。
當(dāng)主程序接收到一個(gè)新的數(shù)據(jù)幀時(shí),就調(diào)用WaveGesture的Update方法。該方法循環(huán)遍歷每一個(gè)用戶的骨骼數(shù)據(jù)幀,然后調(diào)用TrackWave方法對左右手進(jìn)行揮手姿勢識(shí)別。當(dāng)骨骼數(shù)據(jù)不在追蹤狀態(tài)時(shí),重置手勢識(shí)別狀態(tài)。
public class WaveGesture{ private const float WAVE_THRESHOLD = 0.1f; private const int WAVE_MOVEMENT_TIMEOUT = 5000; private const int LEFT_HAND = 0; private const int RIGHT_HAND = 1; private const int REQUIRED_ITERATIONS = 4; private WaveGestureTracker[,] _PlayerWaveTracker = new WaveGestureTracker[6, 2]; public event EventHandler GestureDetected; public void Update(Skeleton[] skeletons, long frameTimestamp) { if (skeletons != null) { Skeleton skeleton; for (int i = 0; i < skeletons.Length; i++) { skeleton = skeletons[i]; if (skeleton.TrackingState != SkeletonTrackingState.NotTracked) { TrackWave(skeleton, true, ref this._PlayerWaveTracker[i, LEFT_HAND], frameTimestamp); TrackWave(skeleton, false, ref this._PlayerWaveTracker[i, RIGHT_HAND], frameTimestamp); } else { this._PlayerWaveTracker[i, LEFT_HAND].Reset(); this._PlayerWaveTracker[i, RIGHT_HAND].Reset(); } } } }}
下面的代碼是揮手姿勢識(shí)別的主要邏輯方法TrackWave的主體部分。它驗(yàn)證我們先前定義的構(gòu)成揮手姿勢的條件,并更新手勢識(shí)別的狀態(tài)。方法識(shí)別左手或者右手的手勢,第一個(gè)條件是驗(yàn)證,手和肘關(guān)節(jié)點(diǎn)是否處于追蹤狀態(tài)。如果這兩個(gè)關(guān)節(jié)點(diǎn)信息不可用,則重置追蹤狀態(tài),否則進(jìn)行下一步的驗(yàn)證。
如果姿勢持續(xù)時(shí)間超過閾值且還沒有進(jìn)入到下一步驟,在姿勢追蹤超時(shí),重置追蹤數(shù)據(jù)。下一個(gè)驗(yàn)證手部關(guān)節(jié)點(diǎn)是否在肘關(guān)節(jié)點(diǎn)之上。如果不是,則根據(jù)當(dāng)前的追蹤狀態(tài),揮手姿勢識(shí)別失敗或者重置識(shí)別條件。如果手部關(guān)節(jié)點(diǎn)在Y軸上且高于肘部關(guān)節(jié)點(diǎn),方法繼續(xù)判斷手在Y軸上相對于肘關(guān)節(jié)的位置。調(diào)用UpdatePosition方法并傳入合適的手關(guān)節(jié)點(diǎn)所處的位置。更新手關(guān)節(jié)點(diǎn)位置之后,最后判斷定義的重復(fù)次數(shù)是否滿足,如果滿足這些條件,揮手這一手勢識(shí)別成功,觸發(fā)GetstureDetected事件。
private void TrackWave(Skeleton skeleton, bool isLeft, ref WaveGestureTracker tracker, long timestamp){ JointType handJointId = (isLeft) ? JointType.HandLeft : JointType.HandRight; JointType elbowJointId = (isLeft) ? JointType.ElbowLeft : JointType.ElbowRight; Joint hand = skeleton.Joints[handJointId]; Joint elbow = skeleton.Joints[elbowJointId]; if (hand.TrackingState != JointTrackingState.NotTracked && elbow.TrackingState != JointTrackingState.NotTracked) { if (tracker.State == WaveGestureState.InProgress && tracker.Timestamp + WAVE_MOVEMENT_TIMEOUT < timestamp) { tracker.UpdateState(WaveGestureState.Failure, timestamp); System.Diagnostics.Debug.WriteLine("Fail!"); } else if (hand.Position.Y > elbow.Position.Y) { //使用 (0, 0) 作為屏幕的中心. 從用戶的視角看, X軸左負(fù)右正. if (hand.Position.X <= elbow.Position.X - WAVE_THRESHOLD) { tracker.UpdatePosition(WavePosition.Left, timestamp); } else if (hand.Position.X >= elbow.Position.X + WAVE_THRESHOLD) { tracker.UpdatePosition(WavePosition.Right, timestamp); } else { tracker.UpdatePosition(WavePosition.Neutral, timestamp); } if (tracker.State != WaveGestureState.Success && tracker.IterationCount == REQUIRED_ITERATIONS) { tracker.UpdateState(WaveGestureState.Success, timestamp); System.Diagnostics.Debug.WriteLine("Success!"); if (GestureDetected != null) { GestureDetected(this, new EventArgs()); } } } else { if (tracker.State == WaveGestureState.InProgress) { tracker.UpdateState(WaveGestureState.Failure, timestamp); System.Diagnostics.Debug.WriteLine("Fail!"); } else { tracker.Reset(); } } } else { tracker.Reset(); }}
下面的代碼添加到WaveGestureTracker結(jié)構(gòu)中:這些幫助方法維護(hù)結(jié)構(gòu)中的字段,使得TrackWave方法易讀。唯一需要注意的是UpdatePosition方法。TrackWave調(diào)用該方法判斷手的位置已經(jīng)移動(dòng)。他的最主要目的是更新CurrentPosition和Timestamp屬性,該方法也負(fù)責(zé)更新InterationCount字段合InPorgress狀態(tài)。
public void UpdateState(WaveGestureState state, long timestamp){ State = state; Timestamp = timestamp;}public void Reset(){ IterationCount = 0; State = WaveGestureState.None; Timestamp = 0; StartPosition = WavePosition.None; CurrentPosition = WavePosition.None;}public void UpdatePosition(WavePosition position, long timestamp){ if (CurrentPosition != position) { if (position == WavePosition.Left || position == WavePosition.Right) { if (State != WaveGestureState.InProgress) { State = WaveGestureState.InProgress; IterationCount = 0; StartPosition = position; } IterationCount++; } CurrentPosition = position; Timestamp = timestamp; }}
上述代碼片段就可以實(shí)現(xiàn)揮動(dòng)(wave)手勢識(shí)別的邏輯了。
6. 結(jié)語本文主要介紹了手勢識(shí)別中設(shè)計(jì)的基本概念以及手勢識(shí)別的發(fā)展過程,在此基礎(chǔ)上介紹了手勢識(shí)別的三種基本方法:基于算法的手勢識(shí)別、基于神經(jīng)網(wǎng)絡(luò)的手勢識(shí)別和基于樣本庫的手勢識(shí)別。