人手雷射筆
胡詠峻 李怡靜 黃筑葭
指導教授:賴尚宏
動機與目標
在現今大眾使用的電腦中,主要的輸入硬體設備為鍵盤和滑鼠所主宰,其方便性以及容易上手的特色,廣受使用者們喜愛。但是漸漸的,人們越來越覺得這些東西似乎少了一點「人性」,因此Sony所推出Wii遊戲機中首創利用「動作」來玩遊戲,廣受大眾好評,不過仍然需要使用搖桿來作輸入;蘋果首創雙點觸控螢幕大大的增加使用上的人性化,也在2011年成為全球最有市價最高的公司。在電影「關鍵報告」中,主角直接對著空中作比畫,電腦就能夠直接判定這些動作,並給使用者一個相對的回應,這個場景扣住許多人的心弦,令人瞠目結舌。在Microsoft推出Kinect之後,給了我們一個機會來實現這個理想。
我們想利用Kinect強大的深度圖,以及座標系統,作出一套能夠取代滑鼠的系統,以手指所指的方向作為指定位置。
問題與討論
1. 環境設定
想要將kinect在Windows上正常運作,設計出自己的程式,目前有兩種環境設定可以選擇,一是利用OpenNI+NITE,另一個則是利用微軟自己所提供的kinectSDK。這兩種環境各有利弊,第一,微軟所提供的kinectSDK可以抓到20個關節點而NITE只有15個(如下圖);第二,OpenNI所提供的函式庫在針對動作的分析、判斷與處理方面比較完整;第三,OpenNI可以一次偵測到兩個以上的人體骨架,而kinectSDK一次只能偵測一人的骨架;最後是在聲音的處理方面,kinectSDK提供相對完整的功能。整體而言,我們認為kinectSDK所提供的資源完整度相當高,但由於我們的專題主要考量偵測人體骨架與手部動作判斷與分析,在這方面OpenNI所提供的環境較符合我們的需要,因此選擇使用OpenNI+NITE的環境來開發我們的專題。
kinectSDK NITE
2. OpenCV讀取 alpha channel
我們在實作射擊遊戲時,遇到OpenCV在讀圖檔時無法讀取alpha channel的問題,使得遊戲畫面無法如我們預期的美觀。OpenCV在讀圖檔時只會讀三個通道,也就是RGB,無法讀alpha channel,也就是所謂得透明度的通道,已經過去背處理的圖讀進來後背景會自動被設為黑色或白色,OpenCV可調整整張圖的透明度,卻無法調整將特定部位的圖設為透明。
3. 實作方法的演進
一開始我們所使用的方法須先加入一個強烈的假設,在人與螢幕平面是平行的情況下,假設手肘的關節點無法移動,首先取得手腕的位置,在定位時將手指向螢幕的左上角及右下角,紀錄手腕在這兩點的座標位置,之後再利用相似三角形原理,以比例的方式取得手指指向的位置如圖所示,計算實際上指到螢幕上的哪一點。
x1:x2 = y1:y2
這個方法相當簡單,實際測試的結果也不錯,缺點是定位完成後,人不能任意移動,必須站在固定的位置上,而且也假定使用者的手與螢幕在平行的平面上移動,限制較多。
因此我們將這個方法改進成目前所使用的方法,加入使用手肘座標,計算在三度空間中,手肘到手腕向量與螢幕交會點,讓計算更加精確,也使得使用者可以任意移動,只要在鏡頭照得到的範圍內,都可以計算手所指到的點。
目前方法雖然使用者可以任意移動,但kinect與螢幕必須放在同一個平面(螢幕正上方或正下方),將來考慮不同場合的限制,可以改進成kinect可以任意擺放,這樣使用者定位的動作可能需要兩次以上,以確保準確度。
方法
為實作出人手雷射筆的效果,使用互動式操作裝置Kinect作為主要的輔助工具,利用Kinect的深度感應技術以及PrimeSense公司提供的 OpenNI 的中介軟體NITE分析出人體骨架、手勢等資料,分別可分析出頭部、左肩、左手手肘……等共24個關節點位置。
為方便使用者操作,本專題使用頭部、左手手腕、右手手腕、左手手肘、右手手肘共五個關節點的空間座標位置做為分析資訊,可經由關節點間的相對位置或單一關節點在特定時間內的移動速度分析出使用者目前的使用狀態並於主畫面上顯示不同的效果。
在Kinect的三維座標系統中,偵測出的關節點以(x,y,z)表示,其中x及y代表人體水平(x)及垂直(y)移動平面座標,z代表深度值,以Kinect的所在位置設為0,若距離Kinect越遠則z值越大。
1. 實作投影筆
在此專題中,先預設Kinect的正上方為投影螢幕的所在位置,在完成定位前,投影螢幕為一個可無限延伸的平面,需先指定出螢幕中的四角位置,方便標示出後續移動投影點的投影位置(如右圖所示),在Kinect三維座標系統中,此平面表示為z=0。為方便使用者能夠快速定位,在定位過程中,程式僅取得投影螢幕之左上角及右下角,取得此兩點後即可推算出投影螢幕四個角的三維座標。取得定位點座標的方法如下,先假設手腕座標位於點C( X1, Y1 ,Z1 ),手肘座標位於點D( X2, Y2, Z2 ),連接CD兩點後形成的直線與平面z=0可相交於一點C,點C即為程式所取得的定位點,也就是螢幕的左上角(點A)或右下角(點B)。則此直線可表示為
x = X1 + ( X1 – X2 ) * t ---(1)
y = Y1 + ( Y1 – Y2 ) * t ---(2)
z = Z1 + ( Z1 – Z2 ) * t ---(3), t屬於實數
假設延手指方向的直線投影在螢幕平面上的座標為點C( I , J , K ),則
K=0 => Z1 +( Z1 – Z2 ) * t = 0 => t = -Z1/(Z1-Z2),將t值代回(1)、(2)式即可得到A點或B點的座標值( I , J , K )
I = X1 + ( X1 – X2 ) * (-Z1/(Z1-Z2))
J = Y1 + ( Y1 – Y2 ) * (-Z1/(Z1-Z2))
K = 0
完成螢幕四角的定位後,投影點必須隨手臂移動方向而改變,改變的結果需顯示在投影螢幕或互動視窗上,因此必須將人體在空間中的相對移動位置經計算後得到投影點在互動視窗中的實際座標位置。假設互動視窗為一個大小P x Q的視窗,螢幕左上角的A點( X1 , Y1 , 0 )位於( 1 , 1 ),螢幕右下角的B點(X1, Y1 ,0)位於( P , Q ),某一時刻在螢幕上的投影點C( M , N , 0 )對應到螢幕上的座標(i ,j)則分別為
i = ( M – x1 ) / ( x2 - x1 ) x P
j = ( N - y1 ) / ( y2 - y1 ) x Q
2. 定位標記動作
在人機互動過程中,若沒有定位前的標記動作,將無法判斷使用者指定螢幕定位點的確切時間,因為必須先指定定位前標記動作,在定位過程中,當左手手肘高過頭頂位置時便記錄手指投影點位置。
3. 觸控式按鈕
先在互動視窗中繪製出按鈕並指定按鈕範圍,當投影點進入指定範圍停留超過3秒即視使用者有碰觸按鈕的動作。使用time.h中的time()函式記錄進入點擊按鈕的時間點及difftime()函式計算出停留的時間差,一但超過3秒則執行按鈕點擊後的功能,若沒秒過3秒即離開點擊按鈕便重新計算進入點擊區域的時間點。
4. 偵測投擲動作(使用Z軸)
為了模擬投擲手榴彈的動作,先將投擲手榴彈的投擲範圍縮小在頭部深度 減五十(Kinect深度單位)至頭部深度加三十(Kinect深度單位)內,一旦在範圍內發現投擲動作在2秒內完成即代表使用者做出丟擲手榴彈的動作。
5. 偵測投降動作(使用Y軸)
遊戲結束的方式,除了生命值到達0之外,也增加了一個有趣的方式。若雙手的座標皆高於頭部座標,則判定為投降。
6. 高分榜
使用檔案的讀寫來保存每一次的高分紀錄。
結果與應用
經過目前的方法計算,已經可以將手所指的點準確的投影在螢幕上的相對位置,利用手指取代滑鼠的功能。
我們將此技術做成一個射擊的小遊戲,不需要任何額外感應器,即可用手當手槍,並結合簡單的動作辨識,可以偵測投擲動作當作丟手榴彈、雙手舉高投降當作遊戲結束…等。
擷取骨架座標 使用者定位
實際遊戲畫面
未來展望
目前只是把這項技術簡單的實作成一個小遊戲,只能在自定義的視窗內操作,如果以後能跟Windows作結合操作整個作業系統,可以利用的層面將廣泛許多,例如:擬雙點觸控、小畫家、手寫輸入等等。亦可以與手勢辨識結合作為一個完整的投影片播報系統。
Kinect也可以應用在許多方面,體育家教系統,糾正使用者的動作,讓自己知道哪邊的姿勢不正確;跳舞機,能夠讓使用者輕鬆自在的在家學跳舞;家電總管,讓使用者能夠輕鬆的在一個地方隨心所欲的使用家電,開關烤箱、冷氣、燈泡等等;相片合成,利用Kinect可以輕鬆得擷取深度影像圖,去背的工作相對而言簡單了許多;使用Kinect作為機器人的眼睛,更容易判斷目前所在場景。當Kinect可以更準確的分辨手指位置時,也可以取代鍵盤滑鼠,作為電腦的主要輸入裝置。