LoginSignup
10
12

More than 3 years have passed since last update.

Python3でLeap Motion

Last updated at Posted at 2020-01-22

記事の目的

Leap Motionというモーショントラッカーがあります。
これのPython用APIを使って、親指と人差し指の距離をリアルタイムに取得することを試みました。
PythonでLeap Motionを使う方法を紹介した記事は多くありますが、私の環境ではなかなかスムーズにいきませんでした。
ので、自分用メモとして方法を残します。

更新履歴

2020年11月16日:
SDKのV2をDLするためのリンクが切れていたので、現在のリンクを貼りました。

環境

  • Windows 10 64bit
  • Python 3.7.5

まずPython 2.xで

Leap MotionのPython APIは、Python 2.xにしか対応していません。
Python3系列で動かすのはあとにして、まずはPython 2.7で動かしてみます。
Anacondaを使って、Python2.7環境を作ります。

Leap Motion SDKの準備

次に、Leap Motion Developerのサイトからデスクトップ用のSDKをダウンロードします。
V2とV4の選択肢がありますが、V2を選びます。

(2020年11月16日追記)リンクが切れていました。
現在のところ、SDKのV2はこちらからダウンロードできるようです。
Windows版の2.3.1をDLしてください。

DLしたzipを解凍すると、中にインストーラがあるので実行しましょう。(←Visualizerいらないなら不要?)
その後、
C:\Program Files\Leap Motion Core Services\Visualizer.exe
を実行すると、Leap Motionの動作確認ができるのでやってみましょう。

ss1.png

Visualizerに何も表示されないようでしたら、この記事を参考にdpinst64.exeを実行してドライバをインストールしてください。

インストーラと一緒に、LeapSDKというフォルダがあります。
さらにその中のlib/Leap.pyをimportすることで、PythonからLeap Motionを扱えるようです。
しかし、例えばLeap.pyと同じディレクトリへ移動してimportしても、Import Error: No module named LeapPythonとなってしまいます。
こちらの記事を参考に、Leap.pyと
LeapSDK/lib/x64の中身と、__init__.py(空のファイル)をひとつのフォルダ(ここでは、leapmotionという名前にします)内にコピーします。
leapmotionがあるディレクトリに移動して、Pythonからfrom leapmotion import Leapとすると、Leap MotionのAPIが使用できるようになります。

Leap Motion APIの使用

このあたりの記事公式のドキュメントdir()を駆使し、親指と人差し指の距離を出力します。

下記のようにすると、その瞬間における手の情報をframeとして取得できるようです。

controller = Leap.Controller()
frame = controller.frame()

ちなみに、controller.frame(1)とやると、1フレーム前の情報が得られるようです。

frameのうち指の情報は、frame.fingersに収められています。
各指の情報は、以下のように取り出すようです。

frame.fingers[0]    # <- Thumb(親指
frame.fingers[1]    # <- Index(人差し指
frame.fingers[2]    # <- Middle(中指
frame.fingers[3]    # <- Ring(薬指
frame.fingers[4]    # <- Pinky(小指

親指と人差し指の指先の距離を出力するためには、下記のようにします。

pos_thumb = frame.fingers[0].tip_position
pos_index = frame.fingers[1].tip_position
print(pos_thumb.distance_to(pos_index))

まとめると、こんな感じです。

from time import sleep

from packages.leapmotion import Leap

controller = Leap.Controller()

THUMB = 0
INDEX = 1
MIDDLE = 2
RING = 3
PINKY = 4

while not controller.is_connected:
    print('Connecting...')
    sleep(.5)
    pass
print('...Connected!')

while True:
    sleep(.01)
    frame = controller.frame()

    pos_thumb = frame.fingers[THUMB].tip_position
    pos_index = frame.fingers[INDEX].tip_position

    print(pos_thumb.distance_to(pos_index))

Python3で動かす

こちらの記事をもとにやっていきます。
記事の設定と違うのは、64bitのWindowsを使っていること、PythonのVer.が3.7であることです。

Swig

Swigを使って、Python用のプログラムを生成してもらいます。

インストール

このサイトを参考に、WindowsにSwigをインストールします。
記事執筆時点での最新版は4.0.1でしたが、4.0.0以降だとエラーを招くようです(参考)。
3.0.12でもエラーは(恐らく)出ませんが、記事の通り2.0.9を使います。
swig.exeまでのパスを環境変数PATHに追加するところまでやりましょう。

スクリプトの手直し

適当なフォルダを作って下記ファイルをコピーします。
- LeapSDK/include/Leap.h
- LeapSDK/include/LeapMath.h
- LeapSDK/include/Leap.i
- LeapSDK/lib/x64/Leap.lib

このフォルダでSwigを実行すればいいのですが、Leap.iがイマイチちゃんとしていないようでエラーになります。
こちらの記事を参考に、手動で直します。
Leap.iをテキストエディタで開いてください。
%pythoncode {% }}で囲われている部分がPython用のコードなのですが、インデント(字下げ)に間違いがあります。
defの前など、インデント不要なところはインデントなし、そのほかのインデントは空白4つになるように直しましょう。
一応、手直ししたLeap.iを置いておきます。

コマンドプロンプトにて、そのフォルダの場所へcdし、下記コマンド。

swig -c++ -python -o LeapPython.cpp -interface LeapPython Leap.i

エラーメッセージがでたら、それをもとにLeap.iのインデントを再度見直しましょう。
成功すれば、Leap.py、LeapPython.cpp、LeapPython.hが同じフォルダ内に作成されます。

Visual Studio

Visual Studioを使い、先ほど生成されたLeapPython.cppを、Pythonから動かせるような形でコンパイルします。

