【翻譯】Leapmotion-python開發官方文檔(9)

座標系統

在使用LeapMotion控制器控制一個程序時一個基本的工作就是將從控制器獲得的座標值轉換到程序的座標系統。

LeapMotion座標系統

LeapMotion控制器在每一個數據幀中提供的座標以毫米爲單位。也就是說,如果一個手指指尖座標是(x,y,z)=[100,100,-100],這些值都是以毫米記得,或者說,x=+10cm,y=10cm,z=-10cm。
在數據幀的座標參考系中LeapMotion硬件是座標中心。座標原點在LeapMotion硬件的上表面的中心點。也就是說,如果你觸碰LeapMotion控制器的中間點(同時能返回數據)那麼你手指指尖的座標將是[0,0,0]。

LeapMotion控制器使用右手座標系。
通常情況下,LeapMotion放在桌子上,使用者在一邊,電腦顯示器在另一邊,也就是說,使用者在控制器的前方(+Z)顯示器在控制器的後方(-Z)。如果使用者開啓了自動定位(automatic orientation),那麼LeapMotion會在控制器反向放置(綠色LED燈背向使用者)自動適應座標系統。但是,如果使用者將控制器放置在不同的位置上(顛倒或者側着放),LeapMotion軟件是無法檢測或者適應(這樣錯誤的放置)的。
設計你的程序時要鼓勵使用者不要離LeapMotion控制器太近。快速的在控制器上方晃動手會增加手和手指在控制器的視野中相互干擾的機率。

將座標轉換到你的應用座標系中

爲了在你的程序中使用從LeapMotion設備中獲得的信息,你必須預處理這些數據使其能爲你的程序所用。比如,將座標從leapMotion座標系轉換到你程序的座標系下,你必須決定哪些座標軸是有用的。利用多大的LeapMotion的視野,以及是使用絕對映射還是相對映射。
對於3D應用,通常會使用LeapMotion設備的所有三個座標軸。對於2D應用,你往往可以忽略一個座標軸,通常是Z軸,將兩個座標軸提供的座標作爲輸入,映射到2D應用的座標系中。
無論你使用兩個還是三個座標軸,你都應當決定在你的應用中使用多大的LeapMotion區域。LeapMotion的視域是一個倒置的金字塔。越接近控制器,X、Z軸的範圍就會越小。如果你使用過寬的範圍或者允許太低的高度,那麼可能使使用者無法訪問你程序界面底角。考慮下面這個例子,其將LeapMotion座標系統映射到下方的矩形中。(這個例子需要插入LeapMotion控制器才能看到):


注意,當你嘗試去訪問程序界面的底部時,你的手指會超出LeapMotion設備的檢測區域所以你沒法將光標移動到那裏。
你也應當去注意如何縮放LeapMotion座標來適應你的程序。(以及在2D應用中每毫米使用多少像素)。縮放因子越大,對細微的運動就越靈敏。這會讓使用者更容易移動光標。比如從程序界面的一邊移動到另一邊,但是更不容易精確定位。你必須爲你的程序在速度與精確之間找到一個平衡點。
最後·,座標系的不同可能需要反轉一個甚至三個座標軸。例如,許多2D窗口繪製API都將原點設置在窗口的左上方的角上,y軸正方向向下。LeapMotion的y值正方向是朝上的,所以你需要在轉換座標時翻轉座標軸。另一個例子,Unity 3D遊戲開發系統使用左手系座標系統。然而LeapMotion軟件使用右手座標系。
映射座標系有點像攝氏度與華氏度的轉換,你可以想象每個座標軸就像相應的起點(零度)與終點(沸點)的縮放。

你可以使用如下公式來轉換座標:
其中
通過改變起點與終,你能夠改變座標系的映射關係使得在你的程序中在一個更寬的範圍或更小的範圍檢測運動。下面的例子在X軸與Y軸上使用這個公式將LeapMotion的可視區域映射到一個矩形顯示區。通過設置不同的縮放,你可以玩耍這個控制器(譯者注:........)。



