hagino3000's blog

平成アーカイブス (更新停止)

エンジニアサポート新年会 CROSS 2012でEmotivについてLTをしました

日本ではあまり使っている人を見ない筋電/脳波ヘッドセットのEmotiv EPOC neuroheadsetを使ってみた。デモはNodejsでデータ飛ばしてCanvasに描画した。視線の位置のxyが取れるのでそれを使った方が面白かったかなぁ。

JavaのコードはSDKのサンプルをベースにJSON作っただけ。状態を取る部分のコードは次の通り。

JSONObject currentState = new JSONObject();

Edk.INSTANCE.EE_EmoEngineEventGetEmoState(eEvent, eState);
float timestamp = EmoState.INSTANCE.ES_GetTimeFromStart(eState);

JSONArray actions = new JSONArray();
if (EmoState.INSTANCE.ES_ExpressivIsBlink(eState) == 1) {
    actions.put("Blink");
}
if (EmoState.INSTANCE.ES_ExpressivIsLeftWink(eState) == 1) {
    actions.put("Left Wink");
}
if (EmoState.INSTANCE.ES_ExpressivIsRightWink(eState) == 1) {
    actions.put("Right Wink");
}
if (EmoState.INSTANCE.ES_ExpressivIsLookingLeft(eState) == 1) {
    actions.put("Looking Left");
}
if (EmoState.INSTANCE.ES_ExpressivIsLookingRight(eState) == 1) {
    actions.put("Looking Right");
}
if (EmoState.INSTANCE.ES_ExpressivIsLookingDown(eState) == 1) {
    actions.put("Looking Down");
}
currentState.put("actions", actions);

currentState.put("Excitement ShortTerm", EmoState.INSTANCE.ES_AffectivGetExcitementShortTermScore(eState));
currentState.put("Excitement LongTerm", EmoState.INSTANCE.ES_AffectivGetExcitementLongTermScore(eState));
currentState.put("Engagement Boredom", EmoState.INSTANCE.ES_AffectivGetEngagementBoredomScore(eState));
currentState.put("Frustration", EmoState.INSTANCE.ES_AffectivGetFrustrationScore(eState));
currentState.put("Meditation", EmoState.INSTANCE.ES_AffectivGetMeditationScore(eState));

send("state", currentState.toString());

キネクハトッカーズマニュアルのサポートページを更新しました。

サポートページ作成時点からかなり状況が変ったので、いろいろと修正しました。OpenNIの進化や、WebSocketでバイナリが使える様になった事など。半年も経てば随分と変る物ですね。

OpenNIをopenFrameworksから使う Advanced編

OpenNI Advent Calendar20日目の記事です。

24日目の記事でもopenFrameworksについて書かれているので、内容がかぶらない様にしています。

何故24日目の記事の方が先に公開されているかは気にしないでください。oFについて基本的な事は上記 @mmlemon_twitter さんの記事に書かれているので割愛します。あと、oFはMacユーザーが多いのでMacOSX + Xcode4の環境を前提に書きます。

ofxOpenNIについて

oFのaddonの一つ。OpenNIをoFっぽいインタフェースで扱える様にした物。誰のブランチを使っていいのかわからないけど、gameoverhack氏のブランチが一番forkされているので自分が使う時はそれを使っている。

DepthGenerator, ImageGenerator, UserGenetator, HandGenerator, IRGenerator, GestureGeneratorの機能はカバーしていて、 exampleを見れば大体の使い方は掴めるはず。ofxOpenNIのジェネレータから得られるデータは、既に世界座標から表示座標系に変換されているため、そのまま表示に使う事ができる。

チルトモーターの首ふりも実装されているが、内部でlibusbを使っているためかMacOSでしか動作しない。Windowsでも首ふりしたかったらOpenNIのXnUSBを使う実装に書きかえれば良い。

リポジトリにある物はKinectで使う事が想定されているらしく、Xtion Proではそのまま使えない。SensorKinectの代りにSensorモジュールを自分でビルドして上書きすればいけそう。あとOpenNIのバージョンも古いので注意。今から使う場合は自分がメンテナになる勢いで使っていかないと厳しいだろう。

アドオンを使わない方法

