Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
連載:Leap Motion開発入門(C#編)

連載:Leap Motion開発入門(C#編)

C#によるLeap Motion v2開発の全体像

2015年8月14日 改訂 (初版:2013/9/13)

Leap Motion Developer SDKを利用してC#でLeap Motionのアプリケーションを開発する方法を解説する連載(2015年改訂版)。今回はC#の開発環境など、開発の基礎を紹介。

Natural Software 中村 薫
  • このエントリーをはてなブックマークに追加

 本連載では、Leap Motion Developer SDK(v2)を利用してC#でLeap Motionのアプリケーションを開発する方法について、サンプルコードを示しながら解説する。Leap Motionの基本的なことがらについては、(v1時代の初期の内容ではあるが)「C#開発者から見たLeap Motion開発のファースト・インプレッション」を参照していただきたい。

 連載は全5回を予定しており、内容としては同テーマC++編における以下の回をC#で記述した場合の解説だ。

 本連載でのサンプルコードは下記のリンク先で公開しており、Visual Studio Express 2013 for Windows Desktopでの動作確認を行っている。

C#で開発できる環境について

 Leap SDKとC#を使うと、さまざまな環境で開発を行える。Leap SDKに付属しているC#のDLLファイルは.NET Framework 3.5および4.0に対応しており、このバージョンが動作する環境であればどこでもよい。動作環境には互換フレームワークであるMonoも含まれており、Windows以外(Mac OS X、Linux)での利用も可能だ。これはLeap SDKがUnityへの対応がなされているためだ。

 Leap SDKとC#を使った開発環境をまとめると次のとおり。

  • .NET Framework 3.5および4.0環境以上でのWindowsデスクトップアプリケーション
  • Unity 4 ProまたはUnity 5 Personal、Pro(Windows、Mac OS X)
  • Monoが動くWindows以外の環境

C#での開発環境の構築

 まずはLeap Motionアプリケーションの開発環境を構築しておこう。Windowsでの開発環境の整備については、下記のリンク先を参考にしていただきたい。

C#で開発する際の実装方法

 Leap MotionのアプリケーションをC#で開発する際には、主にWPFもしくはUnityを利用した開発になるだろう。特にWPFで開発する際には一般的なアプリケーションとは少し異なるので、その点について解説する。

 Leap SDKからLeap Motionのデータを取得する方法は2種類ある。Controllerクラス(Leap名前空間)だけを使用した「ポーリング方式」と、ControllerクラスとListenerクラス(Leap名前空間)を利用した「コールバック方式」だ。Leap Motionサイトのサンプルや、本サイトのVB.NET(Visual Basic)での解説、Unityでの実装もポーリングを利用している。

ポーリング方式でのデータ取得

 ポーリング方式とは、ある一定の周期でアプリケーションからLeap SDKへデータを取得する方式だ。WPFでは例えばCompositionTargetクラスのRenderingイベントに登録することで、WPFのレンダリング周期に合わせてイベントハンドラーが呼ばれる。このタイミングでLeap SDKからデータを取得し、処理を行う。UnityについてはMonoBehaviourクラスの派生クラス内で呼ばれるUpdateメソッドのタイミングでデータの取得を行う。

 この方式のメリット/デメリットを以下に示す。

【ポーリング方式のメリット】

  • 処理をシンプルにできること

【ポーリング方式のデメリット】

  • Renderingイベントを利用する場合、イベント発生の周期(1秒間に50~60回の周期)が上限になるため、Leap Motionの更新周期(1秒間に100回以上の周期)よりも遅くなる(フレーム履歴にて処理は可能)
  • Listenerクラスにある接続イベント(OnConnectメソッド)やフォーカスイベント(OnFocusLostメソッド)を自分で実装する必要がある(「Frameについて」の回で解説予定)

コールバック方式でのデータ取得

 コールバック方式は、Listenerクラス継承の派生クラスを、ControllerクラスにAddListenerメソッドで登録し、Listenerクラスのメソッドをオーバーライドしてイベントを受け取る方法だ。オーバーライドしたメソッドには注意点があり、呼び出しスレッドがワーカースレッドになるため、WPFのUI(ユーザーインターフェース)をそのままでは扱えない。UIを扱うためにはスレッドをUIスレッドに戻す必要がある。

 メリットおよびデメリットについてはポーリング方式の逆になるので、アプリケーションの目的や実装方法によっていずれかの方式を選択していただきたい。

 ここでは1つの例としてSynchronizationContextクラスを使って同期的にUIスレッドに戻し、イベントを発行するようにしてみる。次のコードは、UIスレッドに同期的に処理を戻すListener派生クラスの実装例である。

C#
using System.Threading;
using Leap;

namespace NaturalSoftware.Leap.Toolkit
{
  public class LeapListener : Listener
  {
    // UIスレッドに戻すためのコンテキスト
    SynchronizationContext context = SynchronizationContext.Current;

    public delegate void LeapListenerEvent( Controller leap );

    // イベントハンドラー
    public event LeapListenerEvent OnConnectEvent;
    public event LeapListenerEvent OnDisconnectEvent;
    public event LeapListenerEvent OnInitEvent;
    public event LeapListenerEvent OnExitEvent;
    public event LeapListenerEvent OnFocusGainedEvent;
    public event LeapListenerEvent OnFocusLostEvent;
    public event LeapListenerEvent OnFrameEvent;

    public override void OnConnect( Controller leap )
    {
      Invoke( leap, OnConnectEvent );
    }

    public override void OnDisconnect( Controller leap )
    {
      Invoke( leap, OnDisconnectEvent );
    }

    public override void OnInit( Controller leap )
    {
      Invoke( leap, OnInitEvent );
    }

    public override void OnExit( Controller leap )
    {
      Invoke( leap, OnExitEvent );
    }

    public override void OnFocusGained( Controller leap )
    {
      Invoke( leap, OnFocusGainedEvent );
    }

    public override void OnFocusLost( Controller leap )
    {
      Invoke( leap, OnFocusLostEvent );
    }

    public override void OnFrame( Controller leap )
    {
      Invoke( leap, OnFrameEvent );
    }

    // イベントを発行する
    private void Invoke( Controller leap, LeapListenerEvent handler )
    {
      // UIスレッドに同期的に処理を戻す
      context.Post( state =>
      {
        if ( handler != null ) {
          handler( leap );
        }
      }, null );
    }
  }
}
UIスレッドに同期的に処理を戻すListener派生クラス(LeapListener.cs)

 このクラスを利用することで、一般的なイベントドリブンの形で実装を行えるようになる。次のコードは、上記のListener派生クラスのインスタンスをControllerオブジェクトに登録し、さらにFrameReadyイベントのイベントハンドラーを実装している例である。このイベントハンドラー内では、UIスレッドに処理が戻っているため、WPFのUIオブジェクトも触ることができる。

C#
……省略……
Controller leap;
LeapListener listener;

private void Window_Loaded( object sender, RoutedEventArgs e )
{
  leap = new Controller();

  // リスナーオブジェクトとFrameイベントを登録する
  listener = new LeapListener();
  listener.OnFrameEvent += listener_OnFrameEvent;

  // リスナーオブジェクトを登録する
  leap.AddListener(listener);}

void listener_OnFrameEvent( Controller leap )
{
  // ここではWPFのUIオブジェクトも触ることができる
  // フレームの処理を行う
  var frame = leap.Frame();

  TextLeap.Text = "Event Frame id: " + frame.Id
                + ", timestamp: "    + frame.Timestamp
                + ", hands: "        + frame.Hands.Count
                + ", fingers: "      + frame.Fingers.Count
                + ", tools: "        + frame.Tools.Count
                + ", gestures: "     + frame.Gestures().Count;
}
……省略……
コールバック方式を実装したMainWindowクラス(MainWindow.cs)

まとめ

 このようにLeap SDKをC#で利用する場合には事前に意識しておくことがいくつかある。ただし、これらは決まりごとのようなものなので、手段をいくつか持っておくことで問題なく対応することが可能である。

連載:Leap Motion開発入門(C#編)
1. 【現在、表示中】≫ C#によるLeap Motion v2開発の全体像

Leap Motion Developer SDKを利用してC#でLeap Motionのアプリケーションを開発する方法を解説する連載(2015年改訂版)。今回はC#の開発環境など、開発の基礎を紹介。

連載:Leap Motion開発入門(C#編)
2. Leap SDKで指を検出してみよう(Tracking Hands, Fingers, and Tools)

Leap Motionの最大の特長である手・指を検出するには? Leap Motion Developer SDKを活用した開発方法を詳しく解説。※C++編の同名タイトルと基本的な内容は同じです。

連載:Leap Motion開発入門(C#編)
3. Leap Motionでのタッチ操作はどう開発するのか?

Leapアプリのタッチ操作の認識方法と開発方法を説明。※C++編の同名タイトルの記事と基本的な内容は同じです。

連載:Leap Motion開発入門(C#編)
4. Leap Motionのカメラ画像を取得する

Leapアプリのタッチ操作の認識方法と開発方法を説明。新規書き下ろし。※C++編の同名タイトルの記事と基本的な内容は同じです。

連載:Leap Motion開発入門(C#編)
5. フレームのいろいろな使い方

Leap Motion公式のサンプルを題材に、さまざまなフレームの扱い方についてコードを交えて解説。※C++編の「Leap SDKのいろいろな使い方」と基本的な内容は同じです。

サイトからのお知らせ

Twitterでつぶやこう!