Leap Motion v1 が自動でアップグレードされないようにする

Leap Motion Controller のソフトウェアは、v2 よりも v1 のほうがトラッキングの精度自体は高いため、
v1 を利用したいケースも依然としてあります。

Leap Motion v1 の実行環境をセットアップするには、
Leap Motion のセットアップで書いた通りインストーラーを実行したあと、
コントロール パネルを開いて [最新版を自動的にインストール] のチェックをオフに設定します。

Leap-v1-ControlPanel

この設定変更をしないと、しばらく経つと自動的に v2 のインストーラーをダウンロードしてアップグレードしてしまいます。

問題はここからです。
v2 にアップグレードしてしまったとしても「v2 アンインストール& v1 再インストール」でやり直せると思いきや、
なんと v1 を再インストールした直後に間髪入れずに v2 にアップグレードされてしまいます。

これはどうやら、最初に v2 にアップグレードしたときに使用したインストーラーが
    C:\Windows\Temp\leap
に残っていることが原因のようです。

Leap 2.3.1 Installer

このインストーラーを削除してから v1 のインストーラーを再実行すれば解決します。

// 他にも、ユーザー フォルダーの「AppData\Local\Temp\~nsu.tmp」フォルダーに .exe ファイルが残ってたりしますが、
// こちらは直接影響しないようです。

参照
Leap Motion のセットアップ

カテゴリー: 周辺機器. タグ: , . 1 Comment »

Leap Motion で手の回転状態を取得する

Leap Motion Controller の公式 SDK では、手の回転の状態をオイラー角で取得できるようになっています。
具体的には、Hand.Direction (Vector オブジェクト) の Yaw, Pitch, Roll プロパティが用意されています。
ただし、Hand クラスの説明を参照すると、 ロールについては Direction.Roll ではなく PalmNormal.Roll を使うように書かれています。

float pitch = hand.Direction.Pitch;
float yaw = hand.Direction.Yaw;
float roll = hand.PalmNormal.Roll;

しかし、これらの値を使って実装してみても、期待通りの動作にはなりません。

そこで、前回の 3D における回転の表現と相互変換の内容をもとに、手の回転の状態を取得する機能を自作しました。

Hand.Direction と Hand.PalmNormal はともに長さ 1 で直交しているため、
これらをそれぞれ (0, 0, -1) と (0, -1, 0) の回転後のベクトルと見なして、
前回作成した Rotation3DHelper クラスを利用してオイラー角を求めれば OK です。

全体のソースコードは HandRotationLeap (GitHub) にあります。
このサンプルでは、手とさいころの回転の状態を同期させています。

Hand Rotation by Leap Motion Controller

前回: 3D における回転の表現と相互変換

バージョン情報
.NET Framework 4.5
Leap Motion SDK 2.3.1

参照
Hand クラス

Leap Motion v2 のセットアップ

Leap Motion SDK のバージョン 2 系を .NET 開発で利用するためのセットアップの方法について記述します。
(以前に Leap Motion のセットアップを書きましたが、その改訂版です。)

Leap Motion のサイトから、ドライバーおよび SDK をダウンロードできます。
開発環境ではこれらの両方が必要ですが、非開発環境ではドライバーのみをインストールします。

 

■ 非開発環境におけるセットアップ

Setup Your Leap Motion Controller でドライバーをダウンロードしてインストールします。

最新版以外のバージョンを指定してインストールするには、
V2 Desktop | Leap Motion Developers で Leap Motion SDK (ZIP) をダウンロードします。
ダウンロードするには、アカウントの登録が必要です。
この ZIP ファイルにはドライバーのインストーラーが含まれているので、それを実行します。

なお v2 では、Leap Motion コントロール パネルの [トラッキング] タブで
[道具の追跡] が既定でオフになっているようです。
指以外のツールを使えるようにするには、これをオンに設定します。

 

■ 開発環境におけるセットアップ

V2 Desktop | Leap Motion Developers で、
現在の最新版である [Leap Motion SDK v2.3.1.31549] (ZIP) をダウンロードします。
ダウンロードするには、アカウントの登録が必要です。
この ZIP ファイルを任意の場所に展開します。
中にドライバーのインストーラーが含まれているので、まずそれを実行します。

Leap Motion SDK を .NET Framework 4.0 以降のアプリケーションで利用するには、

  • LeapSDK\lib\LeapCSharp.NET4.0.dll (.NET アセンブリ)
  • LeapSDK\lib\x86\Leap.dll (ネイティブ アセンブリ)
  • LeapSDK\lib\x86\LeapCSharp.dll (ネイティブ アセンブリ)