さて、ofxOpenNIを紹介したが、現在自分の作業マシンにはKinectでは無くXtion Pro liveが接続されているのでofxOpenNIは動かない。なのでoFのプロジェクトにOpenNIを普通に追加して使う時に気にする事を書きます。

config.xmlがアプリケーションの内部に配置される様にする

Build Phasesで「Add Build Phase」してOpenNIの設定ファイルをビルドした.appファイルの中にコピーする。しておかないとHoge.app単体を配布して動作させた時にconfig.xmlが見つからない、とエラーになってしまう。

OpenNIの初期化コードは次の通りになる。

xn::EnumerationErrors ctxErrors;
static string configFilePath = ofFilePath::getCurrentWorkingDirectory() + "../Resources/config.xml";
XnStatus rc = openNIContext.InitFromXmlFile(configFilePath.c_str(), &ctxErrors);
if (rc != XN_STATUS_OK) {
  XnChar strError[1024];
  ctxErrors.ToString(strError, 1024);
  throw std::runtime_error(strError);
}
updateメソッドでfpsを落さないようにする

updateメソッドで注意しないといけないのは、WaitAndUpdata系のメソッドを毎回使うと、ofSetFrameRateでフレームレートを指定していてもブロックがかかりfps30程度に落ちてしまう。fpsに影響を与えたく無い場合はジェネレーターのWaitAndUpdateDataを呼ぶ前にIsNewDataAvailableで新しいデータが来ているかチェックする。ofxOpenNIではupdateメソッド内でWaitAndUpdateDataを呼んでいるため、フレームレートが30fpsに落ちてしまう。

コードは次の通り。

// 各種ジェネレータとOpenNIコンテキストはヘッダファイルでメンバとして定義してある。
void testApp::update(){
 
  if (depthGen.IsNewDataAvailable()) {
    // 深度データの更新
    depthGen.WaitAndUpdateData();
   
    xn::DepthMetaData depthMetaData;
    depthGen.GetMetaData(depthMetaData);
   
    XnMapOutputMode mapMode;
    depthGen.GetMapOutputMode(mapMode);
   
    int width = mapMode.nXRes;
    int height = mapMode.nYRes;
    int numPixels = width * height;
   
    float* depthHist = createHist(&depthMetaData, numPixels);
   
    const XnDepthPixel* depthPixels = depthMetaData.Data();
    for (XnUInt i = 0; i < numPixels; i++, ++depthPixels) {
      grayPixels[i] = depthHist[*depthPixels];
    }
   
    grayImage.setFromPixels(grayPixels, width, height);   
  }
 
  if (imageGen.IsNewDataAvailable()) {
    // ビデオカメラ画像の更新
    imageGen.WaitAndUpdateData();
   
    xn::ImageMetaData imageMetaData;
    imageGen.GetMetaData(imageMetaData);
   
    colorImage.setFromPixels((unsigned char*)imageMetaData.RGB24Data(), colorImage.width, colorImage.height);
   
  }
 
  if (audioGen.IsNewDataAvailable()) {
    // オーディオの更新
    audioGen.WaitAndUpdateData();
    ofLog(OF_LOG_NOTICE, "Audio data size:" + ofToString(audioGen.GetDataSize()));
   
    // doSomething
  }
}

void testApp::draw(){
    ofScale(0.8, 0.8);
    // 深度画像の描画
    grayImage.draw(0, 0);
    // ビデオカメラ画像の描画
    colorImage.draw(640, 0);
}

どうしてもupdateメソッド内がごちゃごちゃしてくるので、OpenNIの処理を分離するためのクラスを一つ作るのが良いだろう。Audioジェネレーターはこの記事のために初めて使ってみたが、安定して動作しなかったので特に何も処理は実装しなかった。*1

コード一式はgistにアップしてあります。

openFrameworks + Kinectな作品

Vimeoで検索するといろいろ見つかる。

自分のおきにいりはWebcam Piano 2.0 Teaserという作品 (Kinectは使っていないけど)

まとめ

android対応も進んでおり、openFrameworksも発展も楽しみなプラットフォームです。OpenNIと一緒に使えるようになっておくと良いかもしれません。openFrameworks + Kinectについての解説はキネクハッカーズマニュアルにもページを裂いて書いたので、興味のある方はチェックしてみてください。

書名
キネクトハッカーズマニュアル
著者
@hagino3000 + 小野 憲史
発売日
2011-08-26
価格
2,604 JPY (256ページ)


