これであなたもダンスグループの一員!?Kinectで自分を分身させるプログラムを作る
前ページからの続きです。
Kinectの画像をビットマップデータに書き出す処理
Byte型の配列変数bytePlayerをInt32Rect構造体の高さにscreenImageStrideで乗算した値で初期化します。640*1280=819200-1の値で初期化するのと同じです。
各分身は、バッファに保存してある0.5秒前、1秒前のデータをそれぞれが参照することで、時差表示を可能にしています。1秒で30フレームなので、0.5秒の場合はその半分の15フレームとなり、変数frameを15で初期化しておきます。
繰り返し変数iで0からメンバ定数変数myPlayer(7)-1分、反復処理を行います。
整数型変数iframeを宣言し、反復変数iが0の場合は、iframe変数にRingBuffer構造体のbuffer_indexプロパティの値(リングバッファ内のインデックス値)を指定します。このbuffer_indexは次のフレームに移動するたびに加算される値で、リングバッファ内のインデックス値になります。
iが0以外の場合は、RingBuffer構造体のbuffer_indexプロパティに、15フレームにi-1の値を乗算した値が加算され格納されます。i-1した値を乗算しないと、背景が白で切り抜かれたプレイヤーが1人分余分に表示されますので注意してください。
Byte型のcolorPixelData配列変数に、RingBuffer構造体のget_rgb_frame関数を使って、iframeに該当する、リングバッファ内のRGBカメラのデータ値を取得します。整数型の配列変数PlayerInexに、RingBuffer構造体のget_PlayerIndexData関数を使って、iframeに該当するリングバッファ内のプレイヤーインデックス値を取得します。
変数indexの値が、colorPixelData変数の値の長さより小さい場合は以下の処理を繰り返します。
4バイトずつ加算される変数indexに該当するPlayerIndexの値が0より大きい場合、つまりプレイヤーが存在する場合は、プレイヤーを描画します。indexに対応する、Byte型の配列変数である距離データを画像化していきます。
Kinectの画像をビットマップデータに書き出します。WriteableBitmap型の変数overrayBitmapにWritePixelsメソッドで、byteからビットマップへ書き出します。ビットマップの指定した領域内に更新したデータを格納します。書式は下記の通りです。このoverrayBitmapプロパティの値を、Nameがhuman_image1というImageコントロールのSourceプロパティに指定します。
WritePixels(更新するWriteableBitmapの四角形,ビットマップの更新に使用するピクセル配列,pixel内の更新領域のストライド,入力バッファのオフセット)
Private Sub RenderScreen2() If screenImageStride = 0 Then Return End If Dim bytePlayer As Byte() = New Byte(CInt(myImageSize.Height) * screenImageStride - 1) {} Dim frame As Integer = 15 For i As Integer = 0 To myPlayer - 1 Dim iframe As Integer If i = 0 Then iframe = myRingBuffer.buffer_index Else iframe = myRingBuffer.buffer_index + (frame * i - 1) End If Dim colorPixelData As Byte() = myRingBuffer.get_rgb_frame(iframe) Dim PlayerIndex As Integer() = myRingBuffer.get_PlayerIndexData(iframe) If colorPixelData Is Nothing Then Continue For End If Dim index As Integer = 0 While index < colorPixelData.Length If PlayerIndex(index) > 0 Then bytePlayer(index) = colorPixelData(index) bytePlayer(index + 1) = colorPixelData(index + 1) bytePlayer(index + 2) = colorPixelData(index + 2) bytePlayer(index + 3) = colorPixelData(index + 3) End If index = index + BytesPerPixel End While Next overrayBitmap.WritePixels(myScreenImageRect, bytePlayer, screenImageStride, 0) human_image1.Source = overrayBitmap End Sub
ウィンドウが閉じられる時の処理
Kinectセンサーの動作を停止してリソースを解放する、StopKinectプロシージャを実行します。
Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing StopKinect() End Sub End Class
RingBufferLib.dllのソースコード(Class1.vb)
リングバッファ内にRGB配列のコピー、Depth配列のコピー、PlayerIndex配列のコピー等を行っています。
Option Strict On Public Class Kinect_RingBuffer Public Structure RingBufferData Public Property ColorPixelData() As Byte() Public Property DepthPixelData() As Short() Public Property PlayerIndexData() As Integer() Public Sub InitArray(ColorStream_FramePixelDataLength As Integer, DepthStream_FramePixelDataLength As Integer) ColorPixelData = New Byte(ColorStream_FramePixelDataLength - 1) {} DepthPixelData = New Short(DepthStream_FramePixelDataLength - 1) {} PlayerIndexData = New Integer(ColorStream_FramePixelDataLength - 1) {} End Sub Public Sub copy_framedata(ByRef value As Byte()) System.Array.Copy(value, ColorPixelData, value.Length) End Sub Public Sub copymyDepthPixelData(value As Short()) System.Array.Copy(value, DepthPixelData, value.Length) End Sub Public Sub copy_PlayerIndexData(value As Integer()) System.Array.Copy(value, PlayerIndexData, value.Length) End Sub End Structure Public Structure RingBuffer Dim myRingBufferData As RingBufferData() Property max_buffer_frame() As Integer Property buffer_index() As Integer Private Function get_index(frameNo As Integer) As Integer Dim no As Integer If frameNo < max_buffer_frame Then no = frameNo Else no = frameNo - max_buffer_frame End If If frameNo < 0 Then no = max_buffer_frame + frameNo End If Return no End Function Public Function get_rgb_frame(frameNo As Integer) As Byte() If myRingBufferData Is Nothing Then Return Nothing End If Return myRingBufferData(get_index(frameNo)).ColorPixelData End Function Public Function get_depth_frame(frameNo As Integer) As Short() If myRingBufferData Is Nothing Then Return Nothing End If Return myRingBufferData(get_index(frameNo)).DepthPixelData End Function Public Function get_PlayerIndexData(frameNo As Integer) As Integer() If myRingBufferData Is Nothing Then Return Nothing End If Return myRingBufferData(get_index(frameNo)).PlayerIndexData End Function Public Function init_ringbuffer(buffer_sec As Integer, ColorStream_FramePixelDataLength As Integer, DepthStream_FramePixelDataLength As Integer) As Boolean Try buffer_index = 0 max_buffer_frame = 30 * buffer_sec myRingBufferData = New RingBufferData(max_buffer_frame - 1) {} For i As Integer = 0 To max_buffer_frame - 1 myRingBufferData(i) = New RingBufferData() myRingBufferData(i).InitArray(ColorStream_FramePixelDataLength, DepthStream_FramePixelDataLength) Next Return True Catch ex As Exception Return False End Try End Function Public Sub save_framedata(value As Byte()) myRingBufferData(buffer_index).copy_framedata(value) End Sub Public Sub save_depthdata(value As Short()) myRingBufferData(buffer_index).copymyDepthPixelData(value) End Sub Public Sub save_playerIndexdata(value As Integer()) myRingBufferData(buffer_index).copy_PlayerIndexData(value) End Sub Public Sub set_nextframe() If buffer_index >= max_buffer_frame - 1 Then buffer_index = 0 Else buffer_index = buffer_index + 1 End If End Sub End Structure End Class
以上で今回のサンプルは終了です。
ダンスグループの一員になれるKinectサンプル
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Kinectで結成したマイ・ダンスチームを、サンプルを見ながら実際の背景に合成してみよう
- Kinectの音声認識を使って、プレイヤーを分離、結合させるデモを試してみる
- Kinectを使って、画面上の赤い輪をくぐるサンプル
- Kinectを使って、自分の手のひらに小さな分身を出現させてみる
- 人体の連続した動作を音声でキャプチャするKinectのサンプルプログラム
- プレイヤーの身体パーツを判別するKinectサンプル
- Kinectで距離カメラの値を取得して、指定した距離で人物が背景に溶け込むサンプル
- 人物を切り抜いて画面に表示するKinectサンプル
- Kinectを使って、顔の動きを認識して画面に表示する
- Kinectによる深度データの取得・表示と、モーターを動かすサンプル