が必要になります。

したがって、Visual Studio における手順は以下のようになります。

  1. プロジェクトの参照に LeapCSharp.NET4.0.dll を追加する。
  2. プロジェクトのプロパティを開いて、
    [ビルド イベント] – [ビルド後イベントのコマンド ライン] に次のようなコマンドを設定する。
    (DLL のパスを指定します。環境によって変わるので注意してください。)

copy "$(ProjectDir)..\..\LeapSDK\lib\x86\Leap.dll" "$(TargetDir)"
copy "$(ProjectDir)..\..\LeapSDK\lib\x86\LeapCSharp.dll" "$(TargetDir)"

ビルド イベント

ビルドしたときに、この 3 つの DLL が bin にコピーされていれば OK です。

出力ディレクトリ

 

(追記) また、上記のような設定を自動で実施するための NuGet パッケージを作成しました。

 

バージョン情報
Leap Motion SDK 2.3.1
Visual Studio 2015

参照
Setup Your Leap Motion Controller
V2 Desktop | Leap Motion Developers

カテゴリー: 周辺機器. タグ: , . 1 Comment »

Kinect アプリで画面のフリーズを防ぐ

Kinect を利用したアプリを普通に実装してみると、
アプリの起動に時間がかかったり、途中でフリーズしたりすることがあると思います。
(Kinect SDK にあるサンプルでも発生します。)
今回は、その原因と回避方法について記述していきたいと思います。

ではまず、WPF アプリケーションを新しく作成し、Microsoft.Kinect.dll を参照に追加して、
MainWindow を次のように実装してみます。
おそらく、よく見られる実装だと思います。

MainWindow.xaml


<Window x:Class="KinectAsyncWpf.MainWindow"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       Title="MainWindow" Height="400" Width="600">
    <Grid>
        <TextBlock x:Name="PositionText" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="36"/>
    </Grid>
</Window>

MainWindow.xaml.cs


public partial class MainWindow : Window
{
    KinectSensor sensor; 

    public MainWindow()
    {
        InitializeComponent();

        Loaded += MainWindow_Loaded;
        Closed += MainWindow_Closed;
    }

    void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
        Thread.Sleep(2000); // 意図的な負荷。

        if (KinectSensor.KinectSensors.Count == 0) return;

        sensor = KinectSensor.KinectSensors[0];
        sensor.SkeletonStream.Enable();
        sensor.Start(); 

        sensor.SkeletonFrameReady += sensor_SkeletonFrameReady;
    }

    void MainWindow_Closed(object sender, EventArgs e)
    {
        if (sensor != null)
        {
            sensor.Stop();
        }
    }

    void sensor_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
    {
        Thread.Sleep(15); // 意図的な負荷。

        using (var frame = e.OpenSkeletonFrame())
        {
            if (frame == null)
            {
                ShowPosition("");
                return;
            }

            var skeletons = new Skeleton[frame.SkeletonArrayLength];
            frame.CopySkeletonDataTo(skeletons);

            var skeleton = skeletons.FirstOrDefault(s => s.TrackingState == SkeletonTrackingState.Tracked);
            if (skeleton == null)
            {
                ShowPosition("");
                return;
            }

            var p = skeleton.Position;
            ShowPosition(string.Format("({0:N3}, {1:N3}, {2:N3})", p.X, p.Y, p.Z));
        }
    }

    void ShowPosition(string text)
    {
        PositionText.Text = text;
    }
}


Kinect で人物をトラッキングして、その中心の座標を表示するだけのアプリです。
上記のコードでは、検証のために意図的に処理に時間がかかるようにしています。

このように実装して実行すると、次のような現象が見られると思います。

(1) アプリを起動した直後、ウィンドウは表示されるがしばらくフリーズする。
(2) 一見問題なく動作しているが、ウィンドウをマウスでドラッグすると不連続に動く (またはフリーズする)。

どちらも、UI スレッドに大きな負担をかけていることが原因です。
したがって、UI のパフォーマンスを下げる要因をなるべくバックグラウンド スレッドに移すことが望ましいです。
それぞれの詳細は次の通りです。

 

(1) Kinect の初期化処理

Kinect の初期化処理は、その内容によってはかなり時間がかかることがあります。
上記のコードでは Loaded イベントで実行しており、この場合、ウィンドウが表示された直後にフリーズします。
なお、MainWindow のコンストラクター内で実行する場合は、ウィンドウが表示されるまでに時間がかかってしまいます。