*1:Windowsでは動作実績があるみたいだが、自分の環境ではすぐにデータが取得できなくなり、Xtion pro liveを抜いて刺し直すというのが必要だった。

OpenNI/NITEのボーントラッキングが劇的に進化していた件

第3回Kinectハッカソン無事に開催できました。レポートっぽい物はShibuya.NIのサイトにアップするとして、OpenNI + Xtion Pro liveで今日試した事など。

ポーズ不要

NITEを1.5.0 unstableにするとユーザー検出からポーズ検出をすっ飛ばしてボーントラッキングが開始できる様になった。以前まで必要だった学習データも不要。適当に動かしてみたらたまたまその場にいた4人をいきなりトラッキングして普通に動いていた。重すぎて描画が遅れるという事も無かった。動画撮ればよかった。

Kinectポーズという単語は最早死語、「OpenNIはポーズを取らないと骨格取れないんですよ」とドヤ顔をする事はもうできませんね。

上半身のみボーントラッキングが動作した

ラッキング開始時にSkeletonCapabilityに渡すXnSkeletonProfileについて。大抵はXN_SKEL_PROFILE_ALLを渡して頭から足までのジョイントを得ると思うが、自分は 机に座る→作業→退席 の動作を正面からトラッキングしたかったので上半身だけで十分。下半身は見えないだろうし。

そこで、上半身のみのジョイントをトラッキングするXN_SKEL_PROFILE_UPPERを使うとこうなった。


頭と手だけもいける

頭の位置を取りたいだけならXN_SKEL_PROFILE_HEAD_HANDSで十分だった。ユーザー検出と同時に頭部の中心座標が取れるので、用途によっては顔認識よりも便利。横顔でも後ろ頭でもいける。始終静止状態の人は検出できないけど。つまり、全身を入れてポーズを取るのが不要になったおかげで、上半身のみや、下半身のみしか見えない状況においてジョイントのトラッキングが可能になった。

正面を向いてるかどうか

OpenCVの物体検出で正面顔の学習データを使ってみた。頭の位置は既にわかっているので、うまくやれば計算量は減らせるはず。cvHaarDetectObjectsに検索領域とか指定できればと思ったけど、そんなオプション無かった。

顔の向き

頭部の深度の平均値を使ってなんとなく傾きを得る方法を@molant3さんに教えてもらった。

Xtion Pro liveは家電量販店でも買えます

中の人曰くそういう事。輸入した時は190ドルだったが日本価格25,000円。
Kinectよりも高いが重くてでかいKinectを毎日持ち歩きたくはないので自分はXtion Pro liveを使っています。

Mac App StoreKinectアプリが増えていた。

3D ScannerというアプリKinectが接続されていない、とかいうエラーが出て動作しない!! 170JPYが無駄に……!!

Kinectプログラミングをより楽しむための、新分野入門の勧め

この記事はOpenNI Advent Calendarの15日目の記事です。

さて、この記事をチェックされる様な方であれば、ある程度はKinectセンサーとそのドライバについて知識はあると思います。さらに、それらを使って何かを作りたいと考えている人も多いでしょう。Kinectはとても魅力的なデバイスです、ある程度のプログラミング経験があればモーションキャプチャセンサーとして使えてしまう環境が整っており、デバイスを使った開発などした事もない人間でも簡単に扱えます。

しかし、実際にアプリケーションを作ってみようとすると、全く未経験の領域に足を突っこむ事に気がつきます。画像処理、音声処理、機械学習、コンピュータインタラクション etc…。それらについて既に習熟していれば問題は無いのですが、私の様な大学で生物を専攻してしまった*1人間には全くもって未知の分野。ここからは、私の経験を元にKinectプログラミングに関係するいくつかの分野に足を踏みいれるのに役に立ちそうな書籍や情報源を紹介します。

画像処理

なにはともあれ最初は画像処理でしょう。Kinect SDKやNITEのボーントラッキング、ユーザー認識は高度な画像処理技術によって実現されています。深度画像を表示したい、加工したい、といった場合。Kinect SDKで深度画像とビデオカメラの像を合せたい、という時に必要になる知識です。


