yoppa.org


immediate bitwave

Blog

openFrameworksで、Leap Motionを使ってみた: その2 – Leap Motion SDKから情報を取得

screenshot_651

前回のエントリーが好評だったので、さらにLeap Motionについて。

前回紹介したように、ofxLeapMotionでは、あらかじめ用意されているofxLeapMotionSimpleHandクラスを使用すると、とても簡単に手の座標などを取得できる。とはいえ、Leap MotionのSDKで用意されているフルの機能を活用できるところまでは充実していないよう。

しかし、ofxLeapMotionでは、Leap Motion SDKの情報を直接取得できる方法も用意されている。これを使用するとより多彩な情報が取得可能。詳しくは、Leap Motionから提供されているDocumentationを参照。

下記のサンプルでは、まずLeapの手(Hand)を取得して、それぞれの指の位置を取得したあと、指全体で包みこむ仮想の球体の情報を取得して表示している。

やってみると、直接SDKを参照する方法でもかなりシンプルに記述できるので、ある程度慣れてきたら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; // 指の位置の配列
  vector <ofVec3f> spherePos; // 手が取り囲む球体の位置の配列
  vector <float> sphereSize;  // 手が取り囲む球体の大きさの配列
};

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);

  // Leap Motion開始
  leap.open();
}

void testApp::update(){
  // Leap Motion SDKで用意されている手(Hand)のクラスを取得してvector配列へ
  vector <Hand> hands = leap.getLeapHands();
  
  // 手が検出されたら
  if( leap.isFrameNew() && hands.size() ){
    // vector配列に記憶した座標をクリア
    fingerPos.clear();
    spherePos.clear();
    sphereSize.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 < hands.size(); i++){
      // 指の位置を取得
      for(int j = 0; j < hands[i].fingers().count(); j++){
        ofVec3f pt;
        const Finger & finger = hands[i].fingers()[j];
        pt = leap.getMappedofPoint( finger.tipPosition() );
        fingerPos.push_back(pt);
      }
      
      // 指がとりかこむ球体を取得
      ofVec3f sp = leap.getMappedofPoint(hands[i].sphereCenter());
      float r = hands[i].sphereRadius();
      spherePos.push_back(sp);
      sphereSize.push_back(r);
    }
  }
  
  // ofxLeapMotionに現在のフレームは古くなったことを通知
  leap.markFrameAsOld();
}

void testApp::draw(){
  cam.begin();
  // 検出された指の数だけくりかえし
  for(int i = 0; i < fingerPos.size(); i++){
    // 検出された位置に球を描画
    ofSpherePrimitive sphere;
    sphere.setPosition(fingerPos[i].x, fingerPos[i].y, fingerPos[i].z);
    sphere.draw();
  }
  
  // 検出された指がとりかこむ球
  for(int i = 0; i < spherePos.size(); i++){
    // 検出された位置に球を描画
    ofSpherePrimitive sphere;
    sphere.setPosition(spherePos[i].x, spherePos[i].y, spherePos[i].z);
    sphere.setRadius(sphereSize[i]*1.5); //ここのスケールは今は目分量…
    sphere.draw();
  }
  cam.end();
}
Shoichi Ishida — 27 July 2013 22:08
ご回答ありがとうございます! 書き換えて対応したいと思います。ありがとうございます!
tado285 — 26 July 2013 16:19
ofSpherePrimitiveは、v.0.8.0の書式でした (現在はNightly build) 。この部分、ofSphere() で書き換えると動きます。
Shoichi Ishida — 26 July 2013 15:14
ofSpherePrimitiveが利用できないのですが、アドバイスいただけませんか?