彭 淼 , 陳國麗 , 姜 瑜
(重慶工業(yè)賦能創(chuàng)新中心有限公司,重慶 401123)
近年來,隨著虛擬現(xiàn)實(shí)技術(shù)的迅速發(fā)展,人們愈加感受到體感交互設(shè)備所帶來的便利,如偵測手臂肌電信號Myo智能臂環(huán)、Google 眼鏡等可穿戴式交互設(shè)備[1]。Leap Motion公司推出了Leap Motion Controller小型運(yùn)動控制系統(tǒng),能以200幀/秒的速度追蹤雙手,追蹤精度可達(dá)0.01mm,可用于捕捉視場范圍達(dá)150。 ,空間范圍可達(dá)8平方英尺的交互式空間中的多個(gè)物體,并且其對手勢及手部細(xì)節(jié)的識別亦是一種新的突破[2]。
Leap Motion Controller目前的主要應(yīng)用分為兩個(gè)方面:一方面是在三維虛擬游戲方面的應(yīng)用,作為虛擬交互設(shè)備提升玩家游戲體驗(yàn);另一方面主要用于三維演示項(xiàng)目的虛擬設(shè)備。在演示項(xiàng)目的使用中有一種使用方法是用手勢代替數(shù)字來進(jìn)行控制項(xiàng)選擇[3]。在中國,手勢早已成為人們生活中簡單方便的交流手段。而Leap Motion的手勢識別能力可達(dá)到很高的精度,因而可以將手勢作為一種設(shè)備控制的輸入方式,幫助人們完成項(xiàng)目選擇,如物體抓取、移動,控制小車,操作機(jī)械臂等[4]。
本文以研究Leap Motion設(shè)備獲取手部位置信息的具體實(shí)現(xiàn)方法為目標(biāo),首先深入了解分析Leap Motion的工作原理和應(yīng)用方法,開發(fā)基于VS2017的Leap Motion手部位置獲取算法;然后編寫基于MFC的應(yīng)用程序界面,設(shè)定輸出所需位置信息的窗口,用于顯示手部位置和姿態(tài)數(shù)據(jù);最后通過實(shí)驗(yàn)分析采集算法的精度以及程序的穩(wěn)定性[5-9]。針對試驗(yàn)的具體結(jié)果,分析該輸出方法的優(yōu)點(diǎn),并且提出一定的改進(jìn)方案,為后續(xù)研究提供依據(jù)。
Leap Motion作為手部信息捕獲設(shè)備,使用光學(xué)傳感器和紅外線掃描獲取處于設(shè)備上方大約150°視野范圍內(nèi)的對象。Leap Motion的有效可視范圍大約在設(shè)備上方25mm~600mm,形狀呈尖端位于設(shè)備中心的倒漏斗形[10]。圖1展示了Leap Motion如何監(jiān)視用戶的手。
圖1 Leap Motion設(shè)備監(jiān)視用戶雙手
在了解Leap Motion控制器所使用的坐標(biāo)系統(tǒng)之后,將要用到手掌的中心坐標(biāo),即如圖2所示圓點(diǎn)的坐標(biāo)位置,然后給出中心坐標(biāo)的某一具體坐標(biāo)值編寫輸出方法。需要注意的是,在輸出手掌中心位置坐標(biāo)時(shí),需要判別手掌類型,即對左右手進(jìn)行判斷。因此,首先輸出手掌類型。
圖2 手掌坐標(biāo)位置及方向
在源代碼中給出了各種類以及類的相互之間的調(diào)用關(guān)系,這里僅對HandList下的C++代碼進(jìn)行更改,在代碼中,程序設(shè)定了一個(gè)Controller對象,用于連接到Leap Motion后臺,從而可以通過命令Controller.frame()獲取數(shù)據(jù)。另外,程序添加了一個(gè)Listener類,來設(shè)定一些回調(diào)函數(shù)。代碼中的onFrame回調(diào)函數(shù)用于定義當(dāng)獲取到一幀數(shù)據(jù)時(shí)需要處理的事件,比如通過對frame的再調(diào)用來獲取一些手部的位置數(shù)據(jù)信息,再調(diào)用的方法主要是通過語句HandList hands= frame.hands()來將幀中關(guān)于手部的數(shù)據(jù)信息傳遞給手列表中的手對象。在代碼中設(shè)定了四個(gè)float型變量,以及一個(gè)初始化為“未檢測到手”的字符變量,由于將其設(shè)定為全局變量,因此,可以在對工作狀態(tài)進(jìn)行判別后,通過對變量進(jìn)行賦值,來輸出手部的位置數(shù)據(jù)。
尖端對象是指在視野范圍中出現(xiàn)的對象中可以指出方向的東西,可以被表示為手指或者工具,可以通過手對象中特定的手,來獲取其相關(guān)的信息。即在獲取hand.palmPosition的同時(shí),獲取尖端坐標(biāo),在視野中部出現(xiàn)工具的情況下,便可以通過兩者之間的物理模型關(guān)系,確定視野中手部的位置以及方向。在檢測時(shí),程序會自動檢測手指尖端距離手掌中心最遠(yuǎn)點(diǎn)的坐標(biāo)并且進(jìn)行輸出。與輸出手掌中心位置坐標(biāo)的方式類似,程序通過onFrame回調(diào)函數(shù)獲取每一幀的數(shù)據(jù),通過命令const Pointable pointable = frame.pointables().frontmost()來獲取幀數(shù)據(jù)中所保存的尖端數(shù)據(jù)信息,并將獲取的坐標(biāo)信息賦給程序開始所定義的float型變量tipx,tipy,tipz,進(jìn)行輸出。
在Leap Motion模型中,手指利用Finger類對象進(jìn)行描述,是一種可指向性對象,物理特性包括Width(寬度)、Length(長度)、Direction(方向)、tipPosition(尖端坐標(biāo))以及tipVelocity(尖端速率)等。如圖3所示,圓點(diǎn)處的位置表示為尖端坐標(biāo),箭頭的方向表示尖端方向。
圖3 尖端坐標(biāo)及方向向量
這里選擇尖端坐標(biāo)來描述手指屬性,并基于Pointable類獲取指尖位置。與描述手掌中心坐標(biāo)的方法相似,利用double型全局變量對獲取的結(jié)果進(jìn)行輸出。
Leap Motion控制器可以獲取用戶十指的數(shù)據(jù)。在LeapSDK中提供了所檢測到的用戶手指物理特征數(shù)據(jù)的C++代碼,通過運(yùn)行可以對相關(guān)數(shù)據(jù)進(jìn)行輸出。所有的手指都包含有四根骨頭,每根骨頭可以獲取指根和指尖的坐標(biāo)位置,即如圖4中小球處的坐標(biāo)位置。定義的骨頭名稱如上述代碼中boneNames[]字符串所包含的四個(gè)成員。拇指模型為了便于編程的統(tǒng)一多定義了一個(gè)掌骨,長度設(shè)定為零。
圖4 Leap Motion手指指骨模型
在Leap Motion SDK中把一些特定的運(yùn)動模式定義為手勢,通過這個(gè)運(yùn)動模式來對用戶的意圖進(jìn)行猜測。對于每一個(gè)設(shè)備觀察到的手勢,都可以在frame.gestures列表中找到相關(guān)的數(shù)據(jù)信息。Leap Motion系統(tǒng)會將獲取到的手勢對象不斷更新在獲取的幀中。通過對手勢的判別,更多的是可以獲取到用戶手部在坐標(biāo)系中的一個(gè)動作姿態(tài)特征,在檢測到用戶的一個(gè)手勢時(shí),可以通過手部模型關(guān)聯(lián)得到用戶手部的一個(gè)大致位置。在手勢識別啟用后,便可以從幀中獲取一些數(shù)據(jù)信息。檢測手勢的代碼首先將幀中的關(guān)于手勢的數(shù)據(jù)信息傳遞給手勢類,采用了switch開關(guān)語句對手勢的基本類型進(jìn)行判別,如果符合case命令下的手勢類型,則執(zhí)行該case命令并且最終結(jié)束switch循環(huán)。識別手勢基本類型的算法封裝在gesture項(xiàng)目中。在程序運(yùn)行過程中,程序通過調(diào)用相關(guān)的函數(shù),將一些基本的信息填入進(jìn)去,通過計(jì)算進(jìn)行轉(zhuǎn)換,在某些數(shù)據(jù)發(fā)生了重復(fù)時(shí),便開始判斷其是否為手勢,以及為何種類型手勢。
基于可視化的用戶程序界面生成系統(tǒng)是當(dāng)前編程發(fā)展的方向。如瀏覽器支持界面實(shí)時(shí)刷新顯示,一些軟件運(yùn)行時(shí)可以實(shí)時(shí)的更新顯示類似于時(shí)間、坐標(biāo)等數(shù)值。由于在Windows中不可能完全由用戶設(shè)計(jì)這些可能需要用到的控件,因此,微軟公司推出的MFC提供了類庫,用戶可以基于此基礎(chǔ),通過重載它的各種消息處理函數(shù)來對所需要的程序界面進(jìn)行編輯修改[11]。
本文所用的VS2017是微軟公司推出的最新版集成開發(fā)工具,提供了MFC類庫[12]。MFC的框架包含有一個(gè)應(yīng)用程序所需的所有可能控件,用戶只需要對其進(jìn)行使用[13]。
應(yīng)用程序界面的生成包括兩個(gè)過程,首先是進(jìn)行界面設(shè)計(jì),即在編輯窗口中加入控件,并為控件添加成員變量。之后便是功能設(shè)計(jì),用戶需要基于各成員變量,編寫功能函數(shù)來得到所需要的結(jié)果。下圖5簡單介紹了如何創(chuàng)建一個(gè)基于對話框類型的應(yīng)用程序。
圖5 基于對話框的應(yīng)用程序工作流程圖
在本文中所編寫的應(yīng)用程序界面需要完成的一個(gè)功能是:在Leap Motion檢測到用戶手部位置數(shù)據(jù)信息時(shí),將存放在frame中的各結(jié)構(gòu)的三維坐標(biāo)分別實(shí)時(shí)動態(tài)顯示出來,在用戶改變所需要的位置信息時(shí)輸出也會隨之發(fā)生改變[14]。因此,本文本框必要的一些控件為:手掌類型、手指個(gè)數(shù)、手掌中心、尖端、手掌角度以及基本手勢。前面四個(gè)坐標(biāo)值可以表示用戶手部的基本信息以及一個(gè)大致空間位置,第五個(gè)坐標(biāo)值則主要用于描述手掌的一個(gè)方向,第四個(gè)為字符串輸出,用于展示用戶手部可能組成的基本手勢。
基于以上分析,在進(jìn)行Leap Motion數(shù)據(jù)信息與MFC界面進(jìn)行共享的過程中,涉及多個(gè)坐標(biāo)信息,以及三個(gè)字符串類型輸出。在進(jìn)行應(yīng)用程序界面設(shè)計(jì)時(shí),為使界面信息明了,采用Group Box控件,將位置坐標(biāo)輸出分別設(shè)置在不同的組合框控件中。在進(jìn)行數(shù)據(jù)顯示時(shí),控件需要有自己的一個(gè)成員變量,該變量的定義類型可能是值,或者字符串。針對本文的應(yīng)用程序,需要定義至少三個(gè)數(shù)值型成員變量以及三個(gè)字符串型成員變量[15]。
該對話框包含了手掌中心坐標(biāo)、尖端坐標(biāo)、手掌姿態(tài)角的數(shù)據(jù)輸出,手勢、手類型的判別,通過這些信息,可以具體地刻畫出手部在空間中的位置信息,并對其進(jìn)行一定的美化,如添加圖片控件以及作者姓名信息等。完整的人機(jī)交互對話框如圖6所示。
圖6 人機(jī)交互對話框
在構(gòu)建好MFC應(yīng)用程序界面的對話框基本結(jié)構(gòu)之后,比較關(guān)鍵的是將Leap Motion程序與搭建的MFC框架聯(lián)系起來,獲取到數(shù)據(jù)并且進(jìn)行動態(tài)顯示[16]。
至此,添加的成員變量有:float型變量m_palmX,m_palmY,m_palmZ,用于描述手掌位置坐標(biāo);int型變量m_pitch,m_yaw,m_roll,用于描述手掌角度;CString型變量m_rightorleft,用于描述手掌類型;int型變量m_fingerscount,用于描述手指數(shù);float型變量m_tipX,m_tipY,m_tipZ,用于描述尖端位置坐標(biāo);CString型變量m_gesturetype,描述特征手勢類型。
在Leap Motion的SDK文檔中設(shè)定了一個(gè)Listener類用于監(jiān)聽設(shè)備狀態(tài)以及獲取幀數(shù)據(jù)并且將幀中的數(shù)據(jù)調(diào)用給手部各姿態(tài)用于輸出。因此,為實(shí)現(xiàn)數(shù)據(jù)傳遞,在MFC項(xiàng)目中新建一個(gè)名為myListener的類,用于與Leap設(shè)備建立聯(lián)系并且獲取一些數(shù)據(jù)信息。關(guān)于MFC項(xiàng)目對各頭文件路徑的識別,可以按照Leap Motion SDK在C++環(huán)境下的配置,在MFC項(xiàng)目中重新配置一次即可[17-19]。
由于輸出信息僅需要調(diào)用onConnect函數(shù)以及onFrame函數(shù),因此,在MyListener的聲明中,僅需添加這兩個(gè)函數(shù)即可。拷貝獲取位置信息的C++代碼到myListener.cpp中,將獲取的位置數(shù)據(jù)賦給所設(shè)定的各全局變量,以方便在交互界面進(jìn)行輸出[20]。在程序運(yùn)行myListener.cpp后,手部位置數(shù)據(jù)信息便保存在了定義的各全局變量中。對話框的主程序代碼需要實(shí)現(xiàn)的功能是將全局變量中的數(shù)據(jù)顯示在相應(yīng)的編輯框中,并且實(shí)現(xiàn)數(shù)據(jù)的動態(tài)更新顯示。對于更新要求,采用的是添加一個(gè)onTimer函數(shù),通過定時(shí)器定時(shí)執(zhí)行某條語句,從而實(shí)現(xiàn)數(shù)據(jù)的更新顯示。
數(shù)據(jù)通過全局變量傳遞到了每個(gè)編輯框所對應(yīng)的成員變量中,并且可以通過編寫的MFC人機(jī)交互界面進(jìn)行動態(tài)顯示。實(shí)時(shí)顯示的輸出交互界面如圖7所示。
圖7 MFC交互界面輸出結(jié)果
對于一個(gè)信息采集設(shè)備,需要了解其所用坐標(biāo)系統(tǒng),以及其可檢測范圍,之后才可以對其采集精度進(jìn)行檢測。因此,需要對Leap Motion設(shè)備的可視范圍進(jìn)行測定,如可采集的三維最大長度,隨后標(biāo)定坐標(biāo)空間的大致形狀,基于此進(jìn)行Leap Motion的采集精度實(shí)驗(yàn)。
在進(jìn)行測定時(shí),首先在Leap Motion設(shè)備旁邊固定一根1m長的直尺,然后由低至高依次抬高手掌,觀察屏幕輸出的手掌中心坐標(biāo),直到輸出為0,記錄此時(shí)的手掌高度,如圖8所示。
圖8 利用直尺測定Y方向上設(shè)備可視范圍
測定Y正方向上,當(dāng)手掌移動到距離設(shè)備上表面約1 000mm的位置時(shí),屏幕輸出為0;最下方距離設(shè)備上表面約20mm的位置時(shí),屏幕輸出為0??梢钥闯觯c官方給出的可視范圍基本吻合。
之后,借助另一根直尺測定相隔一段Y方向上的距離,相應(yīng)的X與Z軸在正負(fù)方向上的極限可視范圍。測定方法與標(biāo)準(zhǔn)基本同上文相似。手掌隨直尺方向平移,觀察屏幕輸出。在輸出為0時(shí)則表示該方向到達(dá)可視范圍的邊界。如圖9所示。
圖9 測定X與Z方向上極限可視范圍
結(jié)果如表1所示。
表1 三維坐標(biāo)測量結(jié)果匯總表
Leap Motion坐標(biāo)系統(tǒng)的方向設(shè)定,分別作X-Y圖及Z-Y圖,如圖10所示。
將圖10與官方給定的坐標(biāo)系統(tǒng)圖示進(jìn)行比較,可知系統(tǒng)的實(shí)際坐標(biāo)區(qū)域可分為兩片不同類型。首先是由坐標(biāo)原點(diǎn)到Y(jié)軸正向約620mm之間區(qū)域,大概為一個(gè)倒金字塔形。由Y軸正向距原點(diǎn)620mm至檢測頂點(diǎn)之間的區(qū)域大概是一個(gè)倒球形。
在交互界面上可顯示手掌姿態(tài)角數(shù)據(jù)信息,具體包括俯仰角(繞X軸)、側(cè)傾角(繞Z軸)以及橫擺角(繞Y軸)。在設(shè)備檢測到用戶手部位置信息時(shí),界面可以實(shí)時(shí)顯示數(shù)據(jù)信息。相關(guān)手部位置及輸出信息如圖11所示。
圖10 坐標(biāo)系實(shí)際可視范圍圖
圖11 手掌姿態(tài)角數(shù)據(jù)信息獲取
在設(shè)備的可視范圍測定完成后,需要沿各軸測定手掌的實(shí)際坐標(biāo)值,并與程序輸出坐標(biāo)值進(jìn)行對比,對設(shè)備的檢測精度進(jìn)行評定。本文僅對Y軸正向的檢測數(shù)據(jù)進(jìn)行精度檢測。測定方式:使用一根刻度為1m、精度為1cm的直尺。在進(jìn)行檢測時(shí),首先將數(shù)據(jù)的輸出頻率降低,以方便讀數(shù)。將使用直尺測定的數(shù)據(jù)與程序輸出的坐標(biāo)值進(jìn)行對比,如表2所示。
表2 沿Y軸正向測定坐標(biāo)與輸出坐標(biāo)數(shù)據(jù)表
基于上表所測數(shù)據(jù),使用直尺測定值與程序輸出值數(shù)據(jù)信息,繪制兩者的數(shù)據(jù)對比線圖如圖12所示。
圖12 手掌位置數(shù)據(jù)信息對比圖
根據(jù)折線圖中,兩根曲線之間的擬合情況,結(jié)合數(shù)據(jù)采集過程中可能出現(xiàn)的誤差,可知在距離Leap Motion設(shè)備較近位置時(shí),如500mm范圍內(nèi),設(shè)備的檢測精度很高,與實(shí)際測量基本無偏差;在距離設(shè)備較遠(yuǎn)處出現(xiàn)數(shù)據(jù)的較大波動,原因可能是設(shè)備所用傳感器的靈敏度隨距離的增加逐漸降低。整體來說,其檢測精度相比較其他傳感器要更高,數(shù)據(jù)輸出更為穩(wěn)定,數(shù)據(jù)偏差范圍較小。
另外,通過實(shí)際檢測可以得知,Leap Motion設(shè)備的實(shí)際檢測范圍可能會比官方給出的標(biāo)準(zhǔn)范圍要更大一些。在運(yùn)行程序時(shí)屏幕輸出的數(shù)據(jù)精度可以達(dá)到0.000 1,精度相比以往更高。這就為用戶提供了更大的操作空間,同時(shí)其更高的檢測精度也為手部位置的獲取提供了更多的便利。
關(guān)于空間物體的坐標(biāo)位置獲取一直都是一個(gè)不斷發(fā)展、不斷進(jìn)步的前沿研究方向,相比較以往推出的三維加速度傳感器、超聲波傳感器、溫度傳感器、雷達(dá)等檢測設(shè)備,Leap Motion具有更高的精度,可以適應(yīng)更多的使用環(huán)境。本文基于Leap公司供用戶參考學(xué)習(xí)的SDK文檔,開發(fā)設(shè)計(jì)出一種相對來說更為實(shí)用、比較簡便的手部位置信息獲取方法,并且利用VS設(shè)計(jì)出了一個(gè)簡單的MFC程序界面對數(shù)據(jù)進(jìn)行輸出顯示。本文主要完成了以下工作:
1)根據(jù)Leap公司提供的用戶參考SDK文檔,對Leap Motion獲取手部位置信息的C++程序進(jìn)行了解讀并且編寫了更為直接以及簡單的輸出代碼。
2)使用VS2017建立了一個(gè)MFC應(yīng)用程序,并且對該應(yīng)用程序的控件進(jìn)行了設(shè)計(jì),使其可以顯示所需的一些位置坐標(biāo)信息。
3)通過對其他MFC程序的參考,經(jīng)過調(diào)試將編寫的Leap Motion程序與新建的MFC程序之間建立了鏈接,使MFC控件的成員變量可以獲得不斷更新的位置數(shù)據(jù)信息并且進(jìn)行動態(tài)顯示,完成了手部位置信息獲取方法的探究。
4)本文雖然對手部位置信息獲取方法進(jìn)行了探究,但是對其可能應(yīng)用的方向并沒有進(jìn)行一個(gè)很好的描述,希望可以在后續(xù)工作中對該方面進(jìn)行探究,并且提出一些可能應(yīng)用的場景,為其更好地與現(xiàn)實(shí)結(jié)合提供參考。