はつねの日記

Kinect, Windows 10 UWP, Windows Azure, IoT, 電子工作

Leap Motion - Tracking Hands, Fingers, and Tools の日本語訳

Leap Motionの日本語情報は非常に限られているので公式ドキュメントをざっくり日本語訳にしました。誤訳などあったらお知らせください。

本エントリはhttps://developer.leapmotion.com/documentation/Languages/CSharpandUnity/Guides/Leap_Tracking.htmlの日本語訳となります。

Tracking Hands, Fingers, and Tools

手、指およびツールはLeap Motion Systemにおけるトラッキング基本エンティティです。本稿ではこれらのエンティティを表すオブジェクトの取得方法と使用方法の詳細を説明します。

Topics:
    • Overview
    • Hand, and Pointable Lists
    • Hands
      • Getting the Hand Characteristics
      • Getting the Fingers and Tools
      • Computing the Hand Orientation
      • Transforming Finger Coordinates into the Hand's Frame of Reference
    • Pointables
      • Converting a Pointable Object to a Finger or Tool
      • Calculating the Position of the Base of a Finger

Overview

Leap APIはトラッキング基本オブジェクトを表すクラスを定義しています。

Frameオブジェクトは、手、指およびツールのリストへのアクセスを提供します。例えばPointableオブジェクトである指とツールはPointableListとして一緒に扱うかFingerListとToolListクラスを使用して個別に扱うことができます。手のオブジェクトは指とツール(PointableListとして一緒に、または別個に)へのアクセスを提供します。

手、指およびツールの物理的特性はLeap座標系(mm単位で測定)の値として取得できます。Leap SDKは位置と方向を表すVectorクラスを提供します。Vectrorクラスを扱うための数学関数を提供します。

Hand, and Pointable Lists

Listクラスはすべて同じ構造を持っています。ベクトル形式の配列のように振る舞うし、イテレータ(反復子)をサポートしています。Leap APIから受信したメンバーオブジェクトを削除したり変更することはできませんが、同じオブジェクトタイプのリストを組み合わせる事ができます。

反復処理を行って例は次のようになります。

VB.NET
    For Each Hand hand in handList
        Console.WriteLine(hand.ToString())
    Next
C#
    foreach (Hand hand in handList) {
        Console.WriteLine(hand.ToString());
    }

 

手、Pointable、指およびツールリストは、Leap座標系の相対位置に基づいて、リストのメンバーを取得するためのleftmost()、rightmost()そしてfrontmostなどが定義されています。次のスニペットではこれらの関数を使用するいくつかの方法を示しています。

VB.NET
    Dim farLeft As Finger = _frame.Fingers.Leftmost
    Dim mostForwardOnHand As Finger = _frame.Hands(0).Fingers.Frontmost
    Dim rightTool As Tool = _frame.Tools.Rightmost
C#
    Finger farLeft = frame.Fingers.Leftmost;
    Finger mostForwardOnHand = frame.Hands[0].Fingers.Frontmost;
    Tool rightTool = frame.Tools.Rightmost;

 

より複雑な例では、検出されたすべてのPointableオブジェクトを含むバウンディングボックスの壁を計算してみます。APIには含まれていない機能なので、下記の例では、上、下を取得するための独自の関数及びリアPointablesを定義します。

VB.NET
    Private left As single = frame.Pointables.Leftmost.TipPosition.x
    Private right As single = frame.Pointables.Rightmost.TipPosition.x
    Private front As single = frame.Pointables.Frontmost.TipPosition.z

    Private back As single = backmost(frame.Pointables).TipPosition.z
    Private top As single = topmost(frame.Pointables).TipPosition.y
    Private bottom As single = bottommost(frame.Pointables).TipPosition.y

    Private Function backmost(pointables As PointableList) As Pointable
        If pointables.Count = 0 Then
            return Pointable.Invalid
        End If
        Dim backmost As Pointable = pointables(0)
        For p = 1 As Integer To p < pointables.Count - 1
            If pointables[p].TipPosition.z > backmost.TipPosition.z Then
                backmost = pointables(p)
            End If
        Next
        Return backmost
    End Function

    Private Function topmost(pointables As PointableList) As Pointable
        If pointables.Count = 0 Then
            return Pointable.Invalid
        End If
        Dim topmost As Pointable = pointables(0)
        For p = 1 As Integer To p < pointables.Count - 1
            If pointables[p].TipPosition.y > topmost.TipPosition.y Then
                topmost = pointables(p)
            End If
        Next
        Return topmost
    End Function

    Private Function bottommost(pointables As PointableList) As Pointable
        If pointables.Count = 0 Then
            return Pointable.Invalid
        End If
        Dim bottommost As Pointable = pointables(0)
        For p = 1 As Integer To p < pointables.Count - 1
            If pointables[p].TipPosition.y > bottommost.TipPosition.y Then
                bottommost = pointables(p)
            End If
        Next
        Return bottommost;
    End Function
