yoppa.org


immediate bitwave

Blog

openFrameworksで、Leap Motionを使ってみた!

待ちに待ったLeap Motionがようやく届いたので、ちょびっとだけ触ってみた。

インストールとセットアップはとにかく簡単。Leap Motionのセットアップページに行って、一式ダウンロードとインストールするだけで、すぐに動作する。デモアプリの完成度もなかなかのもの。ユーザーにストレスを感じさせない環境構築までのナビゲーションのスムーズさに唸らされる。

screenshot_647

ひと通り遊んだところで、openFrameworksからLeap Motionを使ってみることに。そのものズバリなofxLeapMotionというアドオンが開発されているので、それをそのまま利用できる。ただし、いくつかバージョンがありいくつか試した中で下記のリポジトリのバージョンが問題なくビルドできて、Leap Motionからのメッセージも受信できた。

まずは、Hello World的なサンプルとして、手を認識して表示してみる。

ofxLeapMotionでは2通りの方法が用意されている。1つ目は、ofxLeapMotion内で定義されているofxLeapMotionSimpleHandというシンプルな手のモデルを利用する方法。2つ目は、LeapMotionの純正のC++ SDKで用意されている機能にアクセスして表示する方法。

まずは、シンプルなofxLeapMotionSimpleHandを利用する方法で描画してみる。やり方はとても簡単で、ofxLeapMotionSimpleHandを認識したら、そのインスタンスに対してdebugDraw()というメソッドを呼びだせば簡単な手の3Dモデルを表示してくれる。

こんな感じ。

testApp.h

#pragma once

#include "ofMain.h"
#include "ofxLeapMotion.h"

class testApp : public ofBaseApp{

  public:
    void setup();
    void update();
    void draw();

    void keyPressed  (int key);
    void keyReleased(int key);
    void mouseMoved(int x, int y );
    void mouseDragged(int x, int y, int button);
    void mousePressed(int x, int y, int button);
    void mouseReleased(int x, int y, int button);
    void windowResized(int w, int h);
    void dragEvent(ofDragInfo dragInfo);
    void gotMessage(ofMessage msg);
    void exit();

    ofxLeapMotion leap; // Leap Motionのメインクラスをインスタンス化
    vector <ofxLeapMotionSimpleHand> simpleHands; // シンプルな手のモデルのvector配列
    ofEasyCam cam; //カメラ
    ofLight light; //ライト
};

testApp.cpp

#include "testApp.h"

void testApp::setup(){
    // 画面設定
    ofSetFrameRate(60);
    ofSetVerticalSync(true);
    ofBackground(31);
    // 照明とカメラ
    ofEnableLighting();
    light.setPosition(200, 300, 50);
    light.enable();
    cam.setOrientation(ofPoint(-20, 0, 0));
    // GL設定
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_NORMALIZE);
    // Leap Motion開始
    leap.open();
}

void testApp::update(){
    // 検出された手の数だけ、ofxLeapMotionSimpleHandのvector配列に追加
    simpleHands = leap.getSimpleHands();

    // フレーム更新して、手が検出されたら
    if( leap.isFrameNew() && simpleHands.size() ){
        // 画面の大きさにあわせて、スケールをマッピング
        leap.setMappingX(-230, 230, -ofGetWidth()/2, ofGetWidth()/2);
        leap.setMappingY(90, 490, -ofGetHeight()/2, ofGetHeight()/2);
        leap.setMappingZ(-150, 150, -200, 200);
    }

    // ofxLeapMotionに現在のフレームは古くなったことを通知
    leap.markFrameAsOld();
}

void testApp::draw(){
    // 検出された数だけ、手を描画
    cam.begin();
    for(int i = 0; i < simpleHands.size(); i++){
        simpleHands[i].debugDraw();
    }
    cam.end();
}

実行結果はこんな感じ。シンプルだけど、手の平と各指先、そして指先の動きのベクトルが表示されている。

screenshot_648

もちろん、ofxLeapMotionSimpleHandを利用して、指先や手の平などそれぞれのパーツの座標を個別にとり出すことも簡単。

testApp.h

#pragma once

#include "ofMain.h"
#include "ofxLeapMotion.h"

class testApp : public ofBaseApp{

  public:
    void setup();
    void update();
    void draw();

    void keyPressed  (int key);
    void keyReleased(int key);
    void mouseMoved(int x, int y );
    void mouseDragged(int x, int y, int button);
    void mousePressed(int x, int y, int button);
    void mouseReleased(int x, int y, int button);
    void windowResized(int w, int h);
    void dragEvent(ofDragInfo dragInfo);
    void gotMessage(ofMessage msg);
    void exit();

    ofxLeapMotion leap; // Leap Motionのメインクラスをインスタンス化
    vector <ofxLeapMotionSimpleHand> simpleHands; // シンプルな手のモデルのvector配列
    ofEasyCam cam; //カメラ
    ofLight light; //ライト
    vector <ofVec3f> fingerPos;
};

testApp.cpp

include “testApp.h”

#include "testApp.h"

void testApp::setup(){
  // 画面設定
  ofSetFrameRate(60);
  ofSetVerticalSync(true);
  ofBackground(31);
  // 照明とカメラ
  ofEnableLighting();
  light.setPosition(200, 300, 50);
  light.enable();
  cam.setOrientation(ofPoint(-20, 0, 0));
  // GL設定
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);
  // Leap Motion開始
  leap.open();
}

void testApp::update(){
  // 検出された手の数だけ、ofxLeapMotionSimpleHandのvector配列に追加
  simpleHands = leap.getSimpleHands();
  
  // フレーム更新して、手が検出されたら
  if( leap.isFrameNew() && simpleHands.size() ){
    //指の位置をクリア
    fingerPos.clear();
    
    // 画面の大きさにあわせて、スケールをマッピング
    leap.setMappingX(-230, 230, -ofGetWidth()/2, ofGetWidth()/2);
    leap.setMappingY(90, 490, -ofGetHeight()/2, ofGetHeight()/2);
    leap.setMappingZ(-150, 150, -200, 200);
    
    // 検出された手の数だけくりかえし
    for(int i = 0; i < simpleHands.size(); i++){
      // 検出された指の数だけくりかえし
      for(int j = 0; j < simpleHands[i].fingers.size(); j++){
        // 位置をvectorに保存
        ofVec3f pos = simpleHands[i].fingers[j].pos;
        fingerPos.push_back(pos);
      }
    }
  }
  
  // ofxLeapMotionに現在のフレームは古くなったことを通知
  leap.markFrameAsOld();
}

void testApp::draw(){
  cam.begin();
  // 検出された指の数だけくりかえし
  for(int i = 0; i < fingerPos.size(); i++){
    // 検出された位置に立方体を描画
    ofBoxPrimitive box;
    box.setPosition(fingerPos[i].x, fingerPos[i].y, fingerPos[i].z);
    box.set(20);
    box.draw();
  }
  cam.end();
}

指先だけ独立して検出できた! 簡単!

screenshot_649

ジェスチャーの検知や、Leap Motionから提供されている独自のSDKを呼び出して使用するやり方は、また今度。とりあえず、Leap Motion楽しい! ということで…

07.25: コードを若干修正