連載:Leap Motion開発入門(C#編)
Leap Motionでのタッチ操作はどう開発するのか?
Leapアプリのタッチ操作の認識方法と開発方法を説明。※C++編の同名タイトルの記事と基本的な内容は同じです。
第1回および第2回でLeap Motionを利用したアプリケーションの基本的な開発方法および手指の検出について解説した。今回は、よりLeap Motionらしいアプリケーションとして、タッチ操作を扱う。
サンプルコードは、Leap Motionの開発者サイトにある「Touch Emulation」を利用する。
今回のサンプルコードも次のリンク先で公開している。Visual Studio Express 2013 for Windows Desktopでの動作確認を行い、プロジェクトファイルを含めてすぐに利用できるようにしてある。
Touch Emulation
このプログラムを実行し、Leap Motion上に手をかざして指を後ろから前に動かすと緑の丸が現れ、さらに前に動かすと赤に変わる。丸の色は緑●がホバー状態を表し、赤●に変わった位置がタッチを表す。Leap Motionのような非接触のユーザーインターフェースをタッチに利用する場合には、タッチしようとする位置が分かりづらいため、ホバーを利用してタッチしようとしている位置をユーザーに教えて上げることで操作に対するストレスが軽減される。図1は、サンプルの実行例である。
タッチの検出は、C++編第1回で紹介したジェスチャーのScreenTapGesture
クラスでも可能だが、ScreenTapGesture
は(筆者の感覚で)認識が難しいこと、瞬間的なイベントであるため、事前のホバー状態、事後のタッチし続けている状態といった一連のタッチ操作を検出できないことから、Leap Motionを利用したタッチ操作には、今回紹介するLeap.Pointable
クラスを使うことが望ましいと考えている。
Leap Motionを利用したタッチの認識
まずはLeap Motionがどのようにタッチを認識しているかを解説する。
次の図が動作イメージであり、「仮想的なタッチパネル(The virtual touch surface)を持っている」と考えると分かりやすいだろう。仮想的なタッチパネルの前後に状態を判定する空間があり、手前側が「ホバー状態(hovering)」、奥側が「タッチ状態(touching)」を表す。空間の範囲は前後1
~-1
となっているが正確な単位については確認できていない。
コードの解説
本サンプルコードでの注目点はprotected void Update(object sender, EventArgs e)
というメソッドの中身のみとなり、ここに全てが実装されている。
フレームデータを取得する
このフレームでのLeap.Frame
オブジェクトおよびLeap.InteractionBox
オブジェクトを取得する。
Frame frame = leap.Frame();
InteractionBox interactionBox = leap.Frame().InteractionBox;
|
Leap.PointableList
オブジェクトは、名前の通りLeap.Pointable
オブジェクトのリストであり、指やツール(=棒状のもの)をひとまとめにして表している。Leap.Finger
クラスおよびLeap.Tool
クラスは、Leap.Pointable
クラスを継承している。ここではタッチの位置を取得するためにPointableList
オブジェクトを利用する。
Leap.InteractionBox
オブジェクト(=インタラクションボックス)は、Leap Motionで認識できる可動範囲となり、下記のイメージだ。InteractionBox
オブジェクトを利用することで指やツールの位置を実際のディスプレイの座標系に変換できる。
ポイントされた座標を取得する
PointableList
オブジェクトをループで順に処理する。その処理コードは、次のようになっている。
foreach ( Pointable pointable in leap.Frame().Pointables )
{
……省略……
Leap.Vector normalizedPosition = interactionBox.NormalizePoint( pointable.StabilizedTipPosition );
float tx = normalizedPosition.x * windowWidth;
float ty = windowHeight - normalizedPosition.y * windowHeight;
……省略……
}
|
Leap.InteractionBox.NormalizePoint()
メソッドにLeap.Pointable.StabilizedTipPosition
プロパティを渡してポインターの画面上の位置を取得する。取得した画面上の位置はLeap.Vector
型となり、画面サイズ上でのポインターの位置が0.0
~1.0
の間で表される。これを実際の画面サイズで割り出すが、Leap Motionのスクリーン座標系の原点が左下であるため(図4を参照)、Y座標は高さの値から算出した値を引くことで、左上を原点とする座標にしている。
タッチの状態に合わせた処理を行う
続けてループ内で、タッチの状態に合わせた処理を実施する。この際、タッチの状態はLeap.Pointable.TouchDistance
プロパティおよびLeap.Pointable.TouchZone
プロパティで取得する。
今回のサンプルコードでは、(リスト3のように)取得された状態と座標によって表示される丸の色および位置を変えている。ホバーはタッチされていないが指を認識している状態で、「指を押し込むと、ここがタッチされる」という場所を示すものだ。
// ホバー状態
if ( pointable.TouchDistance > 0 && pointable.TouchZone != Pointable.Zone.ZONENONE ) {
alpha = 255 - (int)(255 * pointable.TouchDistance);
touchIndicator.Color = Color.FromArgb( (byte)alpha, 0x0, 0xff, 0x0 );
}
// タッチ状態
else if ( pointable.TouchDistance <= 0 ) {
alpha = -(int)(255 * pointable.TouchDistance);
touchIndicator.Color = Color.FromArgb( (byte)alpha, 0xff, 0x0, 0x0 );
}
// タッチ対象外
else {
alpha = 50;
touchIndicator.Color = Color.FromArgb( (byte)alpha, 0x0, 0x0, 0xff );
}
|
TouchDistance
プロパティは下の図の+1
~0
~-1
の値を返す。また、TouchZone
プロパティはLeap.Pointable.Zone
列挙体の値を返し、この値は「ホバー中(ZONEHOVERING)」「タッチ中(ZONETOUCHING)」「なし(ZONENONE)」、いずれかの状態を指す。
TouchDistance
プロパティおよびTouchZone
プロパティの状態は同期しており、次のようになっている(以下の説明を読んで、上の図を見直すとよりよく理解できるだろう)。
TouchDistance
プロパティが「1」であれば、TouchZone
プロパティは「ZONENONE」TouchDistance
プロパティが「1」以下、かつ「0」より大きい値であれば、TouchZone
プロパティは「ZONEHOVERING」TouchDistance
プロパティが「0」以下、かつ「-1」より大きい値であれば、TouchZone
プロパティは「ZONETOUCHING」
伸びている指やツールのみを検出させる
「これは快適! Leap Motion v2で格段に良くなったSkeletal Tracking機能」でLeap Motion SDK v2について解説した。
V2では指を開いても閉じても5本の指を検出し続けるようになった。これによって指を閉じた(グーの状態)で手を突き出してもタッチとして認識してしまう。これは多くの場合、意図しない動作だろう。そこで伸びている指およびツールのみタッチとして認識するようにさせる。
先の解説にも書いたが、Leap.Pointable.IsExtended
プロパティで伸びているかどうかの状態を取得できる。これを使って次のようにコードを追加することで、意図する動作に変更できる。なお、Leap.Finger
クラス(指)およびLeap.Tool
クラス(ツール)はLeap.Pointable
クラスを継承しているため、同様にIsExtended
プロパティを使うことができる。
foreach ( Pointable pointable in leap.Frame().Pointables ) {
// ここから追加
// 伸びている指、ツール以外は無視する
if ( !pointable.IsExtended ) {
continue;
}
// ここまで追加
……省略……
}
|
これによって、人差し指1本だけを伸ばしたタッチでは1つの円のみが表示される(図6)。先ほど追加したコードを入れたり外したりして、動作の違いを確認するとよい。
まとめ
以上で今回の解説は終了だ。モーション・センサー・デバイスのSDKでは、ユーザーインターフェースへの活用が多いため、デバイスの座標系からスクリーンの座標系に変換する実装を多く行う。Leap Motion Developer SDKではこの座標系変換についても、より簡単に行える。実装者はLeap Motionの視野角を含めた見え方と、それをスクリーンに投影する際の変換イメージを持つことで、より簡単に扱えるだろう。
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のいろいろな使い方」と基本的な内容は同じです。