Help us understand the problem. What is going on with this article?

LeapMotionによる仮想マウス

More than 1 year has passed since last update.

格安でLeapMotionが手元に届いたので、何か作ってみようと思い、仮想マウスを作りました。

LeapMotionの上で指を動かすとポインタが動き、クリックもできるようにしました。また、Macにおける画面遷移もできるようにしました。画面遷移ができるとカッコイイよね!

ソースコードの在り処

コードはgithubにあります。コード量は少なめです。 
https://github.com/slowsingle/leapmotion_controller/tree/master

ReadMeにインストール方法が記載されていますので、お使いになる場合は是非ごらんください。

プログラム

リープモーションから取得した人差し指の座標(X, Y, Z)から、PCのディスプレイ上の座標系に変換して、その座標にポインタを移動させます。

01.gif

座標系の変換
new_x = (x + 120.0) / 240.0 * 1440.0;
if (new_x < 0.0) {
    new_x = 0.0;
} else if (new_x > 1440.0 - 1.0) {
    new_x = 1440.0 - 1.0;
}
new_y = (250.0 - y) / 150.0 * 900.0;
if (new_y < 0.0) {
    new_y = 0.0;
} else if (new_y > 900.0 - 1.0) {
    new_y = 900.0 - 1.0;
}

touchDistance()を用いることでタッチの奥行きを測ることができます。

03.gif

一定のしきい値(以下のコードの場合は-0.1)を下回ると、押されたと判定し、そこから先ほどとは異なる一定のしきい値(以下のコードの場合は0.0)を上回ると離されたと判定し、タッチされたと判定します。

タッチ認識
// タッチの認識
if (isPressed) {
    if (pointable.touchDistance() > 0.0) {
        isPressed = false;
        PyObject_CallMethod(pModule, "touch", "(dd)", touch_x, touch_y);
        std::cout << "===== PRESS_OK =====" << std::endl;
    }
} else {
    if (pointable.touchDistance() < -0.1) {
        isPressed = true;
        touch_x = new_x;
        touch_y = new_y;
        std::cout << "***** PRESS_Prepare *****" << std::endl;
    }
}

スワイプのジェスチャー認識は以下の通りです。

スワイプのジェスチャー認識
Leap::GestureList gestures = frame.gestures();

// スワイプのジェスチャーを認識する
if (swipe_counter == 0) {
    for (int g = 0; g < gestures.count(); g++) {
        gesture = gestures[g];

        if (gesture.type() == Leap::Gesture::TYPE_SWIPE) {
            Leap::SwipeGesture swipe = gesture;
            if (swipe.direction().x < -0.7) {
                std::cout << swipe.direction().x << std::endl;
                PyObject_CallMethod(pModule, "swipe_screen", "(i)", 0);
                // スワイプを認識したら関数を抜ける
                isPressed = false;
                swipe_counter = 100;
                return;
            } else if (swipe.direction().x > 0.7) {
                std::cout << swipe.direction().x << std::endl;
                PyObject_CallMethod(pModule, "swipe_screen", "(i)", 1);
                // スワイプを認識したら関数を抜ける
                isPressed = false;
                swipe_counter = 100;
                return;
            }
        }
    }
}

リープモーションによる認識はC++で実装し、PCに対してポインタを移動させたりスワイプさせたりするのはPythonで行わせています。未確認ですが、これでOSに非依存な仮想マウスができたかと思います。

C++からPythonを呼び出すのにはPyObject_CallMethod()を使用しています。
この関数を呼ぶ前に初期化が必要になります。おまじない的なPy_Initialize()を呼び出し、その後(必要があれば)パスを通し、モジュールのインポートを行います。

C++からPythonを呼び出すための初期化処理
bool SampleListener::initializeForPython() {
    Py_Initialize();
    // カレントディレクトリのパスを通す
    PyObject *sys = PyImport_ImportModule("sys");
    PyObject *path = PyObject_GetAttrString(sys, "path");
    PyList_Append(path, PyString_FromString("."));

    // カレントディレクトリにあるpythonモジュールをインポートする
    pModule = PyImport_ImportModule("script");

    if (pModule != NULL) {
        return true;
    } else {
        return false;
    }
}

なお、PyObject_CallMethod()の引数は、1つ目がインポートしたモジュールのポインタ、2つ目が呼び出す関数名、3つ目がこれから呼び出すpython内の関数における引数の数と型((i)ならint型の引数が1つで、(dd)ならdouble型の引数が2つ)を表し、4つ目がその引数の具体的な値となります。

PyObject_CallMethod(pModule, "swipe_screen", "(i)", 1)ならば、pModule(インポートしたモジュール)のswipe_screen関数に、引数としてint型の引数1を渡して、関数を実行することになります。

終わりに

やる前から何となく覚悟してたけどタッチしづらいです。  
ただ、画面遷移が手の動きでできるとカッコイイのは確かです。未来感を感じます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away