Xtion と Flash をくっつけてちょっとだけ遊んでみた
仕事がアレで全然触れてなかった Xtion(例のKinectのちっこいヤツね)を、OpenNI(NiHandTracker)と Flash(AIR 2.0 NativeProcess))で結合させて、以前 Wonderfl にポストしていた WebCmera を使ったモーショントラックで遊ぶヌンチャクごっこを、精度が高い Xtion版として作り直してみました。
動作のデモ映像はこちら。
(ヌンチャクの綴りが間違っているようですが気にしない気にしないw)
で、Flash と Xtion をどうやって結合したかといえば…
AIR 3.0 の ANE(ネイティブ拡張)を使用してくっつけようかとも思ったのですが、今日一日しか触れる時間が取れそうになかったので、安全策(?)をとって、AIR 2.0 の NativeProcess API を使用して C++(OpenNI)のコンソールアプリケーションと Flash を結合してみました。
というわけで、NativeProcess で Xtion から値を取得するために書いた AS のコードはこちらです。
package { import flash.desktop.*; import flash.filesystem.*; import flash.events.*; import flash.geom.Point; public class GetXtion2DPoint { private var _process:NativeProcess; public var xtionPoint:Point = new Point(); public var msg:String = ""; public function GetXtion2DPoint() { try { init(); } catch (e:Error) { trace(e); } trace(NativeProcess.isSupported); } private function init():void { var info:NativeProcessStartupInfo = new NativeProcessStartupInfo(); var file:File = File.applicationDirectory.resolvePath("bin/start.sh"); info.executable = file; var args:Vector.<String> = new Vector.<String>(); info.arguments = args; _process = new NativeProcess(); _process.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, outputHandler); _process.addEventListener(ProgressEvent.STANDARD_INPUT_PROGRESS, progressHandler); _process.start(info); } private function outputHandler(e:ProgressEvent):void { var data:String = e.target.standardOutput.readUTFBytes(_process.standardOutput.bytesAvailable); dataToPoint(data); } private function progressHandler(e:ProgressEvent):void { trace(e); } private function dataToPoint(data:String):void { var list:Array = data.split(" "); var p:Point = new Point(0,0); if (list.length > 1) { p.x = int(list[0]); p.y = int(list[1]); } msg = p.toString(); xtionPoint = p; } } }
Xtion(OpenNI)側のコードは、OpenIN のサンプルにある「NiHandTracker(NiHandTracker.cpp の DisplayPostDraw 関数)」を一部書き直して使用しました。
書き直した部分はこちら
void HandViewer::DisplayPostDraw() { typedef TrailHistory History; typedef History::ConstIterator HistoryIterator; typedef History::Trail Trail; typedef Trail::ConstIterator TrailIterator; static const float colours[][3] = { { 0.5f, 0.5f, 0.5f}, { 0.0f, 1.0f, 0.0f}, { 0.0f, 0.5f, 1.0f}, { 1.0f, 1.0f, 0.0f}, { 1.0f, 0.5f, 0.0f}, { 1.0f, 0.0f, 1.0f} }; const TrailHistory& history = m_HandTracker.GetHistory(); // History points coordinates buffer XnFloat coordinates[3 * MAX_HAND_TRAIL_LENGTH]; const HistoryIterator hend = history.end(); for(HistoryIterator hit = history.begin(); hit != hend; ++hit) { // Dump the history to local buffer int numpoints = 0; const Trail& trail = hit.GetTrail(); const TrailIterator tend = trail.end(); for(TrailIterator tit = trail.begin(); tit != tend; ++tit) { XnPoint3D point = *tit; m_depth.ConvertRealWorldToProjective(1, &point, &point); ScalePoint(point); coordinates[numpoints * 3] = point.X; coordinates[numpoints * 3 + 1] = point.Y; coordinates[numpoints * 3 + 2] = 0; ++numpoints; } assert(numpoints <= MAX_HAND_TRAIL_LENGTH); // Draw the hand trail history XnUInt32 nColor = hit.GetKey() % LENGTHOF(colours); glColor4f(colours[nColor][0], colours[nColor][1], colours[nColor][2], 1.0f); glPointSize(2); glVertexPointer(3, GL_FLOAT, 0, coordinates); glDrawArrays(GL_LINE_STRIP, 0, numpoints); // Current point as a larger dot glPointSize(8); glDrawArrays(GL_POINTS, 0, 1); glFlush(); } printf("%f %f\n",coordinates[3], coordinates[4]); // 座標を出力 fflush(stdout); // 出力バッファを削除 }
これで、NiHandTracker から出力される値を Flash 側で取得できるようになりました。
そんなこんなで、こういうモーションキャプチャデバイスで遊ぶのは結構楽しいので、今後もヒマを見つけて Xtion で遊んでみたいと思います。