したがって、Kinect の初期化処理を表す

sensor.SkeletonStream.Enable();
sensor.Start();

の部分をバックグラウンドで実行するとよいでしょう。

(2) 各フレームのデータに対する処理

上記のコードでは、各フレーム発生時のコールバックである sensor_SkeletonFrameReady メソッドが
UI スレッドで実行されています。
したがって、ジェスチャを判定したり深度を解析したりするなど、処理に時間がかかってしまうと画面がフリーズします。

実は Kinect SDK では、SkeletonFrameReady などのイベントハンドラーを登録するときに
内部的に SynchronizationContext.Current を取得して保持しており、
イベントハンドラーを実行するときにこの同期コンテキストを使おうとします。

つまり、

sensor.SkeletonFrameReady += sensor_SkeletonFrameReady;

を UI スレッドで実行すれば sensor_SkeletonFrameReady メソッドは UI スレッドで実行され、
バックグラウンドで実行すればバックグラウンド (登録時とは別のスレッド。どのフレームでも同じスレッド ID) で実行されます。

 

以上を踏まえ、コードを次のように修正します。


public MainWindow()
{
    InitializeComponent();

    Loaded += (o, e) => Task.Run(() => MainWindow_Loaded(o, e));
    Closed += MainWindow_Closed;
}


void ShowPosition(string text)
{
    Dispatcher.InvokeAsync(() => PositionText.Text = text);
}

MainWindow_Loaded メソッド全体をバックグラウンドで実行させます。
これにより sensor_SkeletonFrameReady メソッドはバックグラウンドで呼び出されるようになるため、
UI 要素を操作するには、Dispatcher.InvokeAsync メソッドを呼び出して UI スレッドに戻して実行させます。
(Dispatcher.Invoke メソッドを使った場合、アプリ終了時に TaskCanceledException が発生したり、
sensor.Stop メソッドを呼び出すとデッドロックが発生したりします。)

以上で、UI スレッドへの負荷を軽減し、UI がフリーズしないアプリにすることができました。
(ちなみにこの場合、sensor_SkeletonFrameReady メソッドの処理にやたら時間がかかっても、
単にフレームレートが下がるだけでアプリは続行できます。)

ただし、今回は TextBlock の Text プロパティの値をコードから直接変更しましたが、
UI 要素への値の反映については、以前にデータ バインディングと非同期処理 (その 1) で書いた通り、
データ バインディングを使うほうがよいでしょう。

ちなみに Leap Motion の場合は、初期化でフリーズすることはなく、
各フレーム発生時のコールバックはつねにバックグラウンド スレッドで実行されます。

 

作成したサンプル
KinectAsyncWpf (GitHub)
KinectAsyncWpf2 (データ バインディングを利用) (GitHub)

バージョン情報
Kinect for Windows SDK 1.8

参照
Kinect for Windows SDK のセットアップ
データ バインディングと非同期処理 (その 1)

Leap Motion のセットアップ

Leap Motion Controller のバージョン 1 系を .NET で利用するためのセットアップの方法について記述します。
(なお、v1 系の最終版は v1.2 になると思われます。
v2 系については、改訂版として Leap Motion v2 のセットアップを書きました。)

Leap Motion のサイトから、Software および Developer SDK をダウンロードできます。
開発環境ではこれらの両方が必要ですが、非開発環境では Software (ドライバー) のみをインストールします。

■ Software (ドライバー)

公式には Leap Motion Software と呼ぶようですが、要するにドライバーです。
Developer SDK + Documentation にアクセスして、[v.1.2.2 for Windows] をクリックします。
ダウンロードするには、アカウントの登録が必要です。
このインストーラーを実行して、Software をインストールします。

なお、Setup Your Leap Motion Controller でダウンロードできる Software は、現在ではバージョン 2 系になっています。

■ Developer SDK

Developer SDK + Documentation にアクセスして、[v.1.2.0.10970 for Windows] をクリックします。
ダウンロードするには、アカウントの登録が必要です。
ファイル名は LeapDeveloperKit_release_win_1.2.0+10970.zip で、これを任意の場所に展開するだけです。

Developer SDK を .NET Framework 4.0 以降のアプリケーションで利用するには、

  • LeapDeveloperKit\LeapSDK\lib\LeapCSharp.NET4.0.dll (.NET アセンブリ)
  • LeapDeveloperKit\LeapSDK\lib\x86\Leap.dll (ネイティブ アセンブリ)
  • LeapDeveloperKit\LeapSDK\lib\x86\LeapCSharp.dll (ネイティブ アセンブリ)