如果你減小範圍值,更小範圍的物理運動會被映射到程序窗口的顯示範圍上,使它從窗口的一邊移動到另一邊更加容易。
X-Center用於抵消在縮放時x軸的中心向左或向右偏移。由於人手會很自然地放在LeapMotion控制器的左邊或者右邊,如果你基於那隻手在使用來偏移座標映射,會使用戶更容易與全屏應用進行交互。
Y-floor滑塊用於在LeapMotion Y軸上設置映射到顯示區域底部區域的值。值越大代表着使用者需要把手擡得更高,同時也代表着使用者更容易接觸到底部。
點選clamp選項是爲了防止光標離開顯示區域,這樣能告訴使用者,哪裏是能夠進行交互的。
一個更普遍的用來轉換座標的方法就是將LeapMotion中的座標歸一化。然後從這個歸一化的縮放變換到最終的程序座標尺度中。事實上LeapMotion API中的 InteractionBox類會幫你將座標歸一化的。

交互區域

InteractionBox在LeapMotion可視區域定義了一個箱型區域。

只要用戶的手或者手指處於這個箱型區域之中,那麼也一定在LeapMotion的可視範圍中。你可以在你的程序中利用這一點,通過將你程序的交互區域映射到InteractionBox所定義的區域來替代映射到整個LeapMotion的可視區域。InteractionBox類提供normalize_point()方法幫助將LeapMotion座標映射到你的程序座標中。


InteractionBox的大小由LeapMotion可視區域和用戶的交互高度設置(在LeapMotion 控制面板中)。控制器軟件基於保持底角在可視區域中來自適應的調整這個箱型區域的大小。如果你將交互高度的值設置的大,那麼箱型區域也會變得更大。使用者可以通過在使用控制器時他最喜歡將手舉得高度來設置這個交互高度的值。有些使用者更喜歡將手舉得更高。通過使用InteractionBox映射LeapMotion座標系到你的程序座標系中,你能夠滿足所有用戶的喜好。用戶也能將交互高度設置爲自動適應。如果用戶在低於箱型區域移動手,控制器軟件會自動將交互高度自動調小(直到最小的數值)。同樣的,當用戶手部的運動高於這個交互箱型區域時,控制器會擡高箱型區域的位置。
由於這個交互箱型區域會改變大小和位置,每一個Frame對象都包含有InteractionBox類的實例。下面的例子展示了InteractionBox的一些行爲。在LeapMotion控制面板中改變交互高度設置,你會看到這會如何影響這個箱型區域的。
你可以使用在上個例子中使用的箝位控制(clamp control),你會看到當你使用normalize_point()函數時箝位座標的影響。如果你不使用箝位,你會得到介於0與1之間的值。
因爲交互箱型區域會隨時間變化,要注意到當歸一化是使用其他數據幀中的InteractionBox時,當前數據幀中的一個點的歸一化座標可能與現實中歸一化座標並不匹配。這樣由用戶在“空中所畫的”直線和正圓可能不會那麼直或者平滑,如果他們是使用其他的數據幀歸一化。對於大多數應用,這不是個重要的問題,但是你應當在你不確定的情況下使用自動交互高度設置來測試你的程序。
爲保證連續幀中一系列被追蹤的點都能正確的歸一化,你可以保留一個單獨的InteractionBox對象----其具有最大的高度、寬度、深度。所有的點都用它來歸一化。

使用交互箱型區域映射座標

使用InteractionBox對象,首先將點座標歸一化然後將歸一化後的座標轉換到你應用程序的座標系。使用交互箱型區域將待轉換座標歸一化(即取值範圍[0...1])然後將座標原點到顯示區域的左下角。然後,你可以用你程序座標系中每個座標軸最大範圍乘以歸一化後的座標,如果需要的話,再進行反相和平移。

映射到2D

比如,大多數2D繪製座標系統將原點放置在窗口的左上角,當然也沒有Z軸。將LeapMotion座標轉換到這樣的2D座標系統,你可以使用下面的代碼:
app_width = 800
app_height = 600

pointable = frame.pointables.frontmost
if pointable.is_valid:
    iBox = frame.interaction_box
    leapPoint = pointable.stabilized_tip_position
    normalizedPoint = iBox.normalize_point(leapPoint, False)
    
    app_x = normalizedPoint.x * app_width
    app_y = (1 - normalizedPoint.y) * app_height
    #The z-coordinate is not used