インストール

Python3.7の場合、最新の2019版でなく2017版を用意する必要がある(参照)とのことなので、そちらをDLします。
https://docs.microsoft.com/ja-jp/visualstudio/releasenotes/vs2017-relnotes
ss2.png
Download Enterprise 2017を選んで、インストーラをDL&起動。
ss4.png
どうしてよいかイマイチわからなかったので、ワークロードタブからC++によるデスクトップ開発にチェックを入れてインストール。

空のプロジェクト作成

メニューバーから [ファイル]→[新規作成]→[プロジェクト]。
左のメニューから[Visual C++]→[空のプロジェクト]を選択。
名前と場所を適当に決めて [OK]。
ss9.png
プロジェクトのフォルダに、先ほどSwigを動かしたフォルダの中身をすべて(LeapPython.cppだけでもよい?)コピーしてください。
.filtersなんかがあるファイルと同じディレクトリです。

いろいろ設定

[表示]→[ソリューションエクスプローラー]。
ソリューションエクスプローラーのプロジェクト名を右クリックして[追加]→[既存の項目]。
先ほどSwig済のフォルダからコピーしたファイルをすべて[追加]します。

次は、再度プロジェクト名を右クリックして [プロパティ]。
[プロパティ]が見当たらない場合は、下のスクショのように、上部のアイコンを使ってフォルダビューからソリューションビューに変更。
ss5.png
構成マネージャーをクリックし、校正をRelease、プラットフォームをx64に変えます。
[全般]メニューを選び、[ターゲット名]をLeapPython、[構成の種類]をダイナミックライブラリ(.dll)に設定。
ss6.png
続いて、[C/C++]→[全般]メニューを開き、追加のインクルードディレクトリに、Pythonのincludeフォルダを指定します。
例えば私のAnaconda(Miniconda)環境ですと、
C:\Users\(ユーザー名)\Miniconda3\envs\(環境名)\include
といった感じです。
ss7.png
さらに[リンカー]→[入力]メニューへ飛び、追加の依存ファイルのところに Leap.libと、python37.libへのフルパスを追記します。
python37.libは下記の場所などにあるはずです。
C:\Users\(ユーザー名)\Miniconda3\envs\(環境名)\libs\python37.lib
ss8.png
設定完了です。
プロパティを閉じましょう。

ビルド

コンパイルを実行します。
プロジェクト名を右クリック→[ビルド]
エラーメッセージがどっと出てきたら、python33.libとLeap.libがちゃんと64bit用のものになっているか確認してください。
ビルドが終了すると、表示されているディレクトリにLeadPython.dllが作られています。
これの名前を変更して、拡張子を.pydにしてください。
一応、生成されたLeadPython.pydを置いておきます。

Python3.7で実行

Python2.7で動かした、LeapSDKの中身をあれこれ突っ込んで__init__.pyを作ったフォルダを開いてください。
このうち、Leap.pyとLeapPython.pydを、SwigやVisual Studioで生成されたものに置き換えます。

最後にまた、Leap.pyを手動で直す必要があります。
テキストエディタで開きましょう。
あちこちに、余計な%が紛れていますので、消してください。
半角スペース2個+%を置換して消してやると速いです。
手直ししたLeap.pyがこちらです。

これで、Python2.7でやったときと同様にLeap MotionのデータをPython3.7で取得できます。

PsychoPyと組み合わせる(おまけ)

こんなスクリプトを書いて↓

leapmotion.py
from time import sleep

from .leapsdk import Leap


class LeapMotion:
    def __init__(self):
        self.controller = Leap.Controller()
        self.fingers = {'thumb': 0,
                        'index': 1,
                        'middle': 2,
                        'ring': 3,
                        'pinky': 4}

        while not self.controller.is_connected:
            sleep(.5)

    def calc_dist(self, finger_from: str, finger_to: str):
        frame = self.controller.frame()
        pos_from = frame.fingers[self.fingers[finger_from]].tip_position
        pos_to = frame.fingers[self.fingers[finger_to]].tip_position
        return pos_from.distance_to(pos_to)

こんな感じで動かして↓

from time import sleep

from packages.device.leapmotion import LeapMotion

from psychopy import visual

leapmotion = LeapMotion()
window = visual.Window(
    colorSpace='rgb255',
    fullscr=False,
    size=(900, 900),
    allowGUI=True,
    wintype='pygame',
    units='pix')
circle = visual.Circle(window, size=1, autoDraw=True)

while True:
    circle.size = leapmotion.calc_dist('thumb', 'index')
    window.flip()
    sleep(.01)
    print(leapmotion.calc_dist('thumb', 'index'))

こんな風になりました!↓
ezgif-7-145ce88082b1.gif

Visual Studioの代わりにMinGWで(失敗)

MinGWでインストールしたg++を使ってコンパイルしてみようとしたのですが、うまくいきませんでした。
詰むまで記録を残しておきます。

インストール

こちらの記事をもとにMinGW-w64をインストールします。
PATHに追加するところまでやったらOK。
ちなみに私の場合は下記を追加しました。
C:\Program Files\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin

そして、コマンドプロンプトでSwig済フォルダへcdし、

g++ -I C:\Users\issakuss\Miniconda3\envs\study09t\include LeapPython.cpp Leap.lib C:\Users\issakuss\Miniconda3\envs\study09t\libs\python37.lib -shared -o LeapPython.pyd 

これで、Visual Studioでやったのと同じことができると思ったのですが、エラーがたんまり出てしまい詰みました。
ss10.png
こっちでできたらVisual Studioインストールしなくて済むので楽だったんですが。

10
12
9

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
12