OpenKinect(Processing 版)と Flash でソケット通信


OpenKinect の Processing 版であるこれを試してみました。
しかしただ試すだけでは面白くもなんともないので、Processing でソケットサーバを作って Flash と通信させて何かやってみることにして…

なんとなく出来たのが、これです。

で、上のヤツをちょっとだけ発展させてみたのがこれです。

使っているのは深度情報を利用したハンドトラッキングだけなので、Processing 側も Flash 側も 60fps でやってみたところそれなりの速度で動いているようです。
但しこのライブラリでは OpenNI などを使う場合と違って、仕組み上スケルトンは利用できないので、スケルトントラッキングは必要とせずなんとなく手の座標だけが取れればいいとか、被写体との深度情報だけが取れればいいというような場合は、こっちの方が高速で使いやすいのではないかと思いました。

参考のため、今回使用したコードです。
※ ソース一式はこちら

Processing 側(OpenKinect & ソケットサーバ)

import org.openkinect.*;
import org.openkinect.processing.*;
import processing.net.*;


// Showing how we can farm all the kinect stuff out to a separate class
KinectTracker tracker;
// Kinect Library object
Kinect kinect;

//
Server server ;
Client client ;

boolean connected ;

String rcvString;


void setup() 
{
  size(640,520);
  frameRate(60);
  kinect = new Kinect(this);
  tracker = new KinectTracker();
  //
  server = new Server(this, 5204) ;
}


void draw() 
{
  background(255);

  // Run the tracking analysis
  tracker.track();
  // Show the image
  tracker.display();

  // Let's draw the raw location
  PVector v1 = tracker.getPos();
  fill(50,100,250,200);
  noStroke();
  ellipse(v1.x,v1.y,20,20);

  // Let's draw the "lerped" location
  PVector v2 = tracker.getLerpedPos();
  fill(100,250,50,200);
  noStroke();
  ellipse(v2.x,v2.y,20,20);

  // Display some info
  int t = tracker.getThreshold();
  fill(0);
  text("threshold: " + t + "    " +  "framerate: " + (int)frameRate + "    " + "UP increase threshold, DOWN decrease threshold" + "\nReceiveString: " + rcvString, 8, 500);

  //
  updateSocket(v1.x, v1.y);
  //updateSocket(v1.x, v1.y, tracker.display);
  
  receivedSocket();
}


void keyPressed() 
{
  int t = tracker.getThreshold();
  if (key == CODED) 
  {
    if (keyCode == UP) 
    {
      t+=5;
      tracker.setThreshold(t);
    } 
    else if (keyCode == DOWN)
    {
      t-=5;
      tracker.setThreshold(t);
    }
  }
}


void stop() 
{
  tracker.quit();
  super.stop();
}



// ----- Socket Sender ------ 
void updateSocket(float px, float py) 
{
  String str = px + "," + py;
  server.write(str) ;
}


// ----- Socket Receiver ------
void receivedSocket()
{
  if (client != null) 
  {
    String data = client.readString();
    
    if (data != null) 
    {
      rcvString = data;
    }
  }
}

void serverEvent(Server srv, Client clt) 
{
  println("connected") ;
  if (client != null) server.disconnect(client) ;
  client = clt ;
}


と、まぁこんな感じで Kinect から取得した X, Y 座標をソケットで送信(関数 updateSocket )しています。
また、今回の場合は別に必要はないのですが、ソケットの受信(関数 receivedSocket )も実装して Flash 側で受け取った値を加工したデータを取得するようにしています。

で、次に Flash 側のソースです。

package
{
	import com.bit101.components.*;
	
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.events.ProgressEvent;
	import flash.net.Socket;
	import flash.text.TextField;
	
	[SWF(width = "640", height = "520", backgroundColor = "0", frameRate = "60")]
	
	public class Main extends Sprite
	{
		
		private var _sock:Socket;
		private var _tx:TextArea = new TextArea();
		
		public var sp:Sprite = new Sprite();
		
		public function Main()
		{
			_tx.x = 30;
			_tx.width = stage.stageWidth * .25;
			_tx.height = stage.stageHeight;
			addChild(_tx);
			
			sp.graphics.beginFill( 0xFF0000 );
			sp.graphics.drawCircle( 0, 0, 15);
			addChild( sp );
			
			setup();
		}
		
		private function setup():void
		{
			_sock = new Socket();
			_sock.addEventListener(ProgressEvent.SOCKET_DATA, receive_data);
			_sock.connect("localhost", 5204);	
		}
		
		
		// ------------- Socket Receiver ---------------------------------------------------- /
		private function receive_data(e:ProgressEvent):void
		{
			var str:String = _sock.readMultiByte(_sock.bytesAvailable,"utf-8");
			var list:Array = str.split(",");
			
			if(list[0] >= 0 && list[1] >= 0) 
			{
				sp.x = list[0] | 0;
				sp.y = list[1] | 0;
				//
				_tx.text = "X: " + (list[0] | 0) + "          Y: " + (list[1] | 0) + "\n" + _tx.text;
				
				//
				sendData( "X: " + (list[0] | 0) + "  Y: " + (list[1] | 0) );
			}
		}
		
		// ------------- Socket Sender ---------------------------------------------------- /
		private function sendData(data:String):void
		{
			// Wrighte
			_sock.writeUTFBytes( data );
			// Send
			_sock.flush();
		}
	}
	
}

こちらは、ソケットで受信(関数 receive_data )した文字列をパースして X, Y 座標を取り出し、その座標に Sprite を移動させるだけの単純なサンプルです。
ソケットでの送信は関数 sendData で実装しています。

また、今回は簡易的なテストということで Processing 側も Flash 側もエラー処理などは実装していませんので、実際に使用する場合はその部分の実装が必要となるかと思います。

今回は Flash と Processing をソケットで接続して動かすことができたので、次は Processing 製の AR.Drone コントローラを Flash と結合させて、Flash から AR.Drone を操作できるようにしてみたいと思っています。