少し乗り遅れ気味ですが、Kinectネタを。
OpenNIの登場でKinectのユーザーのスケルトン情報が一通り取れるようになったので、
それをFlashへの橋渡しをして、マルチユーザー・マルチタッチな環境を作りました。 
これでFlashでもNaturalInterfaceコンテンツを作れるんダゼ!
今回は「OpenNI解析編」ということで、
Kinectを購入してから、OpenNIを解析、Flashへ信号を投げるまでの解説です。
■開発環境
kinect制御端末 :  WinXP VisualC++ Express2010
コンテンツ端末:MacOSX FlashCS4
ソケット通信で Win→Macへユーザーの手の位置を送ります。 
Kinectハックの手順は先人たちをお手本に。
WindowでKinectを繋ぐまでの手順: 
OpenNI: WindowsでKinectを使う 
OpenNIをビルドするまで の手順 : 
OpenNIをVisual C++ 2010 Expressでビルド&デバックするまでの手順。 
上記サイトを参考にOpenNIを改変できるようにしたら、
OpenNIと一緒にインストールされたサンプルから改変しやすそうなのを探します。
NiUserTracker.exeはスケルトン表示までできているので、
今回はこれにソケット通信を追加しました。
C++は初めてなので、ここから、かなり試行錯誤してます…。
「
【C++】ソケット通信 」を参考にして、SocketServerクラスを作りました。
クラスファイル間のアクセス方法がわからなかったんですが、
ハッシュファイルというのを作るんですね。ちょっと面倒です…。
SocketServerクラスにconnectとsend関数を作り、
send関数に送りたい信号を投げるとソケットで通信するようになりました。  
#include 
#include 
SOCKET s, s1;         //ソケット
//
//connect
int connect(){
  int result;          //戻り値
  //接続を許可するクライアント端末の情報
  struct sockaddr_in source;
  char buffer[1024];  //受信データのバッファ領域
  char ans[] = "送信成功";
  memset(&buffer, '\0', sizeof(buffer));
  //送信元の端末情報を登録する
  memset(&source, 0, sizeof(source));
  source.sin_family = AF_INET;
  //ポート番号はクライアントプログラムと共通
  source.sin_port = htons(3000);
  source.sin_addr.s_addr = htonl(INADDR_ANY);
  //ソケット通信の開始準備
  WSADATA data;
  result = WSAStartup(MAKEWORD(2, 0), &data);
  if (result < 0){
    printf("%d\n", GetLastError());
    printf("ソケット通信準備エラー\n");
  }
  //ソケットの生成
  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (s < 0){
    printf("%d\n", GetLastError());
    printf("ソケット生成エラー\n");
  }
  //ソケットのバインド
  result = bind(s, (struct sockaddr *)&source, sizeof(source));
  if (result < 0){
    printf("%d\n", GetLastError());
    printf("バインドエラー\n");
  }
  //接続の許可
  result = listen(s, 1);
  if (result < 0){
    printf("接続許可エラー\n");
  }
  printf("接続開始\n");
  s1 = s;
  //クライアントから通信があるまで待機
 s1 = accept(s, NULL, NULL);
  if (s1 < 0){
    printf("待機エラー\n");
  }
  //クライアントから送信されたデータの受信
  result = recv(s1, buffer, 10, 0);
  if (result < 0){
    printf("受信エラー\n");
  }
  printf("%sを受信しました\n", buffer);
  return 0;
}
//
//send
int send(char id[],char part[] ,char px[],char py[],char pz[]){
 int result;          //戻り値
 char str[50]= "";
 //
 sprintf_s(str,"%s,%s,%s,%s,%s",id,part,px,py,pz);
 //
 result = send(s1, str, strlen(str)+1, 0);
 return result;
}
   
Flashには、ユーザーの手の情報を送りたいので、 スケルトンを描画しているクラスを解析します。 
SceneDrawer.cppの中のDrawLimb() がそれです。
void DrawLimb(XnUserID player, XnSkeletonJoint eJoint1, XnSkeletonJoint eJoint2)
{
 if (!g_UserGenerator.GetSkeletonCap().IsTracking(player))
 {
  printf("not tracked!\n");
  return;
 }
 XnSkeletonJointPosition joint1, joint2;
 g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(player, eJoint1, joint1);
 g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(player, eJoint2, joint2);
 if (joint1.fConfidence < 0.5 || joint2.fConfidence < 0.5)
 {
  return;
 }
 XnPoint3D pt[2];
 pt[0] = joint1.position;
 pt[1] = joint2.position;
 g_DepthGenerator.ConvertRealWorldToProjective(2, pt, pt);
 glVertex3i(pt[0].X, pt[0].Y, 0);
 glVertex3i(pt[1].X, pt[1].Y, 0);
}
 
このコードから
GetSkeletonJointPosition() がユーザーの部位の位置を返す関数だとわかります。
ユーザーIDと体の部位を指定するとx,y,z座標を返してくれます。  
DrawLimb()を改変した関数SendPosition()を作り、SocketServerのsendに送ります。
void SendPosition(XnUserID player,int id, XnSkeletonJoint part,char _part[2])
{
 if (!g_UserGenerator.GetSkeletonCap().IsTracking(player))
 {
  printf("not tracked!\n");
  return;
 }
 XnSkeletonJointPosition joint1;
 g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(player, part, joint1);
 XnPoint3D pt[1];
 pt[0] = joint1.position;
 g_DepthGenerator.ConvertRealWorldToProjective(1, pt, pt);
 //
 char _id[2] = "";
 sprintf( _id, "%d", id);
 //
 char _px[10] = "";
 sprintf( _px, "%.3f", pt[0].X);
 //
 char _py[10] = "";
 sprintf( _py, "%.3f", pt[0].Y);
 //
 char _pz[10] = "";
 sprintf( _pz, "%.3f", pt[0].Z);
 //
 send(_id,_part,_px,_py,_pz);
}
 
以上で、OpenNIにソケット通信を追加できました。   
今回は手の位置だけですが、顔や胴、足の位置も同じ仕組みで取得できます。
※VS上のデバックビルドでは動きますが、exeだとソケット通信開始時に落ちてしまいます。 
いいところまで出来ているのに、なぜ…。  
[追記 2010.12.22] 
exeでも動くようになりました。 
OpenNI/Data内の「SamplesConfig.xml」 を読み込んでいたのですが、 
開発環境とexeではパスが変わってしまうので、読めなくなっていたようです。 
 
 
main.cppの 
#define SAMPLE_XML_PATH "../../Data/SamplesConfig.xml" を 
 
#define SAMPLE_XML_PATH "SamplesConfig.xml" として、 
exeと同じディレクトリにSamplesConfig.xml をコピーすれば、 
落ちなくになります。 
 続きは
Flash編 へ。
定価:¥ 14,800
新品最安価格:¥ 17,300  (2店出品)
売上ランク:62位
レビュー平均:
4.5点 (127人がレビュー投稿)