yoppa.org


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

[code lang=”cpp”]
#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; //ライト
};
[/code]

testApp.cpp

[code lang=”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();
}
[/code]

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

screenshot_648

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

testApp.h

[code lang=”cpp”]
#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;
};
[/code]

testApp.cpp

include “testApp.h”

[code lang=”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() ){
//指の位置をクリア
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();
}
[/code]

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

screenshot_649

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

07.25: コードを若干修正