注意,這個例子在轉換Y軸座標時在乘以最大高度前先用1減去了歸一化座標值(用於反相)
如果你在一個2D應用中使用Pointable對象或手掌的位置,可以考慮使用Pointable.stabilizedTipPosition或者Hand.stabilized_palm_postion。這些屬性特別穩定而且經過濾波幫助用戶與2D界面交互。對於3D應使用不穩定的Pointable.tipPosition和Hand.palm_position比較合適。

映射到3D

在映射到3D座標系之前,你應當知道縮放因子,原點是否應當平移以及目標座標系統是用左手系還是右手系。
3D圖形的尺寸和大小的單位貌似是任意定義的,但是你需要決定如何將一個現實中的移動映射到虛擬世界中。
座標系原點由交互箱型區域歸一化到左下角。你可以通過將原點移動到更合適的地方來轉換這個歸一化的座標系。
LeapMotion座標系統使用右手系,如果你的座標系統使用左手系,在歸一化之前讓Z軸座標乘以-1(或者反轉X軸和Y軸)。
下面的例子展示了將LEapMotion座標系統轉換到原點在底部中建的3D系統:
def leap_to_world(self, leap_point, iBox):
    leap_point.z *= -1.0; #right-hand to left-hand rule
    normalized = iBox.normalize_point(leap_point, False)
    normalized = normalized + Leap.Vector(0.5, 0, 0.5); #recenter origin
    return normalized * 100.0; #scale

採用不同的方式映射左手和右手

如果你的程序允許全屏交互。那麼在歸一化座標系中爲每隻手定義不同的原點是個很好的主意。通過將左手的座標原點移動到右邊,右手的原點移動到左邊,你實際上將每隻手的自然休息點放置在了你程序的交互區域。對於左手來說可以緩解訪問程序的右邊時的疲勞,反之亦然。

爲了移動每隻手的原點,使用Hand.is_left檢測那隻手是左手(或右手)然後將歸一化座標平移到右邊或者左邊。
def differential_normalizer(self, leap_point, iBox, is_left, clamp):
    normalized = iBox.normalize_point(leap_point, False)
    offset = 0.25 if is_left else -0.25
    normalized.x = normalized.x + offset

    #clamp after offsetting
    normalized.x = 0 if (clamp and normalized.x < 0) else normalized.x
    normalized.x = 1 if (clamp and normalized.x > 1) else normalized.x
    normalized.y = 0 if (clamp and normalized.y < 0) else normalized.y
    normalized.y = 1 if (clamp and normalized.y > 1) else normalized.y

    return normalized

注意:爲使用這項技術,你必須將clamp參數設置爲false(如果你想使用箝位,你可以在抵消x座標後手動執行。)

增加靈敏度

將所有交互箱型區域的範圍都映射到你程序的交互區並不經常是一個好主意。你可能想要在現實世界中微小的運動但在虛擬世界中(你的程序中)有很大的變化。你可以簡單的按照你的需求縮放LeapMotion座標而不是用歸一化座標。(如前所述)如果你仍需要InteractionBox帶來的便利,你可以用比1大的數進行歸一化。使用2,則會使靈敏度增加兩倍,使用3則會增加3倍,等等。如果你的敏感度調的太高,那麼會增加控制的難度併產生跳躍的現象。
你也可以做相反的事情(減小靈敏度),通過對歸一化後的座標乘以一個小於1得數,但是經常不會行得通。顧名思義,用戶的動作的範圍不會再你程序的整個區域中。所以,容易的方法是在你的程序座標系中定義一個小一點的交互區域。
下面的例子使用2D座標,將靈敏度增加1.5倍。
app_width = 800
app_height = 600

pointable = frame.pointables.frontmost
if pointable.is_valid:
    iBox = frame.interaction_box
    leapPoint = pointable.stabilized_tip_position
    normalized_point = iBox.normalize_point(leapPoint, False)
    
    normalized_point *= 1.5; #scale
    normalized_point -= Leap.Vector(.25, .25, .25); # re-center

    app_x = normalized_point.x * app_width
    app_y = (1 - normalized_point.y) * app_height
    #The z-coordinate is not used
你可能注意到,將clamp參數設置爲true不再使你最後得到的座標處於你定義的範圍內。用戶的運動會更加容易移出程序的交互區因爲你有效的將一個箱型交互區域的子集(內部小空間)映射到了你的程序中。爲用戶提供視覺反饋是十分有用且必要的。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章