が必要になります。

したがって、Visual Studio における手順は以下のようになります。

  1. LeapCSharp.NET4.0.dll をプロジェクトの参照に追加する。
  2. プロジェクトを右クリックして [追加] – [既存の項目] を選択し、
    Leap.dll および LeapCSharp.dll をリンクとして追加する。
  3. Leap.dll および LeapCSharp.dll のプロパティで、
    [出力ディレクトリにコピー] を [新しい場合はコピーする] に設定する。

既存項目の追加

出力ディレクトリにコピー

ビルドしたときに、この 3 つの DLL がコピーされていれば OK です。

出力ディレクトリ

 

(追記) 上記のような設定を自動で実施するための NuGet パッケージを作成しました。

(追記) Leap Motion v1 が自動でアップグレードされないようにするというのを書きました。
v1 を使い続けるにはこの設定が必要です。

 

バージョン情報
Leap Motion Software 1.2.2
Leap Motion Developer SDK 1.2.0
Visual Studio 2013

参照
Setup Your Leap Motion Controller
Leap Motion Developers
V1 Developer SDK + Documentation

カテゴリー: 周辺機器. タグ: , . 2 Comments »

Leap Motion で日本語の文字入力・文字認識

Leap Motion を利用して、空中で指やペンで日本語の文字を入力し、同時に手書き文字認識をするプロトタイプを作成しました。
一見、書道アプリですが。

その様子を撮影した動画を投稿しました。
まずはこちらをご覧ください:
Japanese Calligraphy and Handwriting Recognition in the Air

 

以下では、上記の動画について補足していきます。

書道で「鎧武」を書く元ネタはこちら:
【仮面ライダー鎧武】幼稚園児「書き初めで『ガイム』書きたい」書道家「?」の後日談がとっても素敵

鎧武

 

ほとんどの文字を行書で書いていますが、問題なく文字認識されています。
実際には、楷書のほうが認識率は高いと思います。

京都

一部の文字は草書も認識されます。

日本

 

犯人はヤス。
ひらがなとカタカナの例です。

犯人はヤス

 

タイムアタック。

  • 京王八王子: 3"31
  • 四八(仮): 3"44
  • 雪風: 1"93
  • 漣: 1"72
  • 纐纈: 5"75

京王八王子

 

Leap Motion では、指のほかに、ペンなどの棒状のものも使えます。
「龍驤」を書くときには、割り箸を使っています。

龍驤

龍驤

 

三次元空間上で文字を書くには、ユーザー側にも多少の練習が必要になります。
コツは、本当に紙の上で書いていると脳に錯覚させて、普段紙の上で書いているときの動作をすることです。

参照
Japanese Calligraphy and Handwriting Recognition in the Air (Vimeo)
Japanese Calligraphy and Handwriting Recognition in the Air (Youtube)
Text recognition in the air, for Yukikaze and Sazanami.

【仮面ライダー鎧武】幼稚園児「書き初めで『ガイム』書きたい」書道家「?」の後日談がとっても素敵
Vision-Based Handwriting Recognition for Unrestricted Text Input in Mid-Air (PDF)
Ring : Shortcut Everything. by Logbar inc. — Kickstarter
Leap Motion で「つまむ」操作

Leap Motion で「つまむ」操作

昨年末に、Leap Motion Controller を使用して
3D ジェスチャにより画像などの 2D データの集合をブラウズする方法を示すコンセプト動画を投稿しました。

3D Touch and Pinch Gestures

 

空中でスクリーンに平行な平面に触れる操作と、2 本の指で物をつまむ操作を実装しています。
公式 SDK に存在するジェスチャは利用しておらず、判定ロジックを自作しています。
とくに、「つまむ」ジェスチャは公式 SDK にも存在すらしてしないため、
これを実装した動画は現時点で希少です (しかもあるのはなぜか 5 本指のものばかり)。

GUI 部分は WPF (XAML + C#) で実装しており、
独特のヌルヌル感を出すために細やかなチューニングを施しています。
結果的に Windows 8 / Windows Phone の挙動に近くなりました。

なお、この動画は、元日の Leap Motion Developer ML の中で「Highlights & Innovations」の 1 つとして紹介されました。
(YouTube と Vimeo に同じものを投稿しましたが、Vimeo のほうが紹介されました。)
ML の配信は週 1 回なので、たまたま元日に当たったのは運が良かったです。

参照
3D Touch and Pinch Gestures (Vimeo)
3D Touch and Pinch Gestures (YouTube)