C#
    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;

    Pointable backmost(PointableList pointables)
    {
        if(pointables.Count == 0) return Pointable.Invalid;
        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;
    }

    Pointable topmost(PointableList pointables)
    {
        if(pointables.Count == 0) return Pointable.Invalid;
        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;
    }

    Pointable bottommost(PointableList pointables)
    {
        if(pointables.Count == 0) return Pointable.Invalid;
        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;
    }

Hands

HandクラスはLeapによって検出された物理的な手を表しています。HandオブジェクトはPointablesリストだけではなく、手の位置、向き、動きなどの属性へのアクセスを提供します。

次の例ではFrameからHandオブジェクトを取得してます。

VB.NET
    Dim _frame As Frame = controller.Frame ‘ controller is a Controller object
    Dim hands As HandList = _frame.Hands
    Dim firstHand AS Hand = hands(0)
C#
    Frame frame = controller.Frame(); // controller is a Controller object
    HandList hands = frame.Hands;
    Hand firstHand = hands[0];

 

Frameの中での相対的な手の位置を取得するには次のようなコードを記述します。

VB.NET
    Dim _frame As Frame = controller.Frame ‘ controller is a Controller object
    Dim hands As HandList = frame.Hands

    Dim leftmost As Hand = hands.Leftmost
    Dim rightmost As Hand = hands.Rightmost
    Dim frontmost As Hand = hands.Frontmost
C#
    Frame frame = controller.Frame(); // controller is a Controller object
    HandList hands = frame.Hands;

    Hand leftmost = hands.Leftmost;
    Hand rightmost = hands.Rightmost;
    Hand frontmost = hands.Frontmost;

注意:Leftmost()とRightmost()は、もっとも左または右に離れている手を識別することに注意してください。位置関係の判定であり左手や右手を認識しているわけではありません。

Getting the Hand Characteristics

手に対しては、位置、方向、動きを取得できます。

手の位置はLeap Motinからミリメートル単位で掌の中心点の3次元座標を含むベクターで表された掌位置属性で指定されます。手の方向は、掌の中心から指の方向と垂直方向の2つのベクトルによって与えられます。

手の動きはmm/secで手の瞬間的な動きがベクトルとして取得できます。また、2つの指定したフレーム間での手の平行移動、回転、拡大縮小値を変換するモーションファクターを取得できます。

次のコードスニペットでは、フレームからHandオブジェクトを取得し、その基本的な属性にアクセスする方法を示しています。

VB.NET
    Dim _hand As Hand = frame.Hands.Rightmost
    Dim position As Vector = hand.PalmPosition
    Dim velocity As Vector = hand.PalmVelocity
    Dim direction As Vector = hand.Direction
C#
    Hand hand = frame.Hands.Rightmost;
    Vector position = hand.PalmPosition;
    Vector velocity = hand.PalmVelocity;
    Vector direction = hand.Direction;

Getting the Fingers and Tools

IDを使ってリストや個別情報から手と一緒に指やツールも取得できます。

リストの例は次のようになります。

VB.NET
    ' hand is a Hand object
    DIm pointables As PointableList = hand.Pointables ' Both fingers and tools
    Dim fingers As FingerList = hand.Fingers
    Dim tools As ToolList = hand.Tools
C#
    // hand is a Hand object
    PointableList pointables = hand.Pointables; // Both fingers and tools
    FingerList fingers = hand.Fingers;
    ToolList tools = hand.Tools;

 

以前のフレームのIDを使った例は次のようになります。

VB.NET
    Dim knownPointable As Pointable = hand.Pointable(pointableID)
C#
    Pointable knownPointable = hand.Pointable(pointableID);

 

Leapの検出範囲内での指やツールの位置を取得するのに、listクラスのrightmost、leftmostおよびfrontmostが使えます。

VB.NET
    ' hand is a Hand object
    Dim leftPointable As Pointable = hand.Pointables.Leftmost
    Dim rightFinger As Finger = hand.Fingers.Rightmost
    Dim frontTool As Tool = hand.Tools.Frontmost
C#
    // hand is a Hand object
    Pointable leftPointable = hand.Pointables.Leftmost;
    Finger rightFinger = hand.Fingers.Rightmost;
    Tool frontTool = hand.Tools.Frontmost;

注意:手自体ではなくLeap Motionの中心点に対して相対的なことに注意してください。手を基準にして指を取得するにはLeap Matrixクラスを使用して変換します。

Transforming Finger Coordinates into the Hand's Frame of Reference

参照している手のフレームと手の指の座標が一緒に取得できると便利な場合が多いです。なぜなら指を並べたときに指の位置の分析を簡略化できるからです。指の位置と方向を変換するためLeap Matrixクラスを使用して変換行列を作成することができます。手の基準は、2つの間のクロス積で定義されている3番目の軸と手の方向と掌の法線ベクトルを使用して定義できます。