最初の本はこちら。画像データってコンピュータ上でどう表現されているの、という所から教えてくれるのがこの本。簡単なフィルタ(ぼかし、シャープネス、グレースケール化)のロジックの解説からフーリエ変換まで載っています。やさしい入門書。


次の本。上の本よりも多くのフィルタ、変換ロジックが詳細に解説されています。デバイスの話から始まり、画像の性質、フィルタ、変換、動画処理、キャリブレーションパターン認識画像符号化、と一通り学べる感じ。内容盛りだくさんなので、気になった所だけ目を通した。図が多めで読み易い。

他の本は読んでいないのでわかりませんが、CV界隈の偉い人がオススメしていたので良い本なんだろうなと。本と並行してOpenCVを触ってみると、動作イメージが掴めるかと。

音声処理

画像処理よりもさらに経験した事のある人は少ないであろう音声処理について。Kinectといえばボーントラッキングみたいな印象があるけど、Kinect SDKは録音、音声認識、ビームフォーミングといったAudio APIもあります。


OpenNIユーザー = Macユーザー = iOS開発者という偏見を私は持っているので、ここではiPhone Core Audioの本を紹介します。音声のデジタル化の基礎の所(サンプリング周波数、量子化ビット数の意味)から説明があったので助かりました。コードを書いて実際にiPhoneで動かしながらオーディオプログラミングの要領が掴めます。Core AudioはMacOSXでも使えるので、OpenNIのAudio Generatorが実装されたらCore Audioを使ってあれこれする事が増えるのではと予想しています。

表現

openFrameworksやProcessingといったヴィジュアルプログラミングフレームワークの使い方は、プログラミング経験があるのであれば本よりもネットに公開されている動画とコードを読むのがてっとり速いです。最初はパーティクル飛ばしから。


メディアアートっぽい物が作れたけど、そもそも「メディアアート」って何?? みたいな疑問を持ったらこの本。メディアアートの歴史を解説してくれる。デュシャンの泉はこの本で知りました。

コンピュータインタラクション

NUIっぽい物を作りたいという人に。コンピュータインタラクションはどうあるべきか。これからどうなるのか、という内容がざっくりと。Kinect発売よりも後に出た本なのでKinectについても少し言及があります。


人間は世界をどう認識するのか、という所の話。UIデザインやインタラクション設計にも絡んでくる。

機械学習

Kinect SDKのボーントラッキングに使われているあれ。顔認識や手書き文字認識も機械学習で実装されます。
OpenCVだと学習データ作って何個かコマンドを打てば検出器ができてしまうのですが、それがどの様に実現されているのか知りたくもなります。

本は読んでいないのですが、スタンフォード大学のオンライン講義に機械学習のクラスがあったので受けています。3週目に手書き文字認識の実装という課題が出ました。来季も機械学習のコースはあります。

とにかく数式が出てくるので、数式アレルギーの荒治療としても効果的。

まとめ

これだけの分野を全て習得するのは難しいでしょうが、一つでも深くやりこめば相当面白い物が作れると思います。OpenNIの使い方を覚えたら、次は上のどれかの分野に足を突っ込んでみてはいかがでしょうか。

*1:今でも後悔している

舞台演出にOpenNIとXtion Proを利用した「増殖島のスキャンダル」

映像演出担当の奥村周也氏に招待していただき、拝観してきました。

私は開演前から中空に浮かぶXtion Proに目が釘付けでしたね。今回は実験公演との事で、いろいろと新しい試みを取り入れたそうです。その一つがKinectハック的な仕掛けを利用した演出でした。

終演後はいろいろとお話を聞かせてもらえました。最初はKinectを使う予定だったのだが、営利目的に使えないためXtion Proに切り替えたとか。6メートルを越えたあたりで急に精度が悪くなるとか。実際の会場でのセッティングには苦労されたとか。

役者さんにセンサーの位置だけを気にして演技してもらう訳にもいかないでしょうし、直前の調節は大変だったろうなと。まだ平日のチケットは完売していないそうなので、気になる方は上のリンクからどうぞ。

こういったセンサーを演出に取り入れた舞台劇が増えるといいなあ。面白い。

第3回Kinect(など)ハッカソンやります

ブログに書くの忘れてました。来週の日曜日です。渋谷でいつものハッカソンをやります。
私はKinectというかXtion Pro live + OpenNI + OpenCV + 機械学習であれこれする予定です。