KinectでMangoにPush
8/27のTech Party 2011 広島で紹介したKinectとWindows Phone 7を組合せたPush Notification活用事例です。
Windows Phone 7ではPush Notificationという機能があることはご存知ですね。
Kinect for Windows SDKでは人間7人までのインデックスつき深度情報を取得できるので、Kinectセンサーの前を人が通ったら、それをPush NotificationでWindows Phoneデバイスに通知してやろうってーいう寸法です。
まぁイメージとしては、出入り口(部屋でもよし)にKinectが設置してあって、その前を誰かが通過したら、通過したよと、離れた場所にいる誰かに通知が行くわけですね。
Windows PhoneのPush Notificationの詳細はサンプルなどと共に
http://msdn.microsoft.com/en-us/library/ff402537(v=VS.92).aspx
で紹介されています。Windows Phone側のサンプル Toast Notification Clientはそのまま使えます。
そしてKinect for Windows SDKをインストールしたWindows 7 PCとKinectセンサーを用意します。Windowsアプリケーションを一つ作成して、Microsoft.Research.Kinectアセンブリを参照設定に追加します。
そして、クラスに KinectのRuntime型のメンバーを
private Runtime kinectRuntime;
で定義して、
kinectRuntime = new Runtime(); kinectRuntime.Initialize(RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking); kinectRuntime.DepthStream.Open( ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex); kinectRuntime.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(kinectRuntime_DepthFrameReady);
と初期化処理を書けば、kinectRuntime_DepthFrameReadyメソッドがDepthFrameのデータが更新されるたびに呼ばれます。そしてこのメソッドの中で、
void kinectRuntime_DepthFrameReady(object sender, ImageFrameReadyEventArgs e) { byte[] depthImageBytes = e.ImageFrame.Image.Bytes;
で、1ピクセルあたり2バイトで、320ピクセル(=1ライン)×240ラインの深度情報が取得できます。depthImageBytesは各奇数バイトの下位3ビットが、人の識別情報なので、0x3で&をとって、1、2,3,4,5,6,7の値になっているピクセル数をカウントアップします。ノイズもあるので、ある一定のピクセル数を超えたら、それぞれの識別インデックスに割り振られた人が今Kinectセンサーの前にいると判断できます。
そして、このメソッドが1つ前にコールされた状態を保持しておいて比較します。前回いなくて今回居たら通過を始めて、逆に前回いたけど今回いないなら通過終了と判断できるわけです。コードにすると、以下の様になります。
int[] currentPlayers = { 0, 0, 0, 0, 0, 0, 0 }; foreach (byte depthRaw in depth16) { int playerIndex = depthRaw & 0x7; if (playerIndex > 0) { currentPlayers[playerIndex + 1]++; } } bool[] currentPlayerStates = { false, false, false, false, false, false, false }; for (int i = 0; i < currentPlayers.Length; i++) { if (currentPlayers[i] > depthLimit) { currentPlayerStates[i] = true; } }
状態が変化したインデックスがあれば、Push NotificationにパラメータつきでPush Notification Serviceに通知を送ればよろしい。これはWindows PhoneのPush Notificationのサンプルで提供されているクラウド側のコードを参考にして、
HttpWebRequest request = HttpWebRequest.Create(PushURL) as HttpWebRequest; if (!String.IsNullOrWhiteSpace(ProxyURL)) { request.Proxy = new WebProxy(ProxyURL); } request.Method = "POST"; string toastMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<wp:Notification xmlns:wp=\"WPNotification\">" + "<wp:Toast>" + "<wp:Text1>" + "Kinect" + "</wp:Text1>" + "<wp:Text2>" + Status + "</wp:Text2>" + "<wp:Param>/Page2.xaml?NavigatedFrom=Toast Notification</wp:Param>" + "</wp:Toast> " + "</wp:Notification>"; byte[] notifyMessage = Encoding.Default.GetBytes(toastMessage); request.ContentLength = notifyMessage.Length; request.ContentType = "text/xml"; request.Headers.Add("X-WindowsPhone-Target", "toast"); request.Headers.Add("X-NotificationClass", "2"); try { using (var stream = request.GetRequestStream()) { stream.Write(notifyMessage, 0, notifyMessage.Length); stream.Close(); } HttpWebResponse response = request.GetResponse() as HttpWebResponse; if (response.StatusCode != HttpStatusCode.OK) {
StatusはPlayer Indexが現れた、消えたというメッセージにして、Windows Phone側でPush Notificationチャネルを開いた時に取得したURLをPushURLにセットしてあげれば 、MPNSから、Windows Phoneデバイスに通知がいきます。
Kinectをつないでアプリを動かしているのと同じPC上で、Windows PhoneのEmulator上でToast Notification Clientを動かしてみると良いでしょう。
実用で使う場合、PhoneとWinPCでPushのURLを交換する方法が必要になりますが、クラウドサービスを介する方法や、ローカルネット内でのUDPマルチキャストによる交換などいろいろな方法が考えられます。こちらはまた別のお話という事で。
以上、KinectとPhoneの簡単なコラボレーションを紹介しました。センサーは所詮データを取り出すだけのものなので、こんな感じで他のサービスやデバイスと組合わせてシナリオを考えると、結構おもしろいものアイデアが浮かんでくると思うので、皆さんも是非、色々と考えてみてください。
浙公网安备 33010602011771号