連載:Leap Motion開発入門(C#編)
C#によるLeap Motion v2開発の全体像
Leap Motion Developer SDKを利用してC#でLeap Motionのアプリケーションを開発する方法を解説する連載(2015年改訂版)。今回はC#の開発環境など、開発の基礎を紹介。
本連載では、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
派生クラスの実装例である。
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 );
}
}
}
|
このクラスを利用することで、一般的なイベントドリブンの形で実装を行えるようになる。次のコードは、上記のListener
派生クラスのインスタンスをController
オブジェクトに登録し、さらにFrameReady
イベントのイベントハンドラーを実装している例である。このイベントハンドラー内では、UIスレッドに処理が戻っているため、WPFのUIオブジェクトも触ることができる。
……省略……
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;
}
……省略……
|
まとめ
このようにLeap SDKをC#で利用する場合には事前に意識しておくことがいくつかある。ただし、これらは決まりごとのようなものなので、手段をいくつか持っておくことで問題なく対応することが可能である。
1. 【現在、表示中】≫ C#によるLeap Motion v2開発の全体像
Leap Motion Developer SDKを利用してC#でLeap Motionのアプリケーションを開発する方法を解説する連載(2015年改訂版)。今回はC#の開発環境など、開発の基礎を紹介。
2. Leap SDKで指を検出してみよう(Tracking Hands, Fingers, and Tools)
Leap Motionの最大の特長である手・指を検出するには? Leap Motion Developer SDKを活用した開発方法を詳しく解説。※C++編の同名タイトルと基本的な内容は同じです。
5. フレームのいろいろな使い方
Leap Motion公式のサンプルを題材に、さまざまなフレームの扱い方についてコードを交えて解説。※C++編の「Leap SDKのいろいろな使い方」と基本的な内容は同じです。