Leap Motion翻譯系列文章http://52coding.com/leap-motion-official-doc-translation
追蹤手、手指和工具
手、手指和工具是Leap Motion系統的基本追蹤實體。這篇文章將詳細討論如何擷取和使用這些實體物件。
概述
Leap的API定義了一個可以表示每個基本追蹤到的物體的類。 幀對象提供了一個可以訪問手、手指和工具的列表。指尖和工具都是尖端物體,並且他們可以被同時放入尖端列表PointableList中,或者分別使用手指列表FingerList和工具列表類ToolList。手對象提供訪問他們的手指和工具的途徑(都一起在尖端列表中或者分開)。 手、手指和工具的物體特點在Leap的座標系統下(以毫米為單位衡量)有報告。Leap的SDK提供了向量類(Vector)來描述點和朝向。向量類提供了一些有用的向量運算的數學函數[這個挺不錯,避免自己寫了]。
手和尖端列表
列表類都都擁有近似的結構。他們被設計成向量形式矩陣並且支援迭代器。你不能移除或者改變從Leap API接收的列表中的成員變數,但你可以組合列表中的同一個類型的對象。 對某一個列表使用迭代器:
for(HandList::const_iterator hl = handList.begin(); hl != handList.end();) std::cout << *hl << std::endl;
手、尖端物體、手指和工具列表基於在Leap座標系統下的相對位置,定義了額外的函數來擷取列表中的成員變數。這些函數包含leftmost(),rightmost(),和frontmost()。接下來的小片段代碼說明了使用這些函數的方法:
Leap::Finger farLeft = frame.fingers().leftmost();Leap::Finger mostForwardOnHand = frame.hands()[0].fingers().frontmost();Leap::Tool rightTool = frame.tools().rightmost();
一個更複雜的例子是計算一個包含檢測到的所有尖端物體箱子的矩形體。因為在API中沒有提供,這個例子定義了它自己的函數來擷取頂部、底部和後方的尖端。
float left = frame.pointables().leftmost().tipPosition().x; float right = frame.pointables().rightmost().tipPosition().x; float front = frame.pointables().frontmost().tipPosition().z; float back = backmost(frame.pointables()).tipPosition().z; float top = topmost(frame.pointables()).tipPosition().y; float bottom = bottommost(frame.pointables()).tipPosition().y; Leap::Pointable backmost(PointableList pointables) { if(pointables.count() == 0) return Leap::Pointable::invalid(); Leap::Pointable backmost = pointables[0]; for( int p = 1; p < pointables.count(); p++ ) { if( pointables[p].tipPosition().z > backmost.tipPosition().z) backmost = pointables[p]; } return backmost; } Leap::Pointable topmost(PointableList pointables) { if(pointables.count() == 0) return Leap::Pointable::invalid(); Leap::Pointable topmost = pointables[0]; for( int p = 1; p < pointables.count(); p++ ) { if( pointables[p].tipPosition().y > topmost.tipPosition().y) topmost = pointables[p]; } return topmost; } Leap::Pointable bottommost(PointableList pointables) { if(pointables.count() == 0) return Leap::Pointable::invalid(); Leap::Pointable bottommost = pointables[0]; for( int p = 1; p < pointables.count(); p++ ) { if( pointables[p].tipPosition().y < bottommost.tipPosition().y ) bottommost = pointables[p]; } return bottommost; }
[也就是簡單計算下所有物體三維座標的最小外接矩形,很容易理解~代碼如出一轍,看懂一個後面都懂。看了下API,以及我自己猜測,left,front,right這幾個方位,Leap Motion是比較關注的,而對於高Leap可能無法準確探測,但對於其它幾個方向為什麼不直接提供函數呢?]
手
手類描述了一個被Leap追蹤到的物理形式的手。一個手對象提供了訪問它自己尖端(手指)的列表,以及一個描述的手的座標、朝向和運動的屬性。從一幀中擷取手對象:
Leap::Frame frame = controller.frame(); // controller is a Leap::Controller objectLeap::HandList hands = frame.hands();Leap::Hand firstHand = hands[0];
或者,如果你從前一幀中已知ID:
Leap::Hand knownHand = frame.hand(handID);
你還可以通過它們在幀中相對位置擷取手對象:
Leap::Frame frame = controller.frame(); // controller is a Leap::Controller objectLeap::HandList hands = frame.hands();Leap::Hand leftmost = hands.leftmost();Leap::Hand rightmost = hands.rightmost();Leap::Hand frontmost = hands.frontmost();
注意,rightmost()和rightmost()函數僅僅區分哪只手是最右側或者最左側。這個方法不區分這隻手是左手還是右手。
擷取手特徵
一隻手被通過它的座標、朝向和運動得以描述。 手的座標是通過手掌座標屬性得到的,提供了一個以Leap Motion為原點,毫米為單位的手掌中心三維座標的向量。手的朝向由2個向量給出:方向---從手掌中心指向手指方向,手掌垂直面---指向手掌外側,垂直於手的平面。 手的運動通過運動速度屬性給出,它是一個描述手在毫米每秒瞬時運動的向量。你還可以獲得運動因子,它可以描述一隻手在兩幀時的位移、旋轉和縮放值的變化。 下面的代碼塊描述了如何在一幀中擷取一個手對象和它的基本屬性:
Leap::Hand hand = frame.hands().rightmost(); Leap::Vector position = hand.palmPosition(); Leap::Vector velocity = hand.palmVelocity(); Leap::Vector direction = hand.direction();
擷取指尖和工具
你可以通過列表或僅僅通過之前幀的ID兩種方式,擷取與手關聯的手指和工具。 通過列表方法:
// hand is a Leap::Hand object Leap::PointableList pointables = hand.pointables(); // Both fingers and tools Leap::FingerList fingers = hand.fingers(); Leap::ToolList tools = hand.tools();
通過之前幀ID方法: Leap::Pointable knownPointable = hand.pointable(pointableID); 為了擷取手指或者工具在Leap視野的相對位置,可以使用匹配列表類中right-,left-和frontmost函數。
// hand is a Leap::Hand object Leap::Pointable leftPointable = hand.pointables().leftmost(); Leap::Finger rightFinger = hand.fingers().rightmost(); Leap::Tool frontTool = hand.tools().frontmost();
注意,這些函數都是相對於Leap Motion原點位置的,而不是手它自己的。為了擷取相對於手的手指,你可以使用Leap矩陣類來講手指座標轉換到參考幀的手。[不太懂]
計算手的朝向
使用手的方向和垂直向量,你可以計算出手的朝向角度(相對於東方)。向量類定義了俯仰Pitch旋轉(圍繞x軸旋轉)、左右Yaw旋轉(圍繞y軸的旋轉)和平面Roll旋轉(圍繞z軸旋轉):
float pitch = hand.direction().pitch(); float yaw = hand.direction().yaw(); float roll = hand.palmNormal().roll();
注意,roll函數僅僅提供使用垂直向量時的預判的角度。[看來roll判斷比較困難吧]
將手指座標變換到手的參照幀(以手為參照對象)
有時,通過手的參照幀擷取在手上的手指座標是常用的方法。這種方法可以讓你對手指在空間上進行排序,並且可以簡單的分析手指的座標[很有用啊]。你可以使用Leap矩陣類構建一個轉換矩陣來轉換手指座標和方向座標。參照中的手幀可以通過手的朝向和手掌的垂直向量(由與兩個座標軸正交的第三個座標軸)被有效定義。這種方法使得x軸沿著手側面,而z軸指向前方,y軸與手掌平面平行。
Leap::Frame frame = leap.frame(); for( int h = 0; h < frame.hands().count(); h++ ) { Leap::Hand leapHand = frame.hands()[h]; Leap::Vector handXBasis = leapHand.palmNormal().cross(leapHand.direction()).normalized(); Leap::Vector handYBasis = -leapHand.palmNormal(); Leap::Vector handZBasis = -leapHand.direction(); Leap::Vector handOrigin = leapHand.palmPosition(); Leap::Matrix handTransform = Leap::Matrix(handXBasis, handYBasis, handZBasis, handOrigin); handTransform = handTransform.rigidInverse(); for( int f = 0; f < leapHand.fingers().count(); f++ ) { Leap::Finger leapFinger = leapHand.fingers()[f]; Leap::Vector transformedPosition = handTransform.transformPoint(leapFinger.tipPosition()); Leap::Vector transformedDirection = handTransform.transformDirection(leapFinger.direction()); // Do something with the transformed fingers } }
尖端
尖端對象可以被表示為手指和工具 ---- 也就是可以指出方向的東西。 你可以通過手對象中特定的手,擷取與手關聯的手指和工具。尖端未必要和手對象關聯 --- 物理上的手也許不在視野中或者被另一隻手擋住了。因此幀中尖端列表可以包含哪些和手不關聯的手指和工具[即增加了適用性,同時也引入了複雜性呀]。 尖端對象有著許多描述手指和工具的屬性: #尖端座標 --- 在Leap Motion座標系下以毫米為單位的瞬時的座標。 #尖端速度 --- 以毫米每秒為單位的瞬時速度。 #指向 --- 當前的指向朝向向量。 #長度
--- 手指和工具顯現的長度。 #寬度 --- 平均寬度。 #觸摸距離 --- 在虛擬觸摸平面中歸一後的距離。 #觸摸地區 --- 當前尖端和虛擬觸摸平面的關係。 下面的例子說明如何從幀中擷取簡短對象和基本訪問屬性的方法:
Leap::Pointable pointable = frame.pointables().frontmost(); Leap::Vector direction = pointable.direction(); float length = pointable.length(); float width = pointable.width(); Leap::Vector stabilizedPosition = pointable.stabilizedTipPosition(); Leap::Vector position = pointable.tipPosition(); Leap::Vector speed = pointable.tipVelocity(); float touchDistance = pointable.touchDistance(); Leap::Pointable::Zone zone = pointable.touchZone();
將尖端對象轉化成手指或者工具
為了將尖端對象轉化到合適的手指和工具子類,需要使用合適的手指和工具建構函式(某些時候你應該使用Leap類的建構函式)[不太明白]。
if (pointable.isTool()) { Leap::Tool tool = Leap::Tool(pointable); } else { Leap::Finger finger = Leap::Finger(pointable); }
計算手指基本位置
如果你需要計算手指的基本位置,你可以如下使用手指尖位置和朝向:
Leap::Vector basePosition = -pointable.direction() * pointable.length(); basePosition += pointable.tipPosition();