VB.NET
    Dim _frame As Frame = leap.Frame
    For h As Integer = 0 To h < frame.Hands.Count - 1
        Hand leapHand = frame.Hands(h)

        Vector handXBasis =  leapHand.PalmNormal.Cross(leapHand.Direction).Normalized
        Vector handYBasis = -leapHand.PalmNormal
        Vector handZBasis = -leapHand.Direction
        Vector handOrigin =  leapHand.PalmPosition
        handTransform As Matrix = new Matrix(handXBasis, handYBasis, handZBasis, handOrigin)
        handTransform = handTransform.RigidInverse()

        For f As Integer = 0 To f < leapHand.Fingers.Count - 1
            Dim leapFinger As Finger = leapHand.Fingers(f)
            Dim transformedPosition As Vector = handTransform.TransformPoint(leapFinger.TipPosition)
            Dim transformedDirection As Vector = handTransform.TransformDirection(leapFinger.Direction)
            ' Do something with the transformed fingers
        Next
    Next
C#
    Frame frame = leap.Frame();
    for( int h = 0; h < frame.Hands.Count; h++ )
    {
        Hand leapHand = frame.Hands[h];

        Vector handXBasis =  leapHand.PalmNormal.Cross(leapHand.Direction).Normalized;
        Vector handYBasis = -leapHand.PalmNormal;
        Vector handZBasis = -leapHand.Direction;
        Vector handOrigin =  leapHand.PalmPosition;
        Matrix handTransform = new Matrix(handXBasis, handYBasis, handZBasis, handOrigin);
        handTransform = handTransform.RigidInverse();

        for( int f = 0; f < leapHand.Fingers.Count; f++ )
        {
            Finger leapFinger = leapHand.Fingers[f];
            Vector transformedPosition = handTransform.TransformPoint(leapFinger.TipPosition);
            Vector transformedDirection = handTransform.TransformDirection(leapFinger.Direction);
            // Do something with the transformed fingers
        }
    }

Pointables

Pointableオブジェクトは指とツール、すなわち指し示すものを表します。指や手のオブジェクトから特定の手に関連付けられているツール(つまり手に持っている道具)を得ることができます。また、Frameオブジェクトから検出されたすべてのPointablesを得ることができます。Pointablesは必ずしもHandオブジェクトに関連付けられていません。例えば、物理的な手自体がLeap検出範囲の外に当ても良いし、別の手でブロックされている場合もあるでしょう)。したがってFrameからのPointablesリストには関連付けられていないLeapが検出できなかった指やツールを含めることができます。

Pointableオブジェクトは指やツールの特性を記述した多くの属性があります。

  • TipPosition:Leap Motionからの先端までの距離をmm単位で表す
  • TipVelocity:先端の移動速度(mm/sec)
  • StabilizedTipPosition:手ぶれ防止フィルタをかけた位置と速度
  • Direction:先端が差す方向
  • Length:指またはツールの見かけ上の長さ
  • Width:平均幅
  • TouchDistance:仮想タッチ面からの正規化した距離
  • TouchZone:先端と仮想タッチ面の関係

次の例は、FrameからPointableオブジェクトを取得し、その基本的な特性にアクセスする方法を示しています。

VB.NET
    Dim _pointable As Pointable = _frame.Pointables.Frontmost
    Dim direction As Vector = _pointable.Direction
    Dim length As Single = _pointable.Length
    Dim width As Single = _pointable.Width
    Dim stabilizedPosition As Vector = _pointable.StabilizedTipPosition
    Dim position As Vector = _pointable.TipPosition
    Dim speed As Vector = _pointable.TipVelocity
    Dim touchDistance As Single = _pointable.TouchDistance
    Dim zone As Pointable.Zone = _pointable.TouchZone
C#
    Pointable pointable = frame.Pointables.Frontmost;
    Vector direction = pointable.Direction;
    float length = pointable.Length;
    float width = pointable.Width;
    Vector stabilizedPosition = pointable.StabilizedTipPosition;
    Vector position = pointable.TipPosition;
    Vector speed = pointable.TipVelocity;
    float touchDistance = pointable.TouchDistance;
    Pointable.Zone zone = pointable.TouchZone;

Converting a Pointable Object to a Finger or Tool

Pointableオブジェクトを適切なFingerサブクラスやToolサブクラスに変換するには、適切なコンストラクター(Leapクラスのコンストラクタを使う必要があります)を使ってください。

VB.NET
    If (_pointable.IsTool) Then
        Dim _tool As new Tool(_pointable)
    else
        Dim _finger As new Finger(_pointable)
    End If
C#
    if (pointable.IsTool) {
        Tool tool = new Tool(pointable);
    } else {
        Finger finger = new Finger(pointable);
    }

Calculating the Position of the Base of a Finger

指の起点を位置を計算する場合は、次のように指の先端の位置と方向を使用します。

VB.NET
    Vector basePosition = -pointable.Direction * pointable.Length
    basePosition += pointable.TipPosition
C#
    Vector basePosition = -pointable.Direction * pointable.Length;
    basePosition += pointable.